I am trying to save std::time_point into a std::stream and read it back. One problem is that using the standard functions 'loses' an hour somewhere. I.e., the time I read is 1 hour behind the time I write. I suspect that I need to set up daylight saving somewhere. I put together a small program that prints time to a std::stringstream and reads it back.
#include <iomanip>
#include <iostream>
#include <sstream>
#include <chrono>
#include <ctime>
using std::chrono::system_clock;
namespace chrono = std::chrono;
void test();
int main(int argc, char** argv)
{
std::stringstream ss;
auto start = system_clock::now();
std::time_t ts = system_clock::to_time_t(start);
std::tm time_out = *std::localtime(&ts);
ss << std::put_time(&time_out, "%Y-%m-%d %H:%M:%S %Z") << '\n';
std::cout << ss.str() << std::endl;
std::tm time_in;
ss >> std::get_time(&time_in, "%Y-%m-%d %H:%M:%S %Z");
std::cout << "Are time dsts equal? : " <<
(time_out.tm_isdst == time_in.tm_isdst) << '\n';
std::time_t rawTime = std::mktime(&time_in);
auto end = std::chrono::system_clock::from_time_t(rawTime);
std::cout << "Are time points equal? : " << (start == end) << '\n';
// print the trouble makers
std::time_t start_time = system_clock::to_time_t(start);
std::time_t end_time = system_clock::to_time_t(end);
std::cout << "times: \n"
<< '\t' << std::put_time(std::localtime(&start_time), "%c %z") << '\n'
<< '\t' << std::put_time(std::localtime(&end_time), "%c %z") << '\n';
// this is a source of strange behaviour...
// std::cout << "Difference: "
// << chrono::duration_cast<chrono::seconds>(start - end).count()
// << std::endl;
return 0;
}
The strangest thing is that the program prints the following:
Are time dsts equal? : 1
Are time points equal? : 0
times:
Tue Dec 11 19:26:24 2012 +0000
Tue Dec 11 19:26:24 2012 +0000
And when I uncomment the 3 lines at the end of the program (printing the difference between the time points) the result is:
Are time dsts equal? : 0
Are time points equal? : 0
times:
Tue Dec 11 19:29:40 2012 +0000
Tue Dec 11 18:29:40 2012 +0000
Difference: 3600
Notice that dst(daylight saving time) is suddenly not equal and neither are the times.
I am using libc++ on Mac OS X 10.8.2 with XCode46-DP2. The clang++ versions I am using are Apple clang version 4.1 and clang version 3.2 (trunk 167239)
I guess my questions are:
A) As to the 1 hour difference, is this a bug in my library or am I not using the standard functions correctly? (The latter would not surprise me...)
B) What is going on with the code when I uncomment the three lines at the end of my program? This looks like a bug to me. Anyone care to try it on their platform?
I think we're looking at a bug with the %Z specifier, and maybe with the %z specifier as well, not sure yet.
I will look into the cause of these bugs more. However I wanted to go ahead and post to get you a workaround. I believe if you zero-initialize your input tm, and always assume it is with respect to your local timezone, then you will eliminate your errors:
std::tm time_in{0};
Related
How do I get a uint unix timestamp in C++? I've googled a bit and it seems that most methods are looking for more convoluted ways to represent time. Can't I just get it as a uint?
C++20 introduced a guarantee that time_since_epoch is relative to the UNIX epoch, and cppreference.com gives an example that I've distilled to the relevant code, and changed to units of seconds rather than hours:
#include <iostream>
#include <chrono>
int main()
{
const auto p1 = std::chrono::system_clock::now();
std::cout << "seconds since epoch: "
<< std::chrono::duration_cast<std::chrono::seconds>(
p1.time_since_epoch()).count() << '\n';
}
Using C++17 or earlier, time() is the simplest function - seconds since Epoch, which for Linux and UNIX at least would be the UNIX epoch. Linux manpage here.
The cppreference page linked above gives this example:
#include <ctime>
#include <iostream>
int main()
{
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result))
<< result << " seconds since the Epoch\n";
}
#include<iostream>
#include<ctime>
int main()
{
std::time_t t = std::time(0); // t is an integer type
std::cout << t << " seconds since 01-Jan-1970\n";
return 0;
}
The most common advice is wrong, you can't just rely on time(). That's used for relative timing: ISO C++ doesn't specify that 1970-01-01T00:00Z is time_t(0)
What's worse is that you can't easily figure it out, either. Sure, you can find the calendar date of time_t(0) with gmtime, but what are you going to do if that's 2000-01-01T00:00Z ? How many seconds were there between 1970-01-01T00:00Z and 2000-01-01T00:00Z? It's certainly no multiple of 60, due to leap seconds.
As this is the first result on google and there's no C++20 answer yet, here's how to use std::chrono to do this:
#include <chrono>
//...
using namespace std::chrono;
int64_t timestamp = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
In versions of C++ before 20, system_clock's epoch being Unix epoch is a de-facto convention, but it's not standardized. If you're not on C++20, use at your own risk.
#include <iostream>
#include <sys/time.h>
using namespace std;
int main ()
{
unsigned long int sec= time(NULL);
cout<<sec<<endl;
}
I created a global define with more information:
#include <iostream>
#include <ctime>
#include <iomanip>
#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) // only show filename and not it's path (less clutter)
#define INFO std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [INFO] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
#define ERROR std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [ERROR] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
static std::time_t time_now = std::time(nullptr);
Use it like this:
INFO << "Hello world" << std::endl;
ERROR << "Goodbye world" << std::endl;
Sample output:
16-06-23 21:33:19 [INFO] main.cpp(main:6) >> Hello world
16-06-23 21:33:19 [ERROR] main.cpp(main:7) >> Goodbye world
Put these lines in your header file. I find this very useful for debugging, etc.
Windows uses a different epoch and time units: see
Convert Windows Filetime to second in Unix/Linux
What std::time() returns on Windows is (as yet) unknown to me (;-))
I want to get the date, month and year information from the string.
Example Date String: Thu, 30 Jul 2020 00:51:08 -0700 (PDT)
PDT here is for Pacific Daylight time. This string offset (-0700) can change based on system timezone when the file was created.
I need to write a c++ program to extract date, month and year from this string.
Any thoughts on how to go about this?
This is a story of evolution. The correct answer greatly depends on your current toolset (how modern it is). And even if it is completely modern, there are still better tools coming.
Homo habilis
In C++98 we could stand upright. And we had tools to scan ints out of arrays of chars. scanf was the tool to do this. This result was not type safe, but we could scan ints and strings and then reinterpret those values as the components of a date: year, month and day. This might look something like this:
#include <cstdio>
#include <cstring>
#include <iostream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
char const* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char wd[4] = {};
int d;
char mon[4] = {};
int y;
sscanf(s.c_str(), "%s %d %s %d", wd, &d, mon, &y);
int m;
for (m = 0; m < 12; ++m)
if (strcmp(months[m], mon) == 0)
break;
++m;
cout << y << '\n';
cout << m << '\n';
cout << d << '\n';
}
This outputs:
2020
7
30
Notes:
The " 00:51:08 -0700 (PDT)" is never even parsed. It could be parsed. But it is a lot more work.
There's no error checking. This might be a valid date or might not.
There's no type safety. The results are just ints and if you mix them up, it's a run-time error, not a compile-time error.
Neanderthal
Using C++98, there's also a popular but non-standard solution: strptime.
#include <time.h>
#include <iostream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
tm tm;
strptime(s.c_str(), "%a, %d %b %Y %T", &tm);
cout << tm.tm_year + 1900 << '\n';
cout << tm.tm_mon + 1 << '\n';
cout << tm.tm_mday << '\n';
cout << tm.tm_hour << '\n';
cout << tm.tm_min << '\n';
cout << tm.tm_sec << '\n';
}
strptime is in the POSIX standard, but not in the C or C++ standards. It is also supported by MS Visual Studio. So it is a popular extension. And with good reason. It is much higher level, and puts the results into a struct tm: A type representing a date/time; the beginnings of type safety.
Output:
2020
7
30
0
51
8
There are still some problems:
" -0700 (PDT)" is never parsed. There's no way to ask strptime to do this.
There are weird and inconsistent offsets on the different fields of tm. For example the month is zero-based and the day is one-based. But at least it knows how to parse the time too, and relatively easily.
Error checking is there but easy to ignore. strptime returns NULL if something bad happens.
Cro-Magnon
With C++11 arrived an actual C++ wrapper around strptime that was officially recognized by the C++ standard with std::get_time:
#include <iomanip>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
istringstream in{s};
in.exceptions(ios::failbit);
tm tm;
in >> get_time(&tm, "%a, %d %b %Y %T");
cout << tm.tm_year + 1900 << '\n';
cout << tm.tm_mon + 1 << '\n';
cout << tm.tm_mday << '\n';
cout << tm.tm_hour << '\n';
cout << tm.tm_min << '\n';
cout << tm.tm_sec << '\n';
}
With a C++ wrapper you can parse from streams, which gives you access to throwing an exception on parse failure. But it is still a simple wrapper and so the result is just a tm. This has the same weirdness as the previous solution.
The output is the same as in the previous solution:
2020
7
30
0
51
8
Homo sapiens
Though the strongly typed std::chrono time_point / duration system was introduced in C++11, it is not until C++20 that it is integrated with the civil calendar, gaining get_time-like functionality, and going far beyond that.
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
istringstream in{s};
in.exceptions(ios::failbit);
local_seconds t;
in >> parse("%a, %d %b %Y %T %z (%Z)", t);
auto td = floor<days>(t);
year_month_day ymd{td};
hh_mm_ss hms{t-td};
cout << ymd << ' ' << hms << '\n';
cout << ymd.year() << '\n';
cout << ymd.month() << '\n';
cout << ymd.day() << '\n';
cout << hms.hours() << '\n';
cout << hms.minutes() << '\n';
cout << hms.seconds() << '\n';
}
Output:
2020-07-30 00:51:08
2020
Jul
30
0h
51min
8s
The first thing to notice is the much stronger type-safety. No longer is there a need to convert everything to ints to print it out. And no longer is it necessary to convert to ints to do other operations such as arithmetic and comparison.
For example ymd.year() has type std::chrono::year, not int. If necessary, one can explicitly convert between these two representations. But it is generally unnecessary, and akin to a risky reinterpret_cast.
There are no longer unintuitive biases such as 1900, or zero-based counts in unexpected places.
Output generally includes the units for easier debugging.
The " -0700 (PDT)" is parsed here! These values are not used in the results, but they must be there, else there is a parse error. And if you want to get these values, they are available with very simple changes:
string abbrev;
minutes offset;
in >> parse("%a, %d %b %Y %T %z (%Z)", t, abbrev, offset);
...
cout << offset << '\n';
cout << abbrev << '\n';
Now the output includes:
-420min
PDT
If you need the fields in UTC, instead of in local time, that is one simple change:
sys_seconds t;
instead of:
local_seconds t;
Now the offset is subtracted from the parsed time point to result in a UTC time_point (a std::chrono::time_point based on system_clock) instead and the output changes to:
2020-07-30 07:51:08
2020
Jul
30
7h
51min
8s
This allows you to easily parse local times plus offset directly into system_clock::time_point.
Though not shipping yet (as I write this), vendors are working on implementing this. And in the meantime you can get this functionality with a free, open-source, header-only C++20 <chrono> preview library that works with C++11/14/17. Just add #include "date/date.h" and using namespace date; and everything just works. Though with C++11/14 you will need to substitute hh_mm_ss<seconds> hms{t-td}; for hh_mm_ss hms{t-td}; (lack of CTAD).
#include <time.h>
char *strptime(const char *buf, const char *format, struct tm *tm);
I've problem with use of the std::localtime function. When I transform a std::time_t to a local struct tm, it always use the american daylight saving time whereas I want to use the european one (France).
UTC : 03/19/16 16:56 is transformed in Local : 03/19/16 18:56.
At this date, normally, local is 17:56 (UTC+1). The DST happens on the 27th in France.
After several tests, it seems that the used DST is based on the american rule : DST happens on second sunday in march.
I've also changed the TZ environement variable, but it also fails.
`
if( putenv( "TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3" ) != 0 ) {
std::cout << "Unable to set TZ" << std::endl;
} else {
tz = getenv("TZ");
if (tz) std::cout << tz << std::endl;
else std::cout << "TZ not defined" << std::endl; tzset();
}
struct std::tm t;
t.tm_sec = 0;
t.tm_min = 56;
t.tm_hour = 18;
t.tm_mday = 19;
t.tm_mon = 3-1;
t.tm_year = 2016-1900;
t.tm_isdst = -1;
std::time_t tt = std::mktime(&t);
std::cout << "UTC: " << std::put_time(std::gmtime(&tt), "%c %Z") << '\n'; // UTC : 03/19/16 16:56
std::cout << "local: " << std::put_time(std::localtime(&tt), "%c %Z") << '\n'; // Local : 03/19/16 18:56 (not waited result)
`
As a precision, I use the bcc32c compiler (the embarcadero C++ clang based computer).
I hope I'm clear enough and you'll be able to help me.
Thanks in advance
If you have C++11 (or later) available, which includes <chrono>, and if you are willing to work with the <chrono> system. And if you are willing to use this free, open-source timezone library. Then this is a very simple matter:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono_literals;
auto zt = make_zoned("Europe/Paris", sys_days{2016_y/mar/19} + 18h + 56min);
std::cout << format("%m/%d/%y %H:%M %Z", zt.get_sys_time()) << '\n';
std::cout << format("%m/%d/%y %H:%M %Z", zt) << '\n';
}
Output:
03/19/16 18:56 UTC
03/19/16 19:56 CET
In short, you form one zoned_time by pairing a timezone of your choosing
("Europe/Paris"), with a sys_time (UTC). Then you can format that zoned_time both by extracting the sys_time back out of it, and by formatting the zoned_time itself, which will use the local_time of the zoned_time.
I attempted to use formatting that was consistent with your comments. You could of course you any format you want. You can also include any std::locale your system supports as the first argument in the calls to format (which %c would take advantage of).
You can also extract individual fields both from the sys_time and from the local_time if you need to, or do other date or time computations. This is more than just a formatting library.
If you are starting with a time_t, there is a static member function of std::chrono::system_clock to convert a time_t to a system_clock::time_point. You can then use that time_point in place of sys_days{2016_y/mar/19} + 18h + 56min in this example:
auto zt = make_zoned("Europe/Paris", system_clock::from_time_t(t));
I have a project about cars with GPS. I need to return the start and the finish moment for each car.
So we have:
time_t x, y;
Because I will use later them for a transformation.
I have a problem. I read from an external file data in this format:
auto1
1439467747492
auto1
1439467748512
...etc.
auto1->name of the car;
1439467747492->the moment in time of the car
I tried to get the first position of the first moment and the last moment for each car. This is the code in C++:
long test = momenti[choice1]/1000;
time_t x = test;
cout << " Momentul initial:\n " << ctime(&x) << endl;
long test1 = momentf[choice1] / 1000;
time_t y = test1;
cout << " Momentul final:\n " << ctime(&y) << endl;
I receive the same date for every car. Is something like momenti[i]=momentf[i]
What did I do wrong?
It is not good. According epoch converter we should get this : GMT: Thu, 13 Aug 2015 12:09:07 GMT
Here is how you can get this output with C++11/14 and using this free, open source date library which extends the C++ <chrono> library to handle dates.
#include "date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using namespace date;
using time_point = std::chrono::time_point<system_clock, milliseconds>;
auto tp = time_point{1439467747492ms};
auto dp = floor<days>(tp);
auto time = make_time(tp - dp);
auto ymd = year_month_day{dp};
cout << "GMT: " << weekday{dp} << ", " << ymd.day() << ' ' << ymd.month()
<< ' ' << ymd.year() << ' ' << time << " GMT\n";
}
Output:
GMT: Thu, 13 Aug 2015 12:09:07.492 GMT
I threw in the fractional seconds for fun, and it seemed a shame to waste them (the C lib won't give them to you). If you really don't want them, it is easy to fix:
auto time = make_time(floor<seconds>(tp) - dp);
Now the output is:
GMT: Thu, 13 Aug 2015 12:09:07 GMT
You need C++14 for the 1439467747492ms above. If you only have C++11 you can sub in this instead: milliseconds{1439467747492}. If you only have C++03, then you are 13 years behind the times and stuck with ctime. ;-)
The chrono solution will offer you greater type safety, more flexibility, and greater performance.
If i can fix and the latitude and longitude problem would be great lol
If you can translate latitude and longitude into an IANA timezone name (and there are tools to do this), I've got a IANA timezone database parser for you which interoperates with <chrono> and "date.h".
#include <iostream>
#include <cstring>
#include <time.h>
using namespace std;
int main()
{
long test = 1439467747492;
time_t x = test;
cout << ctime( &x ) << endl;
return 0;
}
Produces
Tue Sep 18 20:15:32 1990
So I haven't seen here or anywhere else a way to get only the month hours and minutes using <ctime> or other library.
What I can do now is just get the full current date:
time_t now = time(0);
cout<<ctime(&now);
Any suggestions?
You can use the <ctime> standard library like this:
#include <ctime>
#include <iostream>
int main()
{
// get current time
std::time_t timer = std::time(0);
// convert to 'broken time'
std::tm bt = *std::localtime(&timer); // not thread safe
// extract month number from 'broken time' struct
std::cout << "month: " << (bt.tm_mon + 1) << '\n';
std::cout << "hours: " << (bt.tm_hour) << '\n';
std::cout << "mins : " << (bt.tm_min) << '\n';
}
The function std::localtime returns a pointer to an internal statc structure of type std::tm.
Because it returns a pointer to an internal struct it is best to copy it to a local version by dereferencing the pointer using *:
// copy what the returned pointer points to into `bt`.
std::tm bt = *std::localtime(&timer);
Since you are using ctime (C time), all C things should work. You could use strftime
char timestr[32];
strftime(timestr, sizeof(timestr), "%m:%H:%M", localtime(&now));
If boost is fine for you try this one :
boost::posix_time::to_simple_string(boost::posix_time::microsec_clock::local_time()).c_str()
try
std::put_time("%a %b %d %H:%M:%S %Y", &now);