I'm extracting the year/month/day/hours/min/sec/nanoseconds from a source containing nanoseconds since Epoch, using the answer to the below question:
Extract year/month/day etc. from std::chrono::time_point in C++
However, my input is a different timezone. Below is the code I have so far.
- How do I convert the below to read from a different timezone?
- Do I need to convert before I perform the
duration_casts? Otherwise the number of hours/mins/secs could be wrong?
I'm using C++17, Clang, Linux and prefer standard libraries. Will be moving to C++20 in a few months and I suspect that would simplify the answer.
using namespace std;
using namespace std::chrono;
using Clock = high_resolution_clock;
using TimePoint = time_point<Clock>;
const nanoseconds nanosecondsSinceEpoch(nanosecondsSinceEpochTS);
const Clock::duration since_epoch = nanosecondsSinceEpoch;
const TimePoint time_point_sinc_epoch(since_epoch);
using days = duration<int, ratio_multiply<hours::period, ratio<24> >::type>;
system_clock::time_point now = time_point_sinc_epoch; // Do I need to handle timezone here before duration_cast?
system_clock::duration tp = now.time_since_epoch();
days d = duration_cast<days>(tp);
tp -= d;
hours h = duration_cast<hours>(tp);
tp -= h;
minutes m = duration_cast<minutes>(tp);
tp -= m;
seconds s = duration_cast<seconds>(tp);
tp -= s;
const uint64_t nanosSinceMidnight = tp.count();
time_t tt = system_clock::to_time_t(now);
tm utc_tm = *gmtime(&tt); // Presumably this needs to change
std::cout << utc_tm.tm_year + 1900 << '-';
std::cout << utc_tm.tm_mon + 1 << '-';
std::cout << utc_tm.tm_mday << ' ';
std::cout << utc_tm.tm_hour << ':';
std::cout << utc_tm.tm_min << ':';
std::cout << utc_tm.tm_sec << '\n';
Since your input and output are in the same timezone, the timezone itself becomes irrelevant. This subsequently makes this problem very easy. One simply converts the count of nanoseconds into the desired fields. I recommend one short public domain helper function to convert the count of days into a
{y, m, d}data structure.Output:
Update
After discussions in the comments below, it was discovered that
nanosecondsSinceEpochTSis UTC, not America/Chicago as I presumed. That means that the UTC offset, which is a function of both the timezone and the nanosecond count, must be added to the count as the first step. And then proceed as directed above to get each field.Finding the correct offset is a non-trivial procedure which I won't attempt to show code for. One technique is to precompute a table of
{utc_timestamp, utc_offset}for all of the input years in question, and then use the inpututc_timestampto look up the correct offset.In C++20 one can simply:
And get the output:
If one wants the integral fields:
Disclaimer: As I write this, no vendor is yet shipping this part of C++20.
Update for POSIX time zones
If you're willing to use this free, open-source, header-only library you can use POSIX time zones which avoid the IANA database install issues.
It looks like:
which outputs:
Note that this only models America/Chicago back to 2007. Prior to 2007 America/Chicago had different daylight saving rules.