Reputation: 38307
Ideally, what I'd like to be able to do is take the name of a time zone and call a function to ask for its corresponding time zone info (offset from UTC, DST offset, dates for DST switch, etc.) in Linux. However, I can't find any way to do this. The information exists in /usr/share/zoneinfo/
in the various binary files there, but I don't know how to read them or if there is a way to get the OS to give you the information in them rather than having to read them in yourself. So, I'm looking for a way to get this information. Ideally, there would be a posix function which would do it for you so that it would work on POSIX systems other than Linux, but if there isn't, I'd at least like to know the proper way (or at least the best way) to get the time zone info for an arbitrary time zone in Linux.
Upvotes: 3
Views: 2705
Reputation: 219578
New answer for an old question.
Rationale for new answer: There is now a modern, free, open-source, C++11/14/17 library to do this.1 It does require some installation. But it is portable across Linux/macOS/Windows. And it has full documentation, and even a video introduction.
Here is an example program to get information about a specific time zone. I'm using my own timezone just as an example. This library supports the full IANA timezone database:
#include "tz.h"
#include <iostream>
int
main()
{
auto zone = date::locate_zone("America/New_York");
std::cout << *zone << '\n';
std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
}
The first line looks up a database by its IANA name.
auto zone = date::locate_zone("America/New_York");
The return type is a date::time_zone const*
. This function can never return nullptr
, though it will throw if it can't locate the time zone (with an excellent what()
).
The second line prints out the definition of the time zone:
std::cout << *zone << '\n';
The output of this line is not generally useful to clients of this library. It is mainly useful to myself in debugging the library:
America/New_York -04:56:02 LMT 1883 Nov/18 12:03:58 1883-11-18 17:00:00 UTC 1883-11-18 12:03:58 STD 1883-11-18 12:03:58 00:00 {nullptr, -32768} {nullptr, 32767}
-05:00:00 US E%sT 1920 Jan/01 00:00:00 1920-01-01 05:00:00 UTC 1920-01-01 00:00:00 STD 1920-01-01 00:00:00 00:00 S {US 1918 1919 Mar/Sun[last] 02:00:00 01:00 D, 1918} {US 1918 1919 Oct/Sun[last] 02:00:00 00:00 S, 1919}
-05:00:00 NYC E%sT 1942 Jan/01 00:00:00 1942-01-01 05:00:00 UTC 1942-01-01 00:00:00 STD 1942-01-01 00:00:00 00:00 S {NYC 1920 1920 Mar/28 02:00:00 01:00 D, 1920} {NYC 1921 1954 Sep/Sun[last] 02:00:00 00:00 S, 1941}
-05:00:00 US E%sT 1946 Jan/01 00:00:00 1946-01-01 05:00:00 UTC 1946-01-01 00:00:00 STD 1946-01-01 00:00:00 00:00 S {US 1942 1942 Feb/09 02:00:00 01:00 W, 1942} {US 1945 1945 Sep/30 02:00:00 00:00 S, 1945}
-05:00:00 NYC E%sT 1967 Jan/01 00:00:00 1967-01-01 05:00:00 UTC 1967-01-01 00:00:00 STD 1967-01-01 00:00:00 00:00 S {NYC 1921 1954 Apr/Sun[last] 02:00:00 01:00 D, 1946} {NYC 1955 1966 Oct/Sun[last] 02:00:00 00:00 S, 1966}
-05:00:00 US E%sT 32767 Dec/31 00:00:00UTC 32767-12-31 00:00:00 UTC 32767-12-30 19:00:00 STD 32767-12-30 19:00:00 00:00 S {US 1967 1973 Apr/Sun[last] 02:00:00 01:00 D, 1967} {US 2007 32767 Nov/Sun[1] 02:00:00 00:00 S, 32767}
But one of the reasons for me showing this line is to illustrate that asking for information about a time zone, without also supplying a time point, is not likely to give you the information you're looking for. The information about a timezone is itself a function of time, including the offsets, daylight saving details, abbreviations, etc.
The final line:
std::cout << zone->get_info(std::chrono::system_clock::now()) << '\n';
is likely to be most helpful. This returns an aggregate sys_info
that looks like this:
struct sys_info
{
sys_seconds begin;
sys_seconds end;
std::chrono::seconds offset;
std::chrono::minutes save;
std::string abbrev;
};
This just output for me:
2016-11-06 06:00:00
2017-03-12 07:00:00
-05:00:00
00:00
EST
Which means:
Of course you can access the fields of this aggregate in your program as opposed to just printing them out.
If you want to see what this result might look like 6 months from now:
std::cout << zone->get_info(std::chrono::system_clock::now() + date::months{6}) << '\n';
which currently outputs:
2017-03-12 07:00:00
2017-11-05 06:00:00
-04:00:00
01:00
EDT
This is all considered to be low-level access in this library. There exists higher-level API so that you don't have to deal with low level concepts such as the current UTC offset. The low-level stuff is there if you need it (not hidden away), but not necessary for common use cases such as getting the current time in any specific time zone:
using namespace date;
using namespace std::chrono;
std::cout << make_zoned("America/New_York", system_clock::now()) << '\n';
which just output for me:
2017-03-07 19:26:53.711662 EST
In C++17, due to template deduction guides, the above line will no longer need "make factory functions" for deduction purposes:
std::cout << zoned_time{"America/New_York", system_clock::now()} << '\n';
zoned_time
is a class template, templated on duration, and deduced by the chrono::duration
of the chrono::time_point
(the second argument -- in my case microseconds
).
This is a full-featured date/time/timezone library with both low-level access, and high-level abstractions (true to the philosophy of C++). Correctness and type-safety are highly valued in this library. It is an extension, not a replacement, of the <chrono>
library introduced in C++11.
1Disclaimer: I am the principal author of this library, though there are many contributors (to which I am grateful).
Upvotes: 1
Reputation: 239371
The tzcode package (found along with the data at ftp://ftp.iana.org/tz/releases) contains a description of the tzfile format along with a header file tzfile.h
for working directly with that data.
Upvotes: 3
Reputation: 755094
There isn't a standard way to do that. You could look at ICU. It claims:
Formatting: Format numbers, dates, times and currency amounts according the conventions of a chosen locale. This includes translating month and day names into the selected language, choosing appropriate abbreviations, ordering fields correctly, etc. This data also comes from the Common Locale Data Repository.
Time Calculations: Multiple types of calendars are provided beyond the traditional Gregorian calendar. A thorough set of timezone calculation APIs are provided (emphasis added).
Upvotes: 1