How to get UTC time offset in c++ with windows os - c++

My question is pretty simple. How can I get the UTC offset for Philippines which is +8 and for Japan which is +9, and convert that to integer.
Any suggestions is a great help. Thank you.
UPDATE
For further explanation, I have a c++ desktop application, and I need to automatically detect its timezone wherever the application is used. Like if the application will be used in Japan, the timezone offset for japan will be used. Is that possible?

If you would rather not dig into the Windows-specific API, here is portable, and C++20-standard C++ code1 to do this using Howard Hinnant's timezone library.
#include "date/tz.h"
#include <iostream>
int
main()
{
using date::operator<<;
using std::chrono::system_clock;
std::cout << date::current_zone()->get_info(system_clock::now()).offset << '\n';
}
date::current_zone() detects the computer's current local time zone. This returns a pointer to a date::time_zone which has a member function called get_info().
You can call time_zone::get_info with either a UTC time_point or a local_time time_point to get all kinds of information about this time zone at the indicated point in time (as the information changes with times according to current politics). Use of system_clock::now() as the time_point will get the current information for the time_zone.
A date::sys_info is returned which is an aggregate, one of which members is called offset. This is the current UTC offset with units of std::chrono::seconds.
This just output for me:
-14400s
Indicating that my current local time zone is 14400 seconds west of UTC.
For typical code, one should not program down at the level of adding UTC offsets directly. There is a higher-level API to do this for you. Use of the higher-level API prevents careless errors such as adding the UTC offset when you should have subtracted (or vice-versa). However this low-level API exists because sometimes low-level access to information like this is what makes your program efficient.
For example, here is a higher-level code that simply prints out the current local time:
std::cout << date::make_zoned(date::current_zone(), system_clock::now()) << '\n';
system_clock::now() is still explicitly called, but now the UTC offset addition, as well as the call to current_zone()->get_info() is encapsulated under this higher-level API.
1 This library is in namespace std::chrono in C++20: http://eel.is/c++draft/time.zone.db.access#8

If in your os, std::localtime can access time zone info (in most cases it can, by definition), this is my one-line code:
auto offset_epoch = std::localtime(new time_t(0));
where offset_epoch->tm_hour is the offset hour and offset_epoch->tm_min is the offset minute. You can safely ignore offset_epoch->tm_year as it is of value 70.
It works fine for me so far.

Related

Converting timezone offset from timezone name string in C/C++ in a thread-safe way

I'm trying to implement a function such that can convert a given timezone name string, which it does:
Accepts an input timezone string, for example, "Australia/Melbourne";
Checks host OS (assume it's a POSIX environment) timezone database;
Returns an integer of timezone offset in seconds (for Melbourne in DST, it's 36000).
It can be done by calling putenv("TZ=Australia/Melbourne") but this is may not be thread-safe.
Is there a way to do it without putenv() or somehow let it be thread-safe? Thanks in advance!
Since compilers don't yet support all the features of the C++20 std::chrono library, I will write a solution that's using Howard Hinnant's datehttps://github.com/HowardHinnant/date library. C++20 is introducing std::chrono::zoned_time which you can use to achieve what you want.
#include "date/tz.h"
#include <iostream>
int main()
{
auto current_time = std::chrono::system_clock::now();
auto la = date::zoned_time{"America/Los_Angeles", current_time};
auto sy = date::zoned_time{"Australia/Sydney", current_time};
std::cout << date::format("%T\n", sy.get_local_time() - la.get_local_time());
}
The above example will give you the difference between two time zones. Furthermore, if you want to obtain the current OS's time zone you could use something that, I hope, will be supported by compilers in future - std::chrono::time_zone::name.
In C++20, you will be able to use std::chrono::tzdb::locate_zone(), that will convert a given timezone name to a std::chrono::time_zone object that you can query to get the offset.
There is no standard C function that deals with time zones. There are POSIX.1-compliant functions, but they are indeed not thread-safe. However, depending on your operating system, you might be able to open the timezone database files and parse them manually. For example, on Linux you could open /usr/share/zoneinfo/Australia/Melbourne and parse it according to its specification in the tzfile(5) manpage.
In addition to OP's thread concerns, another consideration:
"timezone offset from timezone name string" is not sufficient in general as the offset differs depending on data/time throughout the year.
Even if no annual daylight adjustments occur in the select zone, the offset can vary due to the history of the zone.
long offset(tz_name) is not enough, long offset(tz_name, time_t t) is needed.

does a C++ locale have an associated timezone? And if yes, how do you access it?

I've done a little research on this, and I have pretty convincing evidence for the
answer YES, and the answer NO. I'm not sure which side to believe.
First, the documentation I've found on cppreference.com, and
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf appear to say nothing about this.
I take that as evidence that locales do NOT support a timezone.
But https://en.cppreference.com/w/cpp/locale/time_get/get and https://en.cppreference.com/w/cpp/locale/time_put/put
both say:
%z writes offset from UTC in the ISO 8601 format (e.g. -0430), or no
characters if the time zone information is not available %Z writes
time zone name or abbreviation, or no characters if the time zone
information is not available (locale dependent)
which appears to suggest there is a timezone SOMETIMES associated with
a locale () object.
Now, if you take the locale en_US.utf8 (one of my favorites ;-)), there really isn't any sensible
timezone to associate (the United States contains at least 4 or more timezones).
So time to get empirical.
I ran the code:
#include <iostream>
#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;
int main ()
{
// locale l;
locale l = locale::classic ();
tm when{};
const time_put<char>& tmput = use_facet<time_put<char>> (l);
ostringstream oss;
oss.imbue (l);
static const string kTZOffsetPattern_{"%z"};
tmput.put (oss, oss, ' ', &when, kTZOffsetPattern_.c_str (), kTZOffsetPattern_.c_str () + kTZOffsetPattern_.length ());
cout << oss.str ();
return 0;
}
On Linux (ubuntu), this gave the answer I expected, +0000 (OK, I also wouldn't have been surprised with error or empty string).
But on Windows (visual studio.net 2k17 - 15.8.7) - this gives:
-0500
Yes, as you may have guessed, I'm testing this in the eastern timezone. But I still would have expected
0, or the empty string (especially for the locale::classic() case).
Direct Answer to your question
Does a C++ locale have an associated time zone?
No.
Nor will it in the future. As correctly noted in the question, for many locales it wouldn't make sense as the geographical area represented by the locale can have more than one time zone.
The C standard does say in the spec for strftime:
%Z is replaced by the locale’s time zone name or abbreviation, or by no characters if no
time zone is determinable. [tm_isdst]
But the C spec for struct lconv provides no such member to store that information. The spec does allow implementations to add such members, but in practice, implementations do not store that information with the C locale.
The C++ locale facets time_put and time_get define themselves in terms of the C spec for strftime, the POSIX spec for strptime, and some additions, which do not include a time zone name or abbreviation.
The POSIX spec for strftime is much more detailed than the C spec, and removes the association with "locale":
Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
The POSIX spec for struct lconv is also much more detailed than the C spec, but still does not provide storage for a time zone name or abbreviation.
But the future does bring hope of more easily and effectively accessing information about time zones, at least in C++.
Prior to C++20, C++ has knowledge of:
A single time standard: UTC, which is closely modeled by Unix Time.
A single time zone: the "local time zone" set by the user or administrator of the computer. UTC can also be used as a local time zone.
As detailed above, the local time zone is not part of the C++ (or C) locale data. The locale data does include some calendrical data such as:
Full and abbreviated weekday names.
Full and abbreviated month names.
Local conventional formats for displaying date and time (e.g. year, month, day ordering).
The UTC offset (%z) and time zone abbreviation (%Z) may be available, but would be stored as part of the local time zone data, instead of with the current locale data, largely because there is not a good one-to-one mapping between time zones and locales.
Explanation of what happened with the code presented in the OP's question
In your example: tm when{}; zeroes all members of the tm, including tm_isdst. When tm_isdst is zero, this means Daylight Saving Time is known to not be in effect, for this particular tm.
tm is also allowed to have members not specified by the standard. A popular extension is to have a member tm_gmtoff which holds the UTC offset in seconds. If your Linux implementation has such a member, tm when{}; would have set it to 0 seconds. If your Windows implementation does not have such a member, the UTC offset of the local time zone would be stored elsewhere. This explains the differences you're seeing, and both implementations are conforming.
Helpful information about how to access time zones since C++ locales do not provide access
In the C++20 spec, there exists a new type called std::chrono::time_zone. One of the member functions of time_zone is:
template<class Duration> sys_info get_info(const sys_time<Duration>& st) const;
sys_time<Duration> is just a system_clock::time_point, but of any precision. So you give a time_zone a time_point, and you get back a sys_info which contains all kinds of useful information about that time_zone at that time_point:
struct sys_info
{
sys_seconds begin;
sys_seconds end;
seconds offset;
minutes save;
string abbrev;
};
The range [begin, end) tells you for what times this information is valid (these are UTC time points).
offset is the time_zone's current UTC offset in seconds.
If save != 0min, the time_zone is currently considered to be in daylight savings.
The time_zone's current abbreviation is stored in abbrev.
Additionally, there is a non-member function:
const time_zone* current_zone();
which returns a pointer to your current local time zone. Putting this all together, here is a C++20 program that prints out interesting information about your current local time zone:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << current_zone()->get_info(system_clock::now()) << '\n';
}
This just output for me:
2018-03-11 07:00:00
2018-11-04 06:00:00
-04:00:00
01:00
EDT
If you like, you can experiment with this part of C++20 using C++11, 14 or 17 by using Howard Hinnant's timezone library. This library puts everything in namespace date instead of std::chrono.
You can also get information on any IANA time zone, for example:
#include "date/tz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << locate_zone("Australia/Sydney")->get_info(system_clock::now()) << '\n';
}
which just output for me:
2018-10-06 16:00:00
2019-04-06 16:00:00
11:00:00
01:00
AEDT
Note though that even in C++20, time zones and locales are not coupled. It just doesn't make sense to do so.
does a C++ locale have an associated timezone?
All aspects of current timezone are implementation defined.
The exact wording of %Z specifier from C99 (C++ delegates C library function specification to the C standard) is:
is replaced by the locale’s time zone name or abbreviation, or by no characters if no time zone is determinable.
It seems a bit ambiguous. One interpretation is indeed that locale may affect the time zone. Another, which doesn't quite fit the wording as well, would be that the locale affects the name or abbreviation of the time zone. Regardless, there appears to be no guarantee that the time zone isn't affected by the locale, although I would not expect that it were.
how do you access it?
As far as I know, you can't using standard library utilities. Not directly anyway, and no way of modifying it.
A way to print the current timezone is to use the %z or %Z format specifiers of strftime/put_time/time_put as you've shown.
There is a way to get the zone difference as an integer as well. std::mktime unparses a std::tm structure into a timestamp according to the locale, while std::gmtime parses a timestamp into std::tm structure according to the UTC, so if you start with the epoch and combine those two, you will get the difference of the current locale time zone and the UTC in seconds.
std::time_t t = 0;
std::cout << -1 * std::mktime(std::gmtime(&t));
The relevant passage of the C standard (which the C++ standard relies upon) says
%z is replaced by the offset from UTC in the ISO 8601 format ‘‘−0430’’ (meaning 4 hours 30 minutes behind UTC, west of Greenwich), or by no characters if no time zone is determinable. [tm_isdst]
%Z is replaced by the locale’s time zone name or abbreviation, or by no characters if no time zone is determinable. [tm_isdst]
Note that time zone name is said to be locale dependent, but time zone offset is not.
Cppreference needs to fix their sloppy wording.

Using std::chrono / date::gps_clock for converting a double gps timestamp to utc/tai

I get a timestamp from a GPS device in a gps_data struct as a double.
I'd like to convert this GPS timestamp to UTC and TAI times, something simple as:
void handle_gps_timestamp(double timestamp)
{
double utc = utc_from_gps(timestamp);
double tai = tai_from_gps(timestamp);
do_stuff(gps, utc, tai);
}
Luckily I found Howard Hinnant's date and timezone library (proposed for C++20) that seems to provide this exact functionality. Unfortunately, at least from what I can see, the date/tz/chrono library has no convenient methods that allow this simple usage.
I must first somehow "transfer" my double into a known chrono/date type. But OK, since I understand the overall concept, namely that the timepoint is defined as a duration after (or before) the epoch of a clock, and I think that this is a beautiful model.
Assumption
I should be able to very easily translate that model to fit my problem, right?
In my case, I have a timestamp that is a point in time, specified as the duration since the gps epoch. Now, there should be a class type of a clock that abstracts and handles all of this for me, I'd like to think. And yes! There is a date::gps_clock and a date::gps_time, which surely should do the work.
Problem
I cannot make it work for me. I'm sure the solution is trivial.
Question
Can someone give me a helping hand, showing how I should use Howard's date library applied to my problem?
It is difficult to answer this question precisely because the input to the problem is underspecified:
I get a timestamp from a GPS device in a gps_data struct as a double ... specified as the duration since the gps epoch.
Therefore I'm going to make some assumptions. I'll state all of my assumptions, and hopefully it will be clear how to alter my answer for other guesses/facts about what that double represents.
Let's say that the double is a non-integral count of milliseconds since the gps epoch. Let's furthermore assume that I want to capture the precision of this input down to microseconds.
#include "date/tz.h"
#include <cstdint>
#include <iostream>
int
main()
{
double gps_input = 1e+12 + 1e-3;
using namespace date;
using namespace std::chrono;
using dms = duration<double, std::milli>;
gps_time<microseconds> gt{round<microseconds>(dms{gps_input})};
auto utc = clock_cast<utc_clock>(gt);
auto tai = clock_cast<tai_clock>(gt);
std::cout << gt << " GPS\n";
std::cout << utc << " UTC\n";
std::cout << tai << " TAI\n";
}
I've arbitrarily created an example input and stored it in gps_input.
Some using directives make the code a lot less verbose.
A custom chrono::duration type that exactly matches the documented specification for what the double represents makes things much simpler, and lessens the chance for errors. In this case I've made a chrono::duration that stores milliseconds in a double and named that type dms.
Now you simply convert the double to dms, and then using round, convert the dms to microseconds, and store those microseconds in a gps time point with precision microseconds or finer. One could use duration_cast in place of round, but when converting from floating point to integral, I usually prefer round, which means round-to-nearest-and-to-even-on-tie.
Now that you have a gps_time, one can use the clock_cast function to convert to other times such as utc_time and tai_time.
This program outputs:
2011-09-14 01:46:40.000001 GPS
2011-09-14 01:46:25.000001 UTC
2011-09-14 01:46:59.000001 TAI
Adjust the milliseconds and microseconds units above as needed. For example if the input represents seconds, the easiest thing to do is to default the second template argument on dms:
using dms = duration<double>;
This library works with C++11/14/17. And with minor modifications it is now part of the official C++20 specification.
The other answer isn't bad but it does require you to have c++17, curl, run cmake, and acquire some custom libraries.
Something that is much easier to drop in as a .h and .cpp would be http://www.leapsecond.com/tools/gpsdate.c.
That doesn't handle the TAI conversion but that might also be on that list.

How to get the local current time in seconds since epoch in C++ (MSVS)?

I need the local (with timezone offset) current time in seconds since epoch. The following code looks a bit clumzy because it creates an intermediate temporary structure tm which is superfluous. Why do I have to get time_t then convert it to tm in order to return to time_t? Is there a better way?
time_t ct = time(0);
tm lct = tm();
localtime_s(&lct, &ct);
ct = _mkgmtime(&lct);
If you want to get the local time (with time zone and DST applied) in portable C, then yes, it's generally a two-step procedure: starting with your time-since-the-epoch, first call localtime, then do something with the resulting broken-down struct tm. (Usually what I do next is call strftime.)
You can also call ctime to get a local time string directly.
The reason there are a lot of different function calls involved is that, unfortunately, there are several different time formats in use. (And the reason for that is that dates and times are complicated!) You can represent time as seconds-since-1970. You can represent it as a struct tm. You can represent it as a string (in one of several zillion formats). In Unix and Linux, you can represent it as a struct timeval or a struct timespec.
But one thing there isn't a straightforward or standard way to do, as you've discovered, is get local time as seconds-since-1970. But the reason for that is that it's not a very useful representation. In general, there are two things you might want to do with a date/time value: (1) perform computations on it or (2) display it to the user. If you want to display it to the user, you probably want to display it in local time, so there are lots of ways of converting to local time in human-readable format in any format you want. (As I said, the usual way is to call localtime, then strftime.) But if you want to perform computations, really the only way to do those is using seconds-since-1970 in UTC, because that makes all the other hairy problems go away. How many days are there in the month? Is it a leap year? What time zone are we in? Is daylight saving time in effect?
If you try to represent local time as seconds-since-1970, though, you're probably fibbing. For example, right now, the time is 1460383736, which is 14:08:56 UTC. Where I'm sitting, that's 10:08:56 EDT (U.S. Eastern time, DST in effect). So I suppose I could say that's 1460369336 seconds since 1970, local time. But, again where I'm sitting, 1460369336 seconds ago was not midnight on January 1, 1970 -- it was actually 11 pm on December 31, 1969. It's off by an hour, and the reason is that DST was not in effect on January 1, 1970.
So, bottom line, I would encourage you to rethink the way you're handling local times, because while it's possible to compute this "seconds-since-1970 as local time" value, it's an odd thing to do, and it's likely to cause you various problems which will be much harder to work around than if you used a more straightforward scheme.
But, if you really want to, here are two ways you might be able to determine the offset between UTC and local time, without calling gmtime or _mkgmtime:
Call localtime, and look at the tm_gmtoff field. (Unfortunately, this field is nonstandard, and not present on all systems.)
Call the obsolete ftime function, and look at the timezone field of struct timeb. (Here there are several gotchas: not only is ftime obsolete and nonstandard, but the timezone field is in minutes, and it's positive for zones west of Greenwich, while tm_gmtoff is negative.)
But, anyway, those would more or less directly give you the number to add to or subtract from your UTC seconds-since-1970 value to get "local" seconds-since-1970.
Here is a way to do this computation using the C++11/14 <chrono> library plus this free, open-source timezone library to do the conversion to local time.
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
auto now = floor<seconds>(system_clock::now());
auto s = current_zone()->to_local(now) - local_days{1970_y/jan/1};
cout << s.count() << '\n';
}
You first discover your current IANA timezone with current_zone(). Then you get the current time with system_clock::now() and truncate it to seconds. Next you can convert that to your local time, and then subtract the result from any epoch you desire (1970-01-01 in this example).
The result is of type std::chrono::seconds.
All this being said, I share the same reservations about doing this as described in Steve Summit's answer.
If you instead decide to represent the timestamp as a string, that is also easily done:
auto now = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
auto str = format("%F %T %z", now);
str has type std::string. This just output for me:
2016-04-11 11:42:50 -0400
which is my current local time (truncated to seconds), and my current local UTC offset.
If in the future you decide that seconds-precision is too coarse, you can easily change the above code to any other precision by just changing one line:
floor<milliseconds>(system_clock::now());
and now the contents of str would look like:
2016-04-11 11:42:50.368 -0400

C++ Equivalent for GetLocalTime in Linux (with milliseconds!)

I have been searching for over an hour but I simply seem to not be able to find the solution!
I am looking for a function that gives me a similar struct as GetLocalTime on Windows does. The important thing for me is that this struct has hours, minutes, seconds and milliseconds.
localtime() does not include milliseconds and therefore I cannot use it!
I would apprechiate a solution that uses the standard library or another very small library since I am working on a Raspberry Pi and connot use large libraries like boost!
As it was mentioned above, there are not direct equivalent. If you can use C++ 11, <chrono> header allows to get the same result, but not in single call. You can use high_resolution_clock to get current Unix time in milliseconds, then you can get localtime C function to get time without milliseconds, and use current Unix time in milleseconds to find milliseconds count. It looks like you will have to write your own GetLocalTime implementation, but with C++ 11 it will not be complex.
GetLocalTime is not a usual Linux function.
Read time(7), you probably want clock_gettime(2), or (as commented by Joachim Pileborg), the older gettimeofday(2)
If you need some struct giving all of hours, minutes, seconds, milliseconds you have to code that yourself using localtime(3) and explicitly computing the millisecond part.
Something like the below code is printing the time with milliseconds
struct timespec ts = {0,0};
struct tm tm = {};
char timbuf[64];
if (clock_gettime(CLOCK_REALTIME, &ts))
{ perror("clock_gettime"), exit(EXIT_FAILURE);};
time_t tim = ts.tv_sec;
if (localtime(&tim, &tm))
{ perror("localtime"), exit(EXIT_FAILURE);};
if (strftime(timbuf, sizeof(timbuf), "%D %T", &tm))
{ perror("strftime"), exit(EXIT_FAILURE);};
printf("%s.%03d\n", timbuf, (int)(ts.tv_nsec/1000000));
You can use a combination of:
clock_gettime(CLOCK_REALTIME); returns local time, up to millisecond (of course constrained by the actual clock resolution); does not care of local timezone information, returns UTC time. Just use millisecond information (from tv_nsec field).
time(); returns local time, up to the second - no millisecond - also UTC time. time() results (a time_t) is easy to convert to the final format.
then convert time() result using localtime_r(); this sets up a structure very similar to Windows SYSTEMTIME; result is up to the second, and takes into account local timezone information.
finally set up the millisecond field using clock_gettime() results.
These routines are documented, not deprecated, portable.
You may need to call tzset() once (this sets the timezone information - a C global variable - from operating system environment - probably a heavy operation).