I want to print timestamp using C++ in different locales, I get strange output for fr_FR in one particular host.
Here is the code,
#include <time.h> /* time_t, struct tm, time, localtime, strftime */
#include <stdlib.h>
#include <locale.h>
#include <clocale>
#include <iostream>
using namespace std;
int main()
{
time_t rawtime;
struct tm * timeinfo;
char buffer [32];
setlocale(LC_ALL, "");
cout << "LC_ALL: " << setlocale(LC_ALL, NULL) << endl;
cout << "LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << endl;
time (&rawtime);
timeinfo = localtime (&rawtime);
strftime (buffer,sizeof(buffer),"%a %b %d %H:%M:%S %Y %Z",timeinfo);
puts (buffer);
return 0;
}
Before running the above program I did
export LANG=fr_FR.ISO8859-1
It gives output,
LC_ALL: fr_FR.ISO8859-1
LC_CTYPE: fr_FR.ISO8859-1
ven. avril 12 08:49:55 2013 UTC
It gives same output for both %b and %B, when I checked in another machine, it works as expected. Output,
LC_ALL: fr_FR.ISO8859-1
LC_CTYPE: fr_FR.ISO8859-1
jeu avr 11 23:26:24 2013 PDT
In one machine,
$date +%b
avr
$date +%B
avril
In problamatic machine,
$date +%b
avril
$date +%B
avril
Please help me to solve this issue.
The output appears correct.
"avril" is a legitimate abbreviation for "avril" Reference.
"Avr" is also an abbreviation for "avril". French months "juin" and "juillet", both beginning with the same 3 letters demonstrate that using the first 3 letters won't always work.
C++ does not specify how to abbreviate month names other than the default locale. Thus assuming the abbreviation are short, the same length within a locale or implemented the same in various OS world wide is problematic.
Recommend checking the return value of strftime().
Related
I'd like to create a program that converts the date of a specific human-readable format to epoch.
So far I have the following code the first part of which creates this human-readable format and the second one converts it to epoch.
#include <time.h>
#include <iostream>
#include <ctime>
#include <string>
#include <cstring>
using namespace std;
int main(int argc, char const *argv[])
{
time_t timeNow;
struct tm *ltm = NULL;
time(&timeNow);
ltm = localtime(&timeNow);
char buffer[100];
strftime(buffer, sizeof(buffer), "%c %Z", ltm);
cout << "human readable timestamp is " << buffer << endl;
std::tm tmNow;
memset(&tmNow, 0, sizeof(tmNow));
strptime(buffer, "%c %Z", &tmNow);
cout << "epoch timestamp is " << mktime(&tmNow) << endl;
return 0;
}
So the printouts I get are the following :
human readable timestamp is Thu Sep 16 10:23:06 2021 EEST
epoch timestamp is 1631780586
My time zone is EEST as one can see but the epoch one is wrong because it is one hour ahead. The correct should have been 1631776986. I assume I'm doing wrong something with the local time. I've found third-party libraries examples like boost or poco that do this conversion, but I'd prefer the above conversion to be done by using native C++.
Does anyone see what I'm missing?
The C timing/calendrical API is very difficult to use correctly (which is why C++ is moving away from it).
From the C standard:
The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and negative if the information is not available.
Set tmNow.tm_isdst = -1; prior to the call to mktime.
I have this little example below that is giving me results that I don't understand.
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
int main() {
auto currentTime = std::time(nullptr);
auto currentTime2 = std::time(nullptr);
std::stringstream ss;
std::stringstream ss2;
ss << std::put_time(std::localtime(¤tTime), "%Y-%m-%dT%H:%M:%S %z %Z");
ss2 << std::put_time(std::gmtime(¤tTime2), "%Y-%m-%dT%H:%M:%S %z %Z");
std::cout << " time now local = " << ss.str() << std::endl;
std::cout << " time now gm = " << ss2.str() << std::endl;
}
On Windows (VS2017) this gives me:
time now local = 2019-10-08T16:25:17 +0200 W. Europe Summer Time
time now gm = 2019-10-08T14:25:17 +0100 W. Europe Standard Time
On Mac (XCode 10) this gives me:
time now local = 2019-10-08T16:25:17 +0200 CEST
time now gm = 2019-10-08T14:25:17 +0100 UTC
Could someone explain to me why the %z gives +0100 for the UTC outputs instead of +0000? What part of logic am I missing?
Running this on http://ideone.com/IspjpG for example always gives +0000.
The std::tm class returned by std::gmtime and std::localtime does not contain timezone information, other than whether daylight saving is in effect. For gmtime, it is never in effect and for localtime, it depends on current locale and time.
%Z format specifier of std::put_time uses the current locale for timezone information. The currently active locale is unaffected by the std::tm object given as argument.
So in first case, you print the local time with information about local timezone (with DST enabled). And in second case, you print UTC time with information about local timezone (with DST disabled).
We can conclude that using %z and %Z is incorrect for printing times from other timezones than the current local one. Frankly, I consider it a flaw in std::put_time interface (and the interface of std::strftime, which std::put_time wraps) that one cannot pass timezone information to the function, but can accidentally print a timezone that may be unrelated to the std::tm instance being printed.
For correct output, you should use:
ss2 << std::put_time(std::gmtime(¤tTime2),
"%Y-%m-%dT%H:%M:%S +0000 UTC");
I have been trying to write a C++ program, that requires me to do date arithmetic.
For example today's date (9-30-2014) minus 4 days and have it return 9-26-2014, or today date plus 3 days returning 10-3-2014.
My original thought process is to use
ctime
which will return the date in seconds from jan 1 1970, I could then add or subtract a set number of seconds for the number of days and pass the result into "put_time" a part of
iomanip
to start I am just trying to get this method to print the correct date, but I can not get the compiler to recognize "put_time"
I am using eclipse version (4.4.0)
with "version 4.1.11(2)-release (x86_64-unknown-cygwin)" as a compiler
From research I have found that "put_time" is only included in certain versions of c++ and I tried running this command
`-std=c++0x`
However I am still receiving the same error "'put_time' was not declared in this scope".
this is the code I am running so far:
//============================================================================
// Name : Date.cpp
// Author : me
// Version :
// Copyright : Your copyright notice
// Description : date calculations
//============================================================================
#include <iostream>
#include <iomanip> // std::put_time
#include <ctime> // std::time_t, struct std::tm, std::localtime
#include <chrono> // std::chrono::system_clock
using namespace std;
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
time_t timer;
time(&timer);
cout << timer;
struct tm * ptm = localtime(&timer);
cout << put_time(ptm,"%c");
return 0;
}
Why not use asctime? It's prototype is char* asctime (const struct tm * timeptr); and you should not have any problem printing out he char*. The only issue is that the output format is fixed as Www Mmm dd hh:mm:ss yyyy where Www represents the three-letter abbreviation of the day of the week.
If you want more flexibility in the format of the output string, you can use strftime to get custom formatting. It's prototype is size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr );
Is there a simple way to get time time of day (17:30, 01:20...etc) that would work on iOS, OSX, Linux and Windows?
If not is there a Windows way and a posix way or something?
Thanks
You can retrieve the time with time_t now = time(NULL); or time(&now);
You then usually convert to local time with struct tm *tm_now = localtime(&now);. A struct tm contains fields for the year, month, day, day of week, hour, minute, and second. If you want to produce printable output, strftime supports that directly.
Both of these are in the C and C++ standards, so they are available on most normal platforms.
If you really only care about C++, you can use std::put_time, which is similar to strftime, but a little bit simpler to use for the typical case of writing the output to a stream.
with C++11 you can use
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t t = std::time(nullptr);
std::cout << "UTC: " << std::put_time(std::gmtime(&t), "%c %Z") << '\n'
<< "local: " << std::put_time(std::localtime(&t), "%c %Z") << '\n';
}
which should produce on (any platform)
UTC: Wed Dec 28 11:47:03 2011 GMT
local: Wed Dec 28 06:47:03 2011 EST
though std::put_time() (from iomanip) is not yet implemented in, say, gcc 4.7.0.
I want to convert seconds since 1970 to datetime for a specific time zone.
I have the time in milisecond and the timezone for a server.
I am getting these values by calling an API. I want to know the year,month, day of that time zone.
int milisecond = 12347586484;
zone = "GMT +8.00";
How can I do that?
Thanks,
Syd
Edit: Will I get the right date if I use gmtime()?
timeinmilisecond + 8*360000;
struct tm *jobCreationtm;
time_t t = (time_t)(timeinmilisecond);
jobCreationtm = gmtime(&t);
Note: I dont want to use third party dlls.
You can set the TZ environment variable to the timezone you want (see the manual page for tzset), and then call localtime.
Something like (now tested):
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main()
{
::putenv("TZ=GMT+8");
time_t t = ::time(0);
tm* x = ::localtime(&t);
char buf[1024];
::strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", x);
std::cout << ::getenv("TZ") << std::endl;
std::cout << "[" << buf << "]" << std::endl;
return 0;
}
Output:
GMT+8
[Thu, 17 Feb 2011 02:22:41 -0800]
What format is the timezone from your server? Is it a GMT offset or formatted like "America\Los Angeles". It's tough w/o a 3rd party library because the result is different based time of year (day light savings) and changes with time (certain counties in Midwest for example change from EST to CST every few years).
Consider installing the ICU library. Given time stamps and a locale (or GMT offset) you can get formatted time / date strings very easily using the TimeZone class.