How to get the current time zone?

2019-01-18 18:10发布

问题:

In most of the examples I had seen:

time_zone_ptr zone( new posix_time_zone("MST-07") ); 

But I just want to get the current time zone for the machine that runs the code. I do not want to hard code the time zone name.

回答1:

Plain posix: call tzset, use tzname.

#include <ctime>
tzset();
time_zone_ptr zone(new posix_time_zone(tzname[localtime(0)->tm_isdst]));

Posix with glibc/bsd additions:

time_zone_ptr zone(new posix_time_zone(localtime(0)->tm_zone));

The above are abbreviated Posix timezones, defined in terms of offset from UTC and not stable over time (there's a longer form that can include DST transitions, but not political and historical transitions).

ICU is portable and has logic for retrieving the system timezone as an Olson timezone (snippet by sumwale):

// Link with LDLIBS=`pkg-config icu-i18n --libs`
#include <unicode/timezone.h>
#include <iostream>

using namespace U_ICU_NAMESPACE;

int main() {
  TimeZone* tz = TimeZone::createDefault();
  UnicodeString us;
  std::string s;

  tz->getID(us);
  us.toUTF8String(s);
  std::cout << "Current timezone ID: " << s << '\n';
  delete tz;
}

On Linux, ICU is implemented to be compatible with tzset and looks at TZ and /etc/localtime, which on recent Linux systems is specced to be a symlink containing the Olson identifier (here's the history). See uprv_tzname for implementation details.

Boost doesn't know how to use the Olson identifier. You could build a posix_time_zone using the non-DST and DST offsets, but at this point, it's best to keep using the ICU implementation. See this Boost FAQ.



回答2:

Quite late in the day, but I was looking for something similar so this can hopefully help others. The following (non-boost) way using strftime seems to work on most platforms:

  time_t ts = 0;
  struct tm t;
  char buf[16];
  ::localtime_r(&ts, &t);
  ::strftime(buf, sizeof(buf), "%z", &t);
  std::cout << "Current timezone: " << buf << std::endl;
  ::strftime(buf, sizeof(buf), "%Z", &t);
  std::cout << "Current timezone: " << buf << std::endl;

Or one can use std::time_put for a pure C++ version.



回答3:

Well, maybe you could do it using the GeoIP library. I know it's a bit of an overkill, but since most computers in the world are connected to the internet, you could probably get away with it. According to the guy I'm developing for, it's been over 99% accurate.

Note: This is a dumb idea. I am just stretching for answers.



回答4:

In order to properly answer this question, it's important to understand that the time zone support in Boost is severely limited.

  • It's primarily focused on POSIX time zones, which have several limitations. These limitations are discussed in the POSIX section of the timezone tag wiki, so I won't repeat them here.

  • It has functions that work with IDs of IANA/Olson time zones, but it artificially maps these to POSIX values - which has the effect of flattening the time zone to a single point in history. These mappings are stored in a csv file in the Boost source code.

  • The csv file hasn't been updated since April 2011, and there have been many changes to time zones since then. So, the mappings it does have are somewhat inaccurate.

In general, I would not recommend Boost for working with time zones. Instead, consider the ICU TimeZone Classes, which are part of the ICU project. You will find these to be fully portable, and they have full and correct time zone support.

It's worth mentioning that ICU is used in many popular applications. For example, the Google Chrome web browser gets it's time zone support from ICU.

In ICU, the current local system time zone is available as the default time zone. You can read more in the section "Factory Methods and the Default Timezone" in the ICU documentation.



回答5:

You could always try getting the universal time and local time from boost and checking the difference, it's probably full of caveats though.