I need to be able to convert Epoch time to Excel time.
Why Excel, because working with the numeric excel time is faster that any parsing done on display formats.
Current time of 2018-06-08 12:46:58 CDTwith UTC 1528480019 should give 0.5326157.
But converted to the New_York time or 2018-06-08 13:46:58 EDT will give 0.574282367.
I only need to convert the time field to Excel style.
Here is my incomplete code:
double GetTime(Datetime currtime, std::string tz = "TZ=America/New_York")
{
std::time_t t = currtime;
//tzset(tz);
std::tm tm = *std::localtime(&t);
return ((tm.tm_hour * 3600 + (tm.tm_min) * 60.0 + tm.tm_sec) / 86400.0);
}
The code works, but only for local time which is "America/Chicago".
I have been unable to use the set the timezone to the one I might need.
Also tm seems to be limited to seconds, but I need to handle milliseconds and microseconds as well.
Furthermore, I need it to be fast and the the current implementation parses the time into separate fields and then I combine it into what I need which seems to do a lot of extra work.
This problem can easily be solved with Howard Hinnant's free, open-source date/time/timezone library, which is very efficient. This library is also in the current C++20 working draft, under namespace std::chrono. So in the future, porting your code to just use the std::lib ought to be as easy as changing a few namespaces.
double
GetTime(std::chrono::system_clock::time_point currtime,
date::time_zone const* tz = date::current_zone())
{
using namespace date;
using namespace std::chrono;
zoned_time<system_clock::duration> zt{tz, currtime};
auto lt = zt.get_local_time();
auto ld = floor<days>(lt);
using ExcelTime = duration<double, days::period>;
ExcelTime tod = lt - ld;
return tod.count();
}
Instead of taking a Datetime it takes a std::chrono::system_clock::time_point, and instead of a std::string, a date::time_zone const*.
On the three big platforms (llvm/gcc/MSVS), the coarsest system_clock::time_point is microseconds, which meets your precision goals.
Step one is to create a zoned_time which is a pairing of a time_point with a time_zone. From this one can get a local_time.
floor<days> truncates the precision of a time_point to days. If one subtracts the day-precision time_point from the finer-precision time_point, one gets the local time-of-day.
If you store this local time-of-day in a chrono::duration that has a double as its representation, and a period of 1 day, then you get the Excel Time-Of-Day format.
This can be used like:
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << std::fixed << std::setprecision(9);
std::cout << GetTime(sys_seconds{1528480019s}, locate_zone("America/Chicago")) << '\n';
zoned_time<system_clock::duration> zt{"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s};
std::cout << GetTime(zt.get_sys_time(), zt.get_time_zone()) << '\n';
}
which outputs:
0.532627315
0.574282407
Above, I struggled to come as close as possible to your existing API. However if you adopt this library, you can make it even simpler, and slightly more efficient, by adopting a "more native" API:
std::chrono::duration<double, date::days::period>
GetTime(const date::zoned_time<std::chrono::system_clock::duration>& zt)
{
using namespace date;
auto lt = zt.get_local_time();
return lt - floor<days>(lt);
}
Now GetTime takes just a single parameter of type zoned_time<system_clock::duration>, and returns a duration<double, days::period>. All that's left for GetTime to do is truncate the local time to days-precision and subtract to get time-of-day.
The demo in main is also simplified:
std::cout << GetTime({"America/Chicago", sys_seconds{1528480019s}}).count() << '\n';
std::cout << GetTime({"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s}).count() << '\n';
And gives the same output as before.
Related
I'm trying to find the best way to see if the current time is before a specified time. Say I want to see if it's before 14:32. What's the best way to do this in C++? Ideally I'd be able to build some time object that represents 14:32, then compare it with the current time as some object.
This is what I'm doing right now. Pretty messy and uses 3 different representations of time.
int hour_ = 14;
int min_ = 32;
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t(now);
std::tm utc_tm = *gmtime(&tt);
if ((utc_tm.tm_hour < hour_) || (utc_tm.tm_hour == hour_ && utc_tm.tm_min < min_) ) {
std::cout << "It's before " << hour_ << ":" << min_ << std::endl;
}
Here is how you can do it in C++20. Later I will show how to convert this to use a free, open-source C++20 chrono preview library which works with C++11/14/17.
#include <chrono>
bool
is_now_before(std::chrono::minutes local_config_tod)
{
using namespace std::chrono;
auto tz = current_zone();
auto now = system_clock::now();
auto local_day = floor<days>(zoned_time{tz, now}.get_local_time());
auto utc_config = zoned_time{tz, local_day + local_config_tod}.get_sys_time();
return now < utc_config;
}
The parameter has type minutes which will be interpreted to be the local time of day in minutes. For example 14:32 is represented by minutes{872}. This representation is compact (one integer), and it is trivial to convert {hours, minutes} to just minutes (shown below).
current_zone() gets the computer's current local time zone. This information is needed twice in this function, so it is best to just get it once. Not only does this save the result, but it also sidesteps the problem of the local time zone changing out from under you (between multiple calls) in a mobile device.
Next the current time is obtained (just once) via system_clock. This gives the current time in UTC.
Now we have a choice:
We could do the comparison in UTC, or
We could do the comparison in local time.
Doing the comparison in UTC is less error prone in the corner case that the UTC offset is changing in the current local day (such as going on or off of daylight saving).
To convert the local config time-of-day (local_config_tod) to a UTC time_point one first has to find out what the current local day is. In general this can be different than the current UTC day. So the current UTC now has to be converted to local time, and then truncated to days-precision:
auto local_day = floor<days>(zoned_time{tz, now}.get_local_time());
Now a local time_point can be created simply by summing local_day and local_config_tod. This local time_point can then be converted back into UTC (a time_point based on system_clock but with seconds precision):
auto utc_config = zoned_time{tz, local_day + local_config_tod}.get_sys_time();
The line of code above handles the corner cases for you. If there is not a unique (one-to-one) mapping from local time to UTC, then an exception is thrown. The .what() of the exception type will have a detailed description about how this mapping is either ambiguous, or non-existent.
Assuming the above mapping does not throw an exception, you can simply compare these two UTC time_points:
return now < utc_config;
The precision of this comparison is with whatever precision your system_clock has (typically microseconds to nanoseconds).
This can be exercised like so:
int hour_ = 14;
int min_ = 32;
using namespace std::chrono;
auto b = is_now_before(hours{hour_} + minutes{min_});
If 14 and 32 are literals (and you're in C++14 or later), it can be shortened to:
auto b = is_now_before(14h + 32min);
If you are using a standard prior to C++17, the zoned_time constructions will require an explicit template parameter:
auto local_day = floor<days>(zoned_time<system_clock::duration>{tz, now}.get_local_time());
auto utc_config = zoned_time<minutes>{tz, local_day + local_config_tod}.get_sys_time();
If you would like to use the free, open-source C++20 chrono preview library, add #include "date/tz.h" and using namespace date;. Some installation is required.
If you would like to avoid an exception in the case that local_day + local_config_tod does not have a unique mapping to UTC, that is also possible with minor changes to is_now_before. But you will have to decide things such as: Do I want to compare against the first or second local_config_tod of the local_day (in case the UTC offset has been decreased).
Oops! Is the config time already UTC?
On re-reading your question it occurred to me that I may have misread your question. If 14:32 is UTC, then things get much, much simpler! And rather than removing my answer showing the local 14:32 interpretation, I thought it would be better to add this, so future readers could pick either solution.
Assuming the config is a UTC time, then time zones play no role at all:
#include <chrono>
bool
is_now_before(std::chrono::minutes utc_config_tod)
{
using namespace std::chrono;
auto now = system_clock::now();
auto utc_day = floor<days>(now);
return now < utc_day + utc_config_tod;
}
The current day in UTC is simply:
auto utc_day = floor<days>(now);
And now the config date-time is simply utc_day + utc_config_tod. This is just drop-dead simple.
If you can't use C++20, the free, open-source C++20 chrono preview library is also much simpler now as it is header-only, requiring no installation at all. Just #include "date/date.h" and add using namespace date;.
In C++ we can use the mt_structure from the date/time functions (documentation here: https://en.cppreference.com/w/cpp/chrono/c/tm) Here is how I would print the date, and check to see if it's past a certain time
#include <iostream>
#include <ctime>
#include <chrono>
using namespace std;
int main()
{
time_t t = time(0); // get time now
tm* now = localtime(&t);
cout << (now->tm_year + 1900) << '-'
<< (now->tm_mon + 1) << '-'
<< now->tm_mday << ", "
<< now->tm_hour << ":" << now->tm_min
<< "\n";
int hour = 7, minute = 30;
if((now->tm_hour > hour) || (now->tm_hour == hour && now->tm_min >= minute))
cout << "it's past 7:30\n";
else
cout << "it's not past 7:30";
}
prints:
2021-10-27, 20:40
it's past 7:30
case
I need to write a program that moves files around at times that are set in a configuration file. The time can be 00:00:01 seconds untill 24:00:00 hours. This is converted into seconds. So if somebody wants to move a file at 12:00:00 pm today, the move time is 12 * 60 * 60 = 43200 seconds. This is done every day and the program needs to check if that time is reached.
I use the chrono library to get the time now since epoch in seconds using:
auto dayInSeconds = 86400;
auto currentTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock().now().time_since_epoch());
auto timeWithoutDays = currentTime % dayInSeconds;
std::cout << "time in seconds today: " << timeWithoutDays.count() << std::endl;
problem
This shows me the current time since epoch in seconds. But now for example ( 13:45 Amsterdam time) it returns a number of: 42294. If I run it exactly five seconds later in a loop it returns 42299. So the counting seems to be correct. What is not correct, is that 42299 seconds is 1174 hours (42299/ 60 /60). Which should mean that is now 11:somewhat AM but its 13:32 PM. Or not? What am I doing wrong? I just need to know, how many seconds have passed since 00:00:00 this day. So i can check if the user set time is passed and stuff needs to be done.
I would like to keep using the chrono library for all sorts of reasons, but mainly because I understand that one. So if answers use that library, it would be a great help. I have a feeling i'm doing something completely stupid.
fix
For any other that seeks the same answer. I fixed it like this, it seems to work:
auto dayInSeconds = 86400;
auto amsterdamUTCPlusTime = 7200;
auto currentTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock().now().time_since_epoch());
auto timeWithoutDays = currentTime % dayInSeconds;
auto currentTimeInSeconds = timeWithoutDays.count() + amsterdamUTCPlusTime;
std::cout << "time in seconds today: " << currentTimeInSeconds << std::endl;
C++20 brings extensions to <chrono> to deal with timezones. It isn't shipping yet (to the best of my knowledge). But here is what it will look like:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
zoned_time zt{"Europe/Amsterdam", floor<seconds>(system_clock::now())};
auto lt = zt.get_local_time();
auto tod = lt - floor<days>(lt);
cout << "time in seconds today: " << tod.count() << '\n';
cout << hh_mm_ss{tod} << '\n';
}
Example output:
time in seconds today: 71923
19:58:43
If your computer's local time zone setting is already set to "Europe/Amsterdam", then "Europe/Amsterdam" above can be replaced with current_zone().
This gets the current time in UTC, truncates it to seconds precision, and then pairs it with the "Europe/Amsterdam" time_zone to create a zoned_time. Then the local time is extracted from the zoned_time. The local time of day is simply the local time minus the beginning of that day (floor<days>(lt)). This is stored in tod which has type seconds. Wrapping it in a hh_mm_ss prints it out in a hh:mm:ss format.
There exists a free, open-source C++20 <chrono> preview library which can be used with C++11/14/17 to do this. To use it, it must be installed. There's a single source file to be compiled, tz.cpp, and it needs to have access to the IANA time zone database, which can be automatically downloaded with specific build settings.
The source code above must be trivially modified by adding #include "date/tz.h" and using namespace date;. In C++11 and 14, change zoned_time to zoned_seconds, and hh_mm_ss to hh_mm_ss<seconds>.
Another possibility is to build your own UTC offset calculator for just Amsterdam (assuming current rules). The advantage of this is that it can use of subset of the free, open-source C++20 <chrono> preview library which is header-only, and thus requires no installation, and does not need the IANA time zone database. That could like this:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
auto AmsterdamOffset = [](system_clock::time_point tp)
{
auto const y = year_month_day{floor<days>(tp)}.year();
auto const start = sys_days{Sunday[last]/March/y} + 1h;
auto const end = sys_days{Sunday[last]/October/y} + 1h;
if (start <= tp && tp < end)
return 2h;
return 1h;
};
auto now = floor<seconds>(system_clock::now());
auto local_now = now + AmsterdamOffset(now);
auto tod = local_now - floor<days>(local_now);
cout << "time in seconds today: " << tod.count() << '\n';
cout << hh_mm_ss{tod} << '\n';
}
This program hardcodes the fact that Amsterdam daylight saving begins on the last Sunday of March at 01:00:00 UTC and ends on the last Sunday of October at 01:00:00 UTC.
After that, the program logic is much like the C++20 solution shown above. In C++11, 1h and 2h will have to be changed to hours{1} and hours{2} respectively.
And yet another approach: Posix time zones
There is also a Posix time zone library at this link in ptz.h. This is also a header-only library, so no install issues. It allows you to use the C++20 zoned_time combined with Posix time zones. This will give you the same results as the example above with the "hard coded" rules for Amsterdam (which are valid back through 1978).
#include "date/ptz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
// Amsterdam rules
Posix::time_zone tz{"CET-1CEST,M3.5.0,M10.5.0/3"};
zoned_time zt{tz, floor<seconds>(system_clock::now())};
auto lt = zt.get_local_time();
auto tod = lt - floor<days>(lt);
cout << "time in seconds today: " << tod.count() << '\n';
cout << hh_mm_ss{tod} << '\n';
}
The above assumes C++17. If in C++11 or 14 the syntax becomes a little messier:
zoned_time<seconds, Posix::time_zone> zt{tz, floor<seconds>(system_clock::now())};
The Posix::time_zone is not part of the C++20 <chrono> library, but is compatible with it. It can be used with the C++20 std::chrono::zoned_time class template as shown above.
You can use localtime function and get the current time from system.
int getIntTime()
{
struct timeb now;
struct tm *curtime;
curtime = localtime(&now);
return(curtime->tm_hour * 10000L + curtime->tm_min * 100L + curtime->tm_sec);
}
And also you should convert the set time in confgi file to same as output of this function and compare them as follow:
if(getIntTime() >= converted_time_configfile )
{
//do processing
}
I'm trying to get the current year stored in a date from before 1970 using an std::chrono::time_point<std::chrono::system_clock>, however I've run into an issue regarding the reading from its contents into a std::tm struct.
I convert the time_point to a time_t first, after which I read its values to get the tm_year value. However, when trying to do so, the code fails when using localtime_s, however it succeeds when I'm using gmtime_s. This is only for dates before 1-1-1970, dates after that work fine using both functions.
The code below reproduces the error. If terstGmTimeVsLocalTime is called with utc=true it works, if it is called with utc=false it doesn't produce the correct output.
#include <iomanip>
#include <time.h>
#include <iostream>
void testGmTimeVsLocaltime(const bool& utc) {
// Create time
std::tm timeInfoWrite = std::tm();
timeInfoWrite.tm_year = 1969 - 1900; // Year to parse, here it is 1969
timeInfoWrite.tm_mon = 0;
timeInfoWrite.tm_mday = 1;
timeInfoWrite.tm_hour = 1;
timeInfoWrite.tm_min = 0;
timeInfoWrite.tm_sec = 0;
timeInfoWrite.tm_isdst = -1;
std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::from_time_t(utc ? _mkgmtime(&timeInfoWrite) : std::mktime(&timeInfoWrite));
// Convert to time_t
std::time_t timeT = std::chrono::system_clock::to_time_t(timePoint);
// Read values
std::tm timeInfoRead;
if (utc) {
gmtime_s(&timeInfoRead, &timeT);
} else {
localtime_s(&timeInfoRead, &timeT);
}
// Output result
std::cout << (timeInfoRead.tm_year + 1900) << '\n';
// Wait for input
std::getchar();
}
int main() {
testGmTimeVsLocaltime(true); // Set to false to show bug
return 0;
}
utc=true outputs 1969, as would be expected. However, utc=false outputs 1899 (presumably since an error occurs and tm_year gets set to -1).
Is there anything I'm missing? The documentation doesn't specifically specify that localtime_s should fail for dates before 1-1-1970.
I'm on Windows 10 x64 if it makes a difference.
Using Howard Hinnant's free, open-source date lib, you can completely side-step the clumsy, error and bug-prone C api, and work directly with a modern <chrono>-based system:
#include "chrono_io.h"
#include "date.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
sys_days timePoint = timeInfoWrite; // this is a chrono::time_point
std::cout << timePoint.time_since_epoch() << '\n'; // -365 days
// Convert to time_t
// no need
// Read values
year_month_day timeInfoRead = timePoint;
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-365[86400]s
1969
There are literals to make it easy to fill in a year_month_day struct which is the analog to the year, month and day parts of a tm. You can easily convert this to a std::chrono::time_point<system_clock, days> (sys_days). This is the same as a system_clock::time_point, but with a precision of days instead. It itself will implicitly convert to a seconds-precision time_point (typedef'd to sys_seconds), or to a system_clock::time_point.
Above I just output its time_since_epoch() which shows that it is -365 days prior to the epoch.
There's never really any need to convert to C API data structures, but it is easy if you want to. For example, assuming time_t is seconds since 1970-01-01:
std::time_t timeT = sys_seconds{timePoint}.time_since_epoch().count();
std::cout << timeT << '\n';
which outputs:
-31536000
The reverse conversion (back to year_month_day) is just as easy. If you want to convert from timeT it is just slightly more involved:
year_month_day timeInfoRead = floor<days>(sys_seconds{seconds{timeT}});
This first converts time_t to chrono::seconds, and then to a seconds-precsion time_point, and then to a days-precsion time_point, finally to the year_month_day field type (tm-like).
Finally year_month_day has a year() getter member function which is streamable. You can explicitly convert year to int if desired:
int{timeInfoRead.year()}
But I think it best to keep things like years, months and days as distinct types so that the compiler can help you catch when you accidentally mix them up.
Finally, if you really meant that you wanted 1969-01-01 00:00:00 in your computer's local timezone, there's a library to do that as well. And it is just a minor modification of the simple program above.
#include "tz.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
using namespace std::chrono;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
auto timePoint = make_zoned(current_zone(), local_days{timeInfoWrite});
// Convert to time_t
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
std::cout << timeT << '\n';
// Read values
timePoint = sys_seconds{seconds{timeT}};
year_month_day timeInfoRead{floor<days>(timePoint.get_local_time())};
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-31518000
1969
Now you create a zoned_seconds using the computer's current_zone() timezone, and converting your timeInfoWrite to local_days instead of to sys_days.
You can get the local time or the system time out of timePoint. For converting to time_t, system time makes the most sense:
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
And now the output (for me) is 5h later (18000s).
-31518000
You can get back either the local year, or the system (UTC) year, by either using .get_local_time() or .get_sys_time(). For me it makes no difference ("America/New_York"). But if you're in "Australia/Sydney", you'll get 1968 if you request the UTC year instead of 1969. And that's all very easy to simulate by simply substituting "Australia/Sydney" or "America/New_York" for current_zone() in the program above.
Yes, it works on Windows, VS-2013 and later. There is some installation required for the timezone lib: https://howardhinnant.github.io/date/tz.html#Installation
I am trying to replace a number of different time classes with a single consistent API. However I have recently run into a problem whereby I cannot serialise the timezone offset correctly. Note that I am attempting to replicate an existing format that is already in wide use in the system.
The format should be YYYY-mm-DD HH:MM:SS.xxxxxxx -HHMM, where the x represents the sub-second precision and the last -HHMM is the TZ offset from UTC.
Code:
using namespace My::Time;
namespace chrn = std::chrono;
time_point now = clock::now();
time_point lclNow = getDefaultCalendarProvider()->toLocal(now);
duration diff{ lclNow - now };
std::wstring sign = diff > duration::zero() ? L" +" : L" -";
duration ms{ now.time_since_epoch().count() % duration::period::den };
int diffHrs = popDurationPart<chrn::hours>(diff).count();
int diffMins{ abs(chrn::duration_cast<chrn::minutes>(diff).count()) };
std::cout << Format{ lclNow, TimeZone::UTC, L" %Y-%m-%d %H:%M:%S." } << ms.count()
<< sign << std::setfill(L'0') << std::setw(2) << diffHrs
<< std::setfill(L'0') << std::setw(2) << diffMins << std::endl;
Problem:
Expected:<2016-05-25 09:45:18.1970000 +0100> Actual:< 2016-05-25
09:45:18.1964787 +0059>
The expected value is what you get when I use the old class to do the same operation. The problem appears to be at the point where I attempt to get the difference between lclNow and now.
Currently I am in UTC +1 (due to DST being in effect). However the diff value is always 35999995635. Being on Visual C++ in Windows the tick is 100 ns, so there are 10000000 ticks per second, meaning the diff value is 3599.9995 seconds, which is just short of the 3600 seconds I would need to make an hour.
When I print the two time values using the same format then I can see that they are exactly one hour apart. So it appears that the time-zone translation is not the issue.
The issue appears to have come from the time-zone conversions as I was attempting (as SamVarshavchik pointed out). Unfortunately I am unable to use Howard Hinnant's very complete date and tz libraries because they require a mechanism to update the IANA time-zone DB that is required for them to work, so I resorted to wrapping the Windows native calls for the time-zone conversions; namely the TzSpecificLocalTimeToSystemTime and SystemTimeToTzSpecificLocalTime functions.
However these only work with SYSTEMTIME and not time_point. This meant I took the quick and easy option of converting the time_point to a FILETIME (just modify the "epoch") and the FILETIME to a SYSTEMTIME before passing it to one of the two above functions. This resulted in truncation of the time value when it was pushed into the SYSTEMTIME struct (which only holds millisecond resolution). The outcome is that while I was accurate for dates, I was not entirely accurate when converting the date back into the original value.
The new solution does no calendar mapping for the basic time_point to time_point translations. It uses the following code to work out the offset in std::chrono::minutes (where zoneInfo is a TIME_ZONE_INFORMATION):
time_point WindowsTzDateProvider::doToUtc(const time_point& inLocal) const {
return inLocal + getBias(inLocal);
}
time_point WindowsTzDateProvider::doToLocal(const time_point& inUtc) const {
return inUtc - getBias(inUtc);
}
std::chrono::minutes WindowsTzDateProvider::doGetBias(const time_point& input) const {
bool isDst = CalendarDateProvider::isDstInEffect(input);
minutes baseBias{ zoneInfo.Bias };
minutes extraBias{ isDst ? zoneInfo.DaylightBias : zoneInfo.StandardBias };
return baseBias + extraBias;
}
bool CalendarDateProvider::isDstInEffect(const time_point& t) {
time_t epochTime = clock::to_time_t(t);
tm out;
#ifdef WIN32
localtime_s(&out, &epochTime);
#else
localtime_r(&out, &epochTime);
#endif
return out.tm_isdst > 0;
}
Note: I'm using the non-virtual interface idiom for the classes, hence the "do..." versions of the methods.
Consider using this free, open source time zone library which does exactly what you want with very simple syntax, and works on VS-2013 and later:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
auto t = make_zoned(current_zone(), system_clock::now());
std::cout << format("%F %T %z", t) << '\n';
}
This should output for you:
2016-05-25 09:45:18.1970000 +0100
What would be the next best thing for strptime when we have the datetime string with millisseconds?
Given:
"30/03/09 16:31:32.121"
we can't use the regular strptime because struct tm doesn't store millisseconds. Is there a new class that can achieve this?
I would parse these fields manually (reading into int and double for the seconds), then use days_from_civil to convert the year/month/day into a chrono::system_clock::time_point:
std::chrono::system_clock::time_point t(days(days_from_civil(y, m, d)));
where days is:
using days = std::chrono::duration<int, std::ratio<86400>>;
Then you can add to that the hours, minutes and seconds. To handle the fractional seconds you'll need to do a slight dance:
double s;
your_stream >> s; // 32.121
using namespace std::chrono;
duration<double> dsecs(s);
seconds sec = duration_cast<seconds>(dsecs);
milliseconds ms = duration_cast<milliseconds>(dsecs - sec);
t += sec + ms;
If you prefer, use round from here for your milliseconds conversion:
milliseconds ms = round<milliseconds>(dsecs - sec);
duration_cast is truncate towards zero. There are other rounding modes: floor, round, ceil, at this link.
Wrap it all up in a neat function for easy reuse. :-)
The above code all assumes UTC. If your date/time that you are parsing is known to be offset from UTC, you can add/subtract that offset. All known implementations of system_clock track Unix time, which is seconds since 1970-01-01 in the UTC time zone.
Update
Since writing this answer I've developed a more general library that the OP seemed to be seeking at that time. It can parse a wide variety of sub second precisions directly into a std::chrono::system_clock::time_point like this:
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
std::istringstream in{"30/03/09 16:31:32.121\n"
"30/03/09 16:31:32.1214"};
std::chrono::system_clock::time_point tp;
in >> date::parse("%d/%m/%y %T", tp);
using namespace date;
std::cout << tp << '\n';
in >> date::parse(" %d/%m/%y %T", tp);
std::cout << tp << '\n';
}
This outputs:
2009-03-30 16:31:32.121000
2009-03-30 16:31:32.121400
This library uses the same techniques and tools as I originally described, but is packaged up and ready to go as a single header library.