How could I determine the day of the week in California (Pacific Time) based on an arbitrary Unix timestamp (seconds)? I have searched around, but have not found a built-in library for C++.
UTC is generally 8 hours ahead of PT, but simply subtracting 8 hours from the Unix timestamp and creating a tm
struct doesn't work since this discounts daylight savings nuances.
Here's how to do it using Howard Hinnant's date library. This is a free MIT-licensed C++11/14 library based on <chrono>
:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono_literals;
using namespace date;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = make_zoned("America/Los_Angeles", unix_timestamp);
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
The first line just constructs the unix timestamp (which you may have from other sources). In C++11 we do not have the chrono-literals and so this line would instead be:
auto unix_timestamp = sys_seconds{seconds{1479664467}};
make_zoned()
creates a zoned_time<seconds>
based on the unix_timestamp
and the time_zone
"America/Los_Angeles". A zoned_time
is a collection of a time_zone
and unix timestamp.
You can get the local time out of a zoned_time
with zt.get_local_time()
. This is a chrono::time_point
but with no clock associated with it. The precision of this time point will be equal to the precision of your original time stamp (seconds in this case).
You can get the local day of the week of the local_time
by truncating the local_time
to a precision of days
:
floor<days>(zt.get_local_time())
And this day-precision time_point
will convert to type weekday
.
A weekday
can be printed out, participate in weekday
arithmetic and comparisons, or be explicitly converted to an unsigned
in the range [0, 6].
The program above outputs:
Sun
The timezone part of this library is a faithful representation of the IANA timezone database. It will give correct adjustments between local time zones and UTC as far back as the mid 1800's up through present day. If you pass the library timestamps prior to the mid 1800's the earliest known UTC offset is extrapolated backwards to the year -32768. You can also pass timestamps as far in the future as the year 32767 and the current offset and daylight saving rules will be propagated forward.
As this library is built on <chrono>
, it will handle any precision that <chrono>
supplies. Note that some chrono::duration
s such as nanoseconds
have a more limited range (+/-292 years for nanoseconds
).
The library / process is thread safe. That is, the program works directly with whatever time zone you specify without changing your computer's time zone or environment variables under the hood. It also does not involve the part of the C timing API which is known to not be thread safe because of non-const function local statics.
Ported to recent versions of gcc, clang and VS.
The above program can trivially be ported to C++20 (some vendors support this as I write and some don't yet):
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
auto unix_timestamp = sys_seconds{1479664467s};
auto zt = zoned_time{"America/Los_Angeles", unix_timestamp};
auto wd = weekday{floor<days>(zt.get_local_time())};
std::cout << wd << '\n';
}
Hacky way using standard UNIX C (non thread safe version):
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void print_times() {
char my_buf[100];
time_t now = time(NULL);
printf(ctime(&now));
strftime(my_buf, 100, "DoW=%w Tz=%Z\n", localtime(&now));
printf(my_buf);
}
int main( int argc, char * argv[] ) {
print_times();
setenv("TZ", "America/Los_Angeles", 1);
print_times();
unsetenv("TZ");
print_times();
}
Unfortunately, TZ
env var or changing the file /etc/localtime
are the only ways you can effect timezone settings for the UNIX time functions (Under the hood tzset() uses these sources to initialize a set of shared variables that encode the timezone settings for all the library functions).
An issue is you need to come with the UNIX TZ string(s) for the zone(s) you need. zoneinfo format is the simplest and recommended format to use. I used tzselect
to generate that TZ value for Pacific time.
Also see man 5 localtime
, man tzselect
for info on the standard UNIX timezone setup.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With