How to achieve time localization in c++? - c++

I'm using the time_t and ctime header to get the time in my app, and it's all OK. The problem is that, the week days and months are displayed in English and i want them to be displayed in my language (Portuguese). How do I do that?
Here's my code:
time_t tempo = time(NULL);
char *data = ctime(&tempo);
cout << data << endl;
And this is the actual output:
"Fri Aug 21 20:00:55 2015"
I was thinking in something like this:
"20:00:55 Sex 21 Ago 2015"
Where Sex is Fri, and Ago is Aug.
I even used this:
setlocale(LC_ALL,".<code_page>");
My full code is this (It's in Portuguese, so the variables names can be weird):
#include <iostream>
#include <iomanip>
#include <ctime>
#include <string>
#include <fstream>
#include <locale>
#include <stdlib.h>
void titulo();
int numOrdem(int a);
using namespace std;
using namespace boost;//I'm experimenting with this, and not working...
int main()
{
int ordem = 0;
int mesa = 0;
int turno = 0;
int quantidade = 0;
int ordemCheck = 0;
string anterior = " ";
string atual;
titulo();
while(true)
{
setlocale(LC_ALL,"");
time_t tempo = time(NULL);
char *data = ctime(&tempo);
minhaOrdem:
cout << "Insira o número da ordem: ";
cin >> ordem;
ordemCheck = numOrdem(ordem);
if (ordemCheck < 7 || ordemCheck > 7)
{
cout << "Ordem incorreta.\n";
goto minhaOrdem;
}
/*ofstream arquivo;
arquivo.open("ordersOnly.txt", ios::app);
arquivo << ordem << endl;
arquivo.close();
ifstream ler;
ler.open("ordersOnly.txt");
if(ler)
{
while(ler >> atual)
{
if(atual == anterior)
{
cout << "Ordem " << atual << " já requisitada!\n";
goto minhaOrdem;
}
anterior = atual;
}
} Here I'm trying to catch an duplicated value...*/
cout << "Insira a quantidade de peças: ";
cin >> quantidade;
minhaMesa:
cout << "Insira o número da mesa: ";
cin >> mesa;
if(mesa < 1 || mesa > 6)
{
cout << "Mesa incorreta.\n";
goto minhaMesa;
}
meuturno:
cout << "Insira seu turno: ";
cin >> turno;
switch (turno)
{
case 100:
break;
case 200:
break;
case 300:
break;
default:{cout << "Turno Incorreto.\n";goto meuturno;}
}
cout << "\n\n";
arquivo.open("ordensDifipro.txt", ios::app);
arquivo << "Ordem: " << ordem << endl;
arquivo << "Quantidade de peças: " << quantidade << endl;
arquivo << "Mesa: RL" << mesa << endl;
arquivo << "Turno: " << turno << endl;
arquivo << "Data: " << data << endl;
arquivo << endl;
arquivo.close();
}//Main while
}// int main
void titulo()
{
cout << setw(62) << "Requisitor de Ordens - Difipro - v 1.1\n\n\n\n\n";
}
int numOrdem(int a)
{
int counter = 0;
while(a > 0)
{
a /= 10;
counter++;
}
return counter;
}
I hope it helps!

Your question is OS specific, I'm focusing on Linux and perhaps other POSIX OSes
You could parse the time string with strptime(3) and convert the time to string with strftime(3), at least if the time fits in a Unix time_t (this would always be the case for time between 1970 i.e. the Unix Epoch and 2038 because of the Y2038 problem) e.g. using mktime(3) & localtime(3). Read locale(7) about some localization & internationalization things. You might need to call setlocale(3) appropriately.
In C++11 use <chrono> (see also this); see this time_point example to start.
Beware that distant times (e.g. early 1900s) can become quite complex, see this
Addenda: if you want your date to be in Portuguese, either set your LANG or LC_ALL environment variable (see environ(7)) to pt_PT.UTF-8 (perhaps by adding export LANG=pt_PT.UTF-8 in your ~/.bashrc file on Linux, if your login shell is bash) or replace the setlocale(LC_ALL,""); with setlocale(LC_ALL,"pt_PT.UTF-8"); in your program.
BTW, Windows has its documentation on setlocale

You should probably have a look at the Boost Locale library.
http://www.boost.org/doc/libs/1_59_0/libs/locale/doc/html/index.html
Especially the part on formatting and parsing of time formatting:
http://www.boost.org/doc/libs/1_59_0/libs/locale/doc/html/formatting_and_parsing.html
It allows you to portably output things like date time values using the locale settings of the system it's being run on. There is an example doing exactly what tou are trying to do in a just two lines of code. It also does so without asking you to write platform dependant code. You may want to look at other parts of Boost Locale too, including message translation to make it truly work cross language.
Try to avoid using low level platform API's or C++14 features (as an alternate answer seems to suggest) unless you are sure your code will never be used on an other platform or in a C++ project not using C++11/C++14. Boost mostly is your best bet at writing stuff like this portably.

Related

CPP Guessing Game not working, its stops after i enter the name

I'm trying to make this kina guess game on C++, I'm a beginner and still learning.
What I'm trying to achieve is a guessing game of two const names, is very simple without errors but it's not working after I enter something. it should report until I find the correct name. Please also I don't want to change the structure of the code, just find why isn't working.
#include <iostream>
#include <string>
using namespace std;
struct Vlerat {
string guess01 = "Resul";
string guess02 = "Rejan";
int numruesi = 0;
};
int main() {
Vlerat funksioni;
string nameGuess;
int nameOkay = 0;
cout << "Gjej njerin prej dy emrava te fshehura." << endl;
cout << "Ndihm: Fillojn me Shkronjen 'R', dhe pas asaj vjen edhe nje shkronj 'e'" << endl;
do {
cout << "Shkruaj Emrin > "; cin >> nameGuess;
if (nameGuess == funksioni.guess01){
cout << "Ju e keni gjetur emrin e njerit nga personat duke provuar gjithesej:";
cout << funksioni.numruesi++ << " here." << endl;
nameOkay++;
}
if (nameGuess == funksioni.guess02) {
cout << "Ju e keni gjetur emrin e njerit nga personat duke provuar gjithesej:";
cout << funksioni.numruesi++ << " here." << endl;
nameOkay++;
}
funksioni.numruesi++;
} while(nameOkay = 0);
}
You should change while(nameOkay = 0); to while(nameOkay == 0);.
Because = is an assignment, but == is operator of comparing (equality)
Read about it here
And here

Simple game database problems

NOTE: I am new to C++ and may do things that are bad practice and if you see that please tell me so I can fix that and please don't be mean. I have only started coding 1-2 months ago. And I am still learning. Please be open to the fact I may not know everything.
This is a console text-based game. It works great! Although, I am creating a feature in it to allow the user to drag and drop any amount of other databases on it to allow database transfers. Although this works fine the problem is that I have a little process it will do to try and make sure none of the info in the databases is the same by placing a number to them,
Example there will be 2 profiles 1 in each file. They are both named main. Then the user drags the second database onto the game and it loads that database into the original one. But now becuase there are 2 SIMILAR profile names it won't be able to differentiate which is which. So then it goes through a little function which scans the database and places a number in front of the copies. Starting at 5 and working its way up. Although this would seem to work and not be that hard to actually do I have hit a problem and I do not know what is wrong. I do know however it is something with how it scans for duplicates. Please help.
I have tried for like a whole day trying different methods or re-writing the code. Google has not revealed a lot to me.
I am using the following libraries in my code. (Some might not be used in the example but tbh I don't remember which is directly used in THIS function).
#include <iostream>
#include <iterator>
#include <cstring>
#include <cmath>
#include <cassert>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <utility>
#include <vector>
#include <array>
#include <functional>
#include <fstream>
Here is the scanning function to make sure there are no duplicate profiles.
Let me explain what happens.
I make a ton of variables which are used in the database. As you can see inside of the database it has a certain order.
Using file stream I access the database. (I have a function which will combine all the databases the user dragged in and the current profiles and data which works just fine).
The pattern in the database looks something like this.
profile_name user_name 100 3 0 0 0 0 knight 1 100 0 0
profile name health etc
If you look at the variables you will see the technical order.
void scanCopy()
{
std::string profile{ "John's_Profile" };
std::string name{ "John_Doe" };
int health{ 0 };
int damage{ 0 };
int gold{ 0 };
int exp{ 0 };
int level{ 0 };
int score{ 0 };
std::string CLASS{ "null" };
int dungeon{ 0 };
int maxHealth{ 0 };
int lives{ 0 };
int kills{ 0 };
std::ifstream in("data/database.txt");
std::vector <std::string> profiles;
int sizeOfVector{ 0 };
while (in >> profile >> name >> health >> damage >> gold >> exp >> level >> score >> CLASS >> dungeon >> maxHealth >> lives >> kills)
{
profiles.resize(sizeOfVector += 1);
profiles.at(sizeOfVector - 1) = { profile };
std::cout << profiles.at(sizeOfVector - 1) << "\n\n";
}
in.close();
for (int loop{ 0 }; loop < sizeOfVector; ++loop)
{
int compare{ loop };
for (int index{ loop }; index < sizeOfVector; ++index)
{
if (compare == index)//meaning they are like at profiles(1)and (1)
continue;
if (profiles.at(compare) == profiles.at(index))
{
std::ofstream out("data/~database.txt", std::ios::app);
in.open("data/database.txt");
int nameIndex{ 5 };
while (in >> profile >> name >> health >> damage >> gold >> exp >> level >> score >> CLASS >> dungeon >> maxHealth >> lives >> kills)
{
if (profile == profiles.at(index))
{
out << profile << nameIndex << " " << name << " " << health << " " << damage << " " << gold << " " << exp << " " << level << " " << score << " " << CLASS << " " << dungeon << " " << maxHealth << " " << lives << " " << kills << " " << std::endl; //Notice at the start profile is put into the database with an extra variable nameIndex to make its name now unique.
++nameIndex;
}
else
{
out << profile << " " << name << " " << health << " " << damage << " " << gold << " " << exp << " " << level << " " << score << " " << CLASS << " " << dungeon << " " << maxHealth << " " << lives << " " << kills << " " << std::endl;
}
}
}
}
}
in.close();
remove("data/database.txt");
in.open("data/~database.txt");
std::ofstream out("data/database.txt", std::ios::app);
//A buffer to copy everything inside a file to a string.
std::string upData((std::istreambuf_iterator<char>(in)),
(std::istreambuf_iterator<char>()));
/////
if (out)
out << upData; //putting everything in the tmp file to the file named database.txt
out.close();
in.close();
remove("data/~database.txt");
in.close();
out.close();
}
The problem is that it does not do its job. It will put numbers by anything. Besides that, it will also seem to overflow or something. What it does is after you already dragged something in, it pretends to work. Then any more input from dragging it does not get scanned. Thing is that everything is copied from the files the user drags from the database to a tmp file. Then the database is deleted and the temp file is renamed to database.txt. The problem is that this whole scan function seems to not be working right and I don't see the problem in it. Does anyone know a good way to do something like this or what the problem is? Thanks!
We really do not need the backstory that this is a game, that users can do XYZ and so on. Please construct a minimal example, as in minimal reproducible example. Often by constructing those, you yourself discover the problem. – Fureeish
Thank you Fureeish. I have found the problem. I was sending the function too many times which wiped the file or it did not scan it all the way. It is hard to explain the real thing I did because it was easy but I can't explain it well.
ALL IN ALL. I examined and found the bug, I was sending it to this function I posted up there too many times. or too little times.

c++ get years between date chosen by user and actual date(counting days,months,years)

i tried doing this:
struct Den_t
{
int day, month, year;
};
int main()
{
struct Den_t* Datum = new struct Den_t;
struct Den_t* Dnes = new struct Den_t;
time_t theTime = time(NULL);
struct tm aTime;
localtime_s(&aTime, &theTime);
Dnes->day = aTime.tm_mday;
Dnes->month = aTime.tm_mon + 1;
Dnes->year = aTime.tm_yday + 1900;
cin >> Datum->day >> Datum->month >> Datum->year;
if (Dnes->year - Datum->year >= 18 )
cout << "full aged " << endl;
else
cout << "not full aged " << endl;
system("PAUSE");
return 0;
}
but i somehow cant understand what should i even compare and decrement,could someone explain me
what else i need to do to tell people's date for example in float by
comparing year,month and day of actual time and date user inputs in
the program?
You have an issue with your code logic here.
For example:
Datum is 31/12/1982
Dnes is 01/01/2000
The year difference is 18 but the age is 17 and 2 days.
Consider using standard library functions instead of reinventing the wheel.
difftime could be useful, for example
This is a very dirty example, but it would do the work:
time_t dnes;
time(&dnes);
// Set datum here ...
cin >> Datum->day >> Datum->month >> Datum->year;
datum.tm_mday = Datum->day;
datum.tm_mon = Datum->month - 1;
datum.tm_yday = Datum->year - 1900;
datum->tm_yday+=18;
if (difftime(dnes, mktime(&datum)) <0 )
cout << "not full aged " << endl;
else
cout << "full aged " << endl;
Using these libraries:
http://howardhinnant.github.io/date/date.html
http://howardhinnant.github.io/date/tz.html
This is how I would tackle the problem. First the code, then the explanation:
#include "tz.h"
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << "Enter birthday [day month year]:";
int di, mi, yi;
std::cin >> di >> mi >> yi;
if (std::cin.fail())
{
std::cout << "Invalid date\n";
return 1;
}
auto y = year{yi};
if (!y.ok())
{
std::cout << "Invalid year\n";
return 1;
}
auto m = month(mi);
if (!m.ok())
{
std::cout << "Invalid month\n";
return 1;
}
auto d = day(di);
if (!d.ok())
{
std::cout << "Invalid day\n";
return 1;
}
auto birthday = y/m/d;
if (!birthday.ok())
{
std::cout << "Invalid birthday\n";
return 1;
}
auto local_time = current_zone()->to_local(system_clock::now());
auto today = year_month_day{floor<days>(local_time)};
auto age = today.year() - birthday.year();
if (birthday + age > today)
--age;
if (age >= years{18})
std::cout << "full aged at " << age.count() << "\n";
else
std::cout << "not full aged at " << age.count() << "\n";
}
I would first go to some trouble to check the validity of the user input. What I have below seems like a minimum:
It must be integral input.
Each integral input must have a reasonable value (e.g. month must be in the range [1, 12].
The combination y/m/d must be a valid date.
A more robust program might give the user some feedback on what he input, and give him another chance to correct his mistake.
Once assured we have a valid birthday, we need to get the current date in the local timezone. This:
auto local_time = current_zone()->to_local(system_clock::now());
gets the local time.
This local time can be converted to a local year, month and day with:
auto today = year_month_day{floor<days>(local_time)};
This computation follows the custom that your birthday begins at the local midnight, regardless of what time of day (and where on the planet) you were actually born. In other words, once the local year/month/day is established, this problem is independent of the local time zone, and even the local time of day.
Next, the current age is computed:
auto age = today.year() - birthday.year();
if (birthday + age > today)
--age;
The difference between the years of today and the birthday is a first approximation to the age. This approximation is refined by computing the date on which your birthday falls this year. If this year's birthday is still in the future, then by custom we count that as one year younger. If we were doing something that leaned less towards a legal system, and more towards scientific work, we might well compute in other ways, such as rounding to the nearest year (also easy to do with this library).
If the birthday is on Feb 29, the above code still works: birthday + age will result (75% chance) in an invalid date, e.g.: feb/29/2015. However this invalid date will correctly compare greater than feb/28/2015 and less than mar/1/2015, exactly as we need it to! Invalid dates are your friend, not your enemy -- you just have to know they exist and what to do about them.
Now it is a simple matter to report your findings:
if (age >= years{18})
std::cout << "full aged at " << age.count() << "\n";
else
std::cout << "not full aged at " << age.count() << "\n";

C++ subtract days in string format YYYYMMDD

I'm struggling a little getting some C++ code to cooperate. Is there a straight forward way to subtract two dates that are strings? I'm trying to get the number of days between them. They are strings, YYYYMMDD. Is the Boost library the right direction to go?
Yes, Boost Date_Time can certainly do that even others may suggest "lighter" alternatives.
Here is the example about the days alive which does almost exactly your problem (just add a second date parsing):
/* Short example that calculates the number of days since user was born.
* Demonstrates comparisons of durations, use of the day_clock,
* and parsing a date from a string.
*/
#include "boost/date_time/gregorian/gregorian.hpp"
#include <iostream>
int
main()
{
using namespace boost::gregorian;
std::string s;
std::cout << "Enter birth day YYYY-MM-DD (eg: 2002-02-01): ";
std::cin >> s;
try {
date birthday(from_simple_string(s));
date today = day_clock::local_day();
days days_alive = today - birthday;
days one_day(1);
if (days_alive == one_day) {
std::cout << "Born yesterday, very funny" << std::endl;
}
else if (days_alive < days(0)) {
std::cout << "Not born yet, hmm: " << days_alive.days()
<< " days" <<std::endl;
}
else {
std::cout << "Days alive: " << days_alive.days() << std::endl;
}
}
catch(...) {
std::cout << "Bad date entered: " << s << std::endl;
}
return 0;
}

Array of Struct

I want to just hard code these values into a table. when I try to use 2D arrays, I run into the problem of dealing with characters and integers. When I do a struct I have this so far but it doesn't divide the information up in columns, and I'm not sure how to format it that way. (I only did 3 rows to start off with, if I get them working, the rest will just be the same)
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
typedef struct table
{
std::string game;
int year;
float rating;
int num_voters;
}t;
void processTab(t*);
int main()
{
t tabl[2] = {0,0};
int i;
processTab(tabl);
for(i=0; i<2; i++)
{
std::cout << "Game: " << setw(20) << tabl[i].game;
std::cout << "\tYear: " << setw(4) << tabl[i].year;
std::cout << "\tRating: " << fixed << setprecision(2) << tabl[i].rating;
std::cout << "\tVoters: " << setw(6) << tabl[i].num_voters;
}
system("pause");
return 0;
}
void processTab(t*tab)
{
(tab[0].game, "twilight struggles");
tab[0].year = 2005;
tab[0].rating = 8.226;
tab[0].num_voters = 10690;
(tab[1].game, "Agricloa");
tab[1].year = 2007;
tab[1].rating = 8.17;
tab[1].num_voters = 23738;
(tab[2].game, "Puerto Rico");
tab[2].year = 2002;
tab[2].rating = 8.163;
tab[2].num_voters = 27433;
}
Table Data:
Game (0) Year (1) Rating (2) Num Voters (3)
Twilight Struggle 2005 8.226 10690
Agricola 2007 8.17 23738
Puerto Rico 2002 8.163 27433
Through the Ages 2006 8.153 8137
Power Grid 2004 8.02 21655
Le Havre 2008 7.972 9258
Eclipse 2011 7.968 3194
Brass 2007 7.911 5814
Dominion: Intrigue 2009 7.895 10889
Caylus 2005 7.878 13878
What I think you are looking for is <iomanip>
#include <iomanip>
std::cout << "Game: " << setw(20) << tabl[i].game;
std::cout << "\tYear: " << setw(4) << tabl[i].year;
std::cout << "\tRating: " << fixed << setprecision(3) << tabl[i].rating;
std::cout << "\tVoters: " << setw(6) << tabl[i].num_voters;
std::cout << std::end;
Notes:
setw adds padding when writing out stuff, so it will always be at least a certain width
setprecision specifies how many decimal places to display
fixed makes floating point never use scientific notation
Your game member is a letter, and you're attemptying to assign it a string. Don't use strcpy in C++, use the std::string class instead.
#include <string>
struct table
{
std::string game;
int year;
double rating;
int num_voters;
};
Avoid using namespace std;, when you get to complex code with many namespaces, those few letters are a small price to pay for avoiding confusion.
Avoid endl: it flushes buffers which is slow. If you just want a newline, use '\n'.
Also, you can use the new initialization syntax to initialize your list:
std::vector<table> tbal = {
{"twilight struggles ", 2005, 8.226, 10690},
{"Agricola ", 2007, 8.17 , 23738},
{"Puerto Rico ", 2002, 8.163, 27433}
};
Short answer: use std::vector, not a raw array.
The following is as close to your original code as I could make it, introducing a minimum number of new features for you:
#include <assert.h> // assert
#include <iostream> // std::cout, std::endl
#include <stddef.h> // ptrdiff_t
#include <string> // std::string
#include <utility> // std::begin, std::end
#include <vector> // std::vector
using namespace std;
typedef ptrdiff_t Size;
template< class Container >
Size countOf( Container& c ) { return end( c ) - begin( c ); }
struct Game
{
string game;
int year;
double rating;
int num_voters;
};
void initialize( vector<Game>& games )
{
assert( countOf( games ) == 0 );
games.resize( 3 );
games[0].game = "twilight struggles";
games[0].year = 2005;
games[0].rating = 8.226;
games[0].num_voters = 10690;
games[1].game = "Agricloa";
games[1].year = 2007;
games[1].rating = 8.17;
games[1].num_voters = 23738;
games[2].game = "Puerto Rico";
games[2].year = 2002;
games[2].rating = 8.163;
games[2].num_voters = 27433;
}
int main()
{
vector<Game> games;
initialize( games );
for( int i = 0; i < countOf( games ); ++i )
{
cout << i << endl;
cout <<"\tGame: " << games[i].game << endl;
cout<<"\tYear: " << games[i].year << endl;
cout<<"\trating: " << games[i].rating << endl;
cout<<"\tnum voters: " << games[i].num_voters << endl;
}
}
There are ways to just declare the data more directly, including brace initializers; check out your C++ textbook.
First you need to define your table (bad name for a struct, by the way) correctly. You're trying to use game to store a string, but have defined it as only a single char. You probably want to change that to a std::string instead.
Then you probably want to do your formatting in an operator<< overloaded to take a reference to table as the type. #MooingDuck has already covered the formatting itself quite well, so it's mostly a matter of how you package that:
std::ostream &operator<<(std::ostream &os, table const &t) {
os << "Game: " << setw(20) << t.game;
os << "\tYear: " << setw(4) << t.year;
os << "\tRating: " << fixed << setprecision(2) << t.rating;
return os << "\tVoters: " << setw(6) << t.num_voters;
}
Along with that, you almost certainly want to change tabl from an array to std::vector<table>:
std::vector<tabl> tabl;
Then processing the table becomes:
std::copy(tabl.begin(), tabl.end(), std::ostream_iterator<table>(std::cout, "\n"));
One other minor detail: you seem to have two entirely different/separate functions, both named processTab. You probably want to rename at least one of those. Just glancing at them, I'd probably call one initializeTable or something on that order.