Cross Platform way to get the time of day? - c++

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.

Related

Conversion of date from human-readable format to epoch fails

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.

std::strftime displays timezone UTC as UTC+1 using gmtime in windows

I am trying to understand why in windows (in linux works) std::strftime displays the timezone UTC as UTC+1.
If I run the next code
#include <ctime>
#include <chrono>
#include <string>
#include <iostream>
int main()
{
std::time_t t = std::time(nullptr);
char utc_str[80];
std::strftime(utc_str, 80, "%H:%M:%S %z", std::gmtime(&t));
std::string utcStd = { utc_str };
std::cout << "UTC: " << utcStd << std::endl;
char local_str[80];
std::strftime(local_str, 80, "%H:%M:%S %z", std::localtime(&t));
std::string localStd = { local_str };
std::cout << "Local: " << std::string(localStd) << std::endl;
return 0;
}
I get the next output:
UTC: 07:26:18 +0100
Local: 09:26:18 +0200
Where the UTC and localtime times are correct but the UTC timezone is incorrect.
Any ideas?
Microsoft has been always famous for its implementations of C library functions to work somewhat differently than specified in standards. Other platform vendor doing that is Apple. As it has lasted for decades it must be is deliberate strategy.
There are bugs reported about that time zone in Visual Studio implementation of strftime. Perhaps what you observe is other "bug", other manifestation of same "bug" or new manifestation of some "fix".
Usage of some open source library can be less headache than what these library vendors provide. Typical suggestion is boost but I have observed it to be inefficient and to misbehave. The one by Howard Hinnant is quite decent.

Why does std::put_time(std::gmtime with the %z format give back +0100 for UTC?

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(&currentTime), "%Y-%m-%dT%H:%M:%S %z %Z");
ss2 << std::put_time(std::gmtime(&currentTime2), "%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(&currentTime2),
"%Y-%m-%dT%H:%M:%S +0000 UTC");

C++ strftime %b not working as expected

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().

convert number of seconds since 1970 to DateTime for a specific time zone?

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.