Reputation: 804
I'm having troubles building a UTC date in c++ using the standard library. For example (any is fine):
or parsing
01/01/1970 00:00:00 UTC
01/01/1970 00:00:00 +0000
01/01/1970 00:00:00 # (implicitely in UTC)
Conditions:
The best candidates so far are:
std::time_get
but specification doesn't say anything about the timezone (for what I understood of it :-) ).date_time
, but its a pretty heavy dependency (mentioned in C++ library (unix) to parse date/time string Including timezones, but the answer predates C++11)strptime
is not portable on windowsstd::tm
directly, but on my system (glibc), it has non-standard undocumented fields (namely tm_zone ...). I suppose I could initialize it with gmtime(0)
then modify the days, month, year fields.How can I build an std::chrono::time_point::time_point
from the UTC date?
Upvotes: 3
Views: 1724
Reputation: 218750
How can I build a
std::chrono::system_clock::time_point
from the UTC date?
Just for this part of it, here is a header-only high-performance C++11/14 modern solution. It can be used like this:
int y = 2016;
int m = 1;
int d = 14;
int h = 18;
int min = 2;
int sec = 15;
std::chrono::system_clock::time_point tp =
date::sys_days{date::year{y}/m/d} +
std::chrono::hours{h} +
std::chrono::minutes{m} +
std::chrono::seconds{sec};
This is an open source, free library on github. Here is a video presentation of the library. This library is portable to all recent implementations of C++11 and C++14 (including VS2013 and VS2015). It offers a better interface than tm
inherited from C, and a greater range of validity. It also offers higher performance, and a great deal of compile-time abilities in C++14. It is designed to be a simple extension of <chrono>
, and is thus fully interoperable with <chrono>
.
For parsing, use tz.h:
01/01/1970 00:00:00 UTC
#include "tz.h"
#include <iostream>
#include <sstream>
int
main()
{
std::istringstream in{"01/01/1970 00:00:00 UTC"};
date::sys_seconds tp;
date::parse(in, "%d/%m/%Y %T %Z", tp);
using namespace date;
if (!in.fail())
std::cout << tp << '\n';
}
In the above code, sys_seconds
is a std::chrono::time_point<system_clock, seconds>
.
01/01/1970 00:00:00 +0000
Change %Z
to %z
above.
01/01/1970 00:00:00
Remove the %Z/%z
.
- avoid external libraries if possible
Sorry, but otherwise you have to:
- messing around with std::tm directly,...
This library allows you to parse both %z
and %Z
. You can throw away the abbreviation, or discover it, and try to figure out what it means (in general the abbreviation is ambiguous). With %z
the offset will alter the parsed value to give you UTC:
std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::sys_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
std::cout << tp << '\n';
Output:
1969-12-31 19:00:00
If you would rather get the local time, that is easy too:
std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::local_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
std::cout << tp << '\n';
Output:
1970-01-01 00:00:00
local_seconds
is a std::chrono::time_point
, but based on a "clock" which has no now()
.
Upvotes: 2
Reputation: 323
Better use std::tm
... As it is standard.
Don't worry about tm_zone. It's an optional field, only available in some environment like Linux/GNU or freeBSD... (actually, it comes with glibc, as you pointed out).
It as, nevertheless NO functionnal effect.
A program using it should have a #ifndef
or #ifdef
directive to embed the statement, allowing compilation on systems without the field defined in the structure.
To answer your last question... Unsure of your your needs, but a starting point can be :
system_clock::time_point tp = system_clock::now();
as found here :
http://www.cplusplus.com/reference/chrono/time_point/time_since_epoch/
Hope it helps,
PS : throw an eye on this : Difference between steady_clock vs system_clock?
Upvotes: 0