Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time: time.Parse mishandles southern hemisphere daylight savings? #3604

Closed
rsc opened this issue May 9, 2012 · 5 comments
Closed

time: time.Parse mishandles southern hemisphere daylight savings? #3604

rsc opened this issue May 9, 2012 · 5 comments
Milestone

Comments

@rsc
Copy link
Contributor

rsc commented May 9, 2012

Why does the Sydney case not recognize EDT?


---------- Forwarded message ----------
From: Russ Cox <rsc@golang.org>
Date: Wed, May 9, 2012 at 11:44 AM
Subject: Re: [go-nuts] incorrect documentation in "time" package?
To: andrey mirtchovski <mirtchovski@gmail.com>
Cc: Kyle Lemons <kevlar@google.com>, Aaron Bohannon <aaron678@gmail.com>,
golang-nuts@googlegroups.com


If you call time.Parse and ask it to parse a string like "EST" against
"MST", that's not really well-defined.  Is it EST as in New York time
or is it EST as in Sydney time?  Of course, if time.Parse just
rejected that request outright, that would be not very useful.

So time.Parse does the following when trying to parse a zone abbreviation:

1. If the zone abbreviation corresponds to a valid abbreviation for
the zone that is used in the default location (time.Local) at the
given time, then time.Parse uses that location. So if your program is
running on a computer set up to default to New York or Sydney time and
you parse a time when EST is in use there, then parsing "EST" uses
time.Local and will end up with that location's zone offset (-05:00 or
+11:00).

2. If the zone abbreviation is "GMT" or "UTC", then time.Parse uses
time.UTC as the location.

3. Otherwise, the zone abbreviation is unrecognized.  time.Parse can't
be expected to know the location you want, but maybe you don't care
about the location, so it creates a stub implementation to record the
abbreviation and uses zone offset 0.  When you print such a time and
only show the abbreviation, you get back what you put in.  This is
useful in many contexts, but it does mean that a computer set up to
default to California time treats "EDT" with a meaning that is both
not New York and not Sydney.

If you don't look closely, it can be hard to distinguish case #1 from
case #3, but the difference is one reason that the default format for
printing a time.Time prints both the zone abbreviation and its offset.
 If you do look closely, you can see the difference.

$ cat x.go
package main

import (
       "fmt"
       "time"
)

func main() {
       fmt.Printf("time.Local = %v\n", time.Local)

       show("01/01/2011 12:00am EST")
       show("01/01/2011 12:00am EDT")
       show("07/01/2011 12:00am EST")
       show("07/01/2011 12:00am EDT")
       show("01/01/2011 12:00am PST")
       show("07/01/2011 12:00am PDT")
}

func show(s string) {
       t, err := time.Parse("01/02/2006 3:04pm MST", s)
       if err != nil {
               fmt.Printf("Parse(%q): %v\n", s, err)
               return
       }
       fmt.Printf("Parse(%q) = %v\n", s, t)
}
$ TZ=America/New_York go run x.go
time.Local = America/New_York
Parse("01/01/2011 12:00am EST") = 2011-01-01 00:00:00 -0500 EST
Parse("01/01/2011 12:00am EDT") = 2011-01-01 00:00:00 +0000 EDT
Parse("07/01/2011 12:00am EST") = 2011-07-01 00:00:00 +0000 EST
Parse("07/01/2011 12:00am EDT") = 2011-07-01 00:00:00 -0400 EDT
Parse("01/01/2011 12:00am PST") = 2011-01-01 00:00:00 +0000 PST
Parse("07/01/2011 12:00am PDT") = 2011-07-01 00:00:00 +0000 PDT
$ TZ=America/Los_Angeles go run x.go
time.Local = America/Los_Angeles
Parse("01/01/2011 12:00am EST") = 2011-01-01 00:00:00 +0000 EST
Parse("01/01/2011 12:00am EDT") = 2011-01-01 00:00:00 +0000 EDT
Parse("07/01/2011 12:00am EST") = 2011-07-01 00:00:00 +0000 EST
Parse("07/01/2011 12:00am EDT") = 2011-07-01 00:00:00 +0000 EDT
Parse("01/01/2011 12:00am PST") = 2011-01-01 00:00:00 -0800 PST
Parse("07/01/2011 12:00am PDT") = 2011-07-01 00:00:00 -0700 PDT
$

There may be a bug in handling daylight savings lookups in the
southern hemisphere, or there may be a bug in the Sydney time zone
information (less likely).  It doesn't seem to pick up EDT ever:

$ TZ=Australia/Sydney go run x.go
time.Local = Australia/Sydney
Parse("01/01/2011 12:00am EST") = 2011-01-01 00:00:00 +1100 EST
Parse("01/01/2011 12:00am EDT") = 2011-01-01 00:00:00 +0000 EDT
Parse("07/01/2011 12:00am EST") = 2011-07-01 00:00:00 +0000 EST
Parse("07/01/2011 12:00am EDT") = 2011-07-01 00:00:00 +0000 EDT
Parse("01/01/2011 12:00am PST") = 2011-01-01 00:00:00 +0000 PST
Parse("07/01/2011 12:00am PDT") = 2011-07-01 00:00:00 +0000 PDT
$

As for why QQQ is not a valid time zone, time.Parse requires as a
sanity check that the zone abbreviation be 3 or 4 letters (A-Z) long
and end in T.

Russ
@remyoudompheng
Copy link
Contributor

Comment 1:

Here EST stands for both summer and winter:
% zdump -v -c 2010,2012 Australia/Sydney
Australia/Sydney  Sat Apr  3 15:59:59 2010 UTC = Sun Apr  4 02:59:59 2010 EST isdst=1
gmtoff=39600
Australia/Sydney  Sat Apr  3 16:00:00 2010 UTC = Sun Apr  4 02:00:00 2010 EST isdst=0
gmtoff=36000
Australia/Sydney  Sat Oct  2 15:59:59 2010 UTC = Sun Oct  3 01:59:59 2010 EST isdst=0
gmtoff=36000
Australia/Sydney  Sat Oct  2 16:00:00 2010 UTC = Sun Oct  3 03:00:00 2010 EST isdst=1
gmtoff=39600
Australia/Sydney  Sat Apr  2 15:59:59 2011 UTC = Sun Apr  3 02:59:59 2011 EST isdst=1
gmtoff=39600
Australia/Sydney  Sat Apr  2 16:00:00 2011 UTC = Sun Apr  3 02:00:00 2011 EST isdst=0
gmtoff=36000
Australia/Sydney  Sat Oct  1 15:59:59 2011 UTC = Sun Oct  2 01:59:59 2011 EST isdst=0
gmtoff=36000
Australia/Sydney  Sat Oct  1 16:00:00 2011 UTC = Sun Oct  2 03:00:00 2011 EST isdst=1
gmtoff=39600

@rsc
Copy link
Contributor Author

rsc commented May 10, 2012

Comment 2:

Aha.  So we should probably handle that possibility in the code.  Thanks.

@robpike
Copy link
Contributor

robpike commented Aug 25, 2012

Comment 3:

See also issue #4001.

Labels changed: added go1.1.

@rsc
Copy link
Contributor Author

rsc commented Dec 10, 2012

Comment 4:

Labels changed: added size-m.

@rsc
Copy link
Contributor Author

rsc commented Feb 4, 2013

Comment 5:

This issue was closed by revision 1d9f67d.

Status changed to Fixed.

@rsc rsc added fixed labels Feb 4, 2013
@rsc rsc added this to the Go1.1 milestone Apr 14, 2015
@rsc rsc removed the go1.1 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants