Opened 13 years ago

Last modified 9 years ago

#3336 new Bugs

utc offset calculated wrong

Reported by: silvan@… Owned by: az_sw_dude
Milestone: Boost 1.57.0 Component: date_time
Version: Boost 1.54.0 Severity: Problem
Keywords: Cc:

Description

Boost seems to invert the posix time zone specs or even worse to calculate them completely wrong:

http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html

states:

"If preceded by a '-', the timezone shall be east of the Prime Meridian; otherwise, it shall be west (which may be indicated by an optional preceding '+' )."

Using the following lines in a c++ program:

  time_zone_ptr myzone(new posix_time_zone(string("CET-1CEST,M3.5.0,M10.5.0/3"))); // e.g. Europe/Berlin
  cout << "Posix time string: " << myzone->to_posix_string() << endl;
  local_date_time mylocaltime(date(2009,8,11), time_duration(17,0,0), myzone, true);
  cout << "Wall clock: " << mylocaltime.local_time() << endl;
  cout << "Time in UTC: " << mylocaltime.utc_time() << endl;

gives following output:
Posix time string: CET-01CEST+01,M3.5.0/02:00,M10.5.0/03:00
Wall clock: 2009-Aug-11 17:00:00
Time in UTC: 2009-Aug-11 17:00:00

The system I used: Debian GNU/Linux squeeze/sid
uname -a
Linux fafner 2.6.28.7 #1 SMP Mon Mar 16 17:39:15 CET 2009 i686 GNU/Linux

output from date:
date -d "2009-8-11 17:00 CEST "
Di 11. Aug 17:00:00 CEST 2009
date -d "2009-8-11 17:00 CEST " -u
Di 11. Aug 15:00:00 UTC 2009

Libraries (debian): libboost-date-time1.38.0 libboost-date-time1.38-dev libboost-date-time-dev

The time zone spec ist taken from /usr/share/zoneinfo/CET on my system.

Change History (5)

comment:1 by Steven Watanabe, 13 years ago

Component: Nonedate_time
Owner: set to az_sw_dude

comment:2 by Jason Pettiss <jpettiss@…>, 12 years ago

The UTC offset in POSIX 1003.1 section 8.3 TZ strings is inverted from that in Olson TZ database strings, which is a cause for confusion. The former treats UTC as relative to the local time, i.e what do we add to the local wall clock to produce the wall clock time in UTC. The latter treats the local time as relative to UTC, as in, what do we add to the time in UTC to get to the local time.

The man pages for tzset(3) seem pretty consistent although some are clearer than others. I like this wording best, myself:

offset
Indicates the value one must add to the local time to arrive at Coordinated Universal Time.

Sun is their own celestial body but they see it the same way:

http://docs.sun.com/source/816-5523-10/appf.htm

USA (Eastern) EST5EDT
Russia (Moscow) MST-3MDT

Here also, positive is west of Greenwich, negative is east of it.

As a hacky workaround, the string can be manipulated prior to feeding it to posix_time_zone. Find the first [0-9+-]. If we're not at the end of the string, if '+' change to '-' and vice versa. Otherwise insert '-' before the current position. Something like the following (untested!):

void fliptzoffset(std::string& tzstr) {
  std::string::iterator i = tzstr.begin(), e = tzstr.end();
  while (i != e && !isdigit(*i) && '+'!=*i && '-'!=*i) ++i;
  if (i == e) return;
  if ('-' == *i) *i = '+';
  else if ('+' == *i) *i = '-';
  else tzstr.insert(i, '-');
}

comment:3 by roman.fietze@…, 10 years ago

Version: Boost 1.38.0Boost 1.44.0

This bug doesn't seem to get a lot of attention.

It is still valid for newer versions of the boost library.

comment:4 by Alexey Spiridonov <bstbg.20.lesha@…>, 9 years ago

Just got bitten by the same bug. Correct behavior:

$ export TZ="PST-8PDT,M3.2.0,M11.1.0"; date -d@1383465600
Sun Nov  3 16:00:00 PST 2013

posix_time_zone maps the same timestamp with the same timezone string to "Sun Nov 3 01:00:00 PST 2013" (16 hours - 1 DST adjustment). Here's another (currently working) link to the POSIX RFC that boost::local_time purports to implement:

http://tools.ietf.org/html/draft-ietf-dhc-timezone-01

The relevant text is at the end of page 2, beginning of page 3.

The boost::local_time documentation and code are both written assuming "-" means "west of Greenwich" and "+" means "east of Greenwich", but the standard clearly states otherwise.

Flipping the sign is pretty easy (I can send a patch, even), but I'm not sure what's Boost's preferred approach for fixing such errors. The flip would break code that depends on the currently broken behavior.

If it's not appropriate to fix the bug in the current API, posix_time_zone2 might be introduced that has the correct sign. Does anybody see other approaches?

comment:5 by Alexey Spiridonov <bstbg.20.lesha@…>, 9 years ago

Milestone: Boost 1.40.0Boost 1.57.0
Version: Boost 1.44.0Boost 1.54.0

I reproduced it in 1.51 and 1.54.

Note: See TracTickets for help on using tickets.