29

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.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

5 Answers5

10

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.

Community
  • 1
  • 1
Tobu
  • 24,771
  • 4
  • 91
  • 98
  • 3
    I can't speak for other environments, but MSVS 2008's implementation of `_get_tzname()` returns a name, like "Pacific Standard Time"; Boost's `posix_time_zone` wants something like "PST". Also, btw, `tzname` (POSIX, standard calls it `_tzname`) is a 2-D char array. [MSVC also supplies a `TZNAME_MAX`, if you `#define _POSIX_`, but set to 10, apparently an oversight from an earlier implementation.] – Mike C May 15 '12 at 16:50
  • 1
    I wrote "Boost wants something like 'PST'" which was slightly inaccurate; Boost wants something like "PST-8". You can use a bogus label; since I don't intend to display the TZ, I just figure out the bias and use "XXT-8". – Mike C May 15 '12 at 17:49
  • Another thing is, even working around @MikeC 's problem, this still won't work on MSVC. Even using `_tzset()` works only for UTC offset, but doesn't correctly interpret DST change definitions from the TZ variable (some particular US rules are hardcoded). – BartoszKP Jan 29 '15 at 12:29
  • "You could build a posix_time_zone using the non-DST and DST offsets" - yes that's exactly what I would want to do (and what would answer the question). The advantage is that it would hide the ICU dependencies (timezone and unicode related classes), when I work with boost everywhere already. – BartoszKP Feb 03 '15 at 17:22
4

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.

sumwale
  • 199
  • 1
  • 1
1

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.

amphetamachine
  • 27,620
  • 12
  • 60
  • 72
1

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.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Thanks. While this input is valuable it unfortunately doesn't answer the question at all :) I know about boost's limitations and I know about ICU (in fact, boost documentation itself recommends using it instead of boost :) ). – BartoszKP Feb 01 '15 at 16:08
  • @BartoszKP could you please elaborate on what kind of answer your looking for then? Thanks. – Matt Johnson-Pint Feb 01 '15 at 20:00
  • What do you mean by "what kind"? Any kind that demonstrates how to have boost's `time_zone_ptr` correctly set to machine's current timezone in a portable way - that's what the question asks. You can imagine that I'd rather not add another dependency, and the question is about boost, but if the only possibility is to use ICU then so be it. Unfortunately, this part of your answer, the only part that's directly relevant, is link-only. – BartoszKP Feb 02 '15 at 00:11
0

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

Nicklas A.
  • 6,501
  • 7
  • 40
  • 65
  • No. Getting a local time from Boost with a correct TZ offset requires setting the correct TZ offset first. – Mike C May 15 '12 at 17:46
  • 1
    Actually, I think my previous comment was mistaken, but I haven't delved deeper to figure it out. There is a local clock and a posix clock. – Mike C May 18 '12 at 16:49