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: parsing reference times seems to ignore three-letter timezones #9617

Closed
jovlinger opened this issue Jan 16, 2015 · 9 comments
Closed

Comments

@jovlinger
Copy link

According to the docs for package time, the RFC822(Z) format of the reference time is

    RFC822      = "02 Jan 06 15:04 MST"
    RFC822Z     = "02 Jan 06 15:04 -0700"

But when I try to parse these times, the RFC822 one gets parsed as GMT rather than MST:

rfc822 in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136214240
rfc822z in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 -0700 1136239440
rfc822 == rfc822z: false

furthermore, once parsed, the result of Format into RFC850 doesn't conform to its own definition and can't be parsed into RFC850.

http://play.golang.org/p/8q0OkLkNQ-

(in case that link expires:)

package main

import (
"fmt"
"time"
)

func prt(name string, t time.Time) {
fmt.Println(name, "in RFC850 and unix seconds is", t.Format(time.RFC850), t.Unix())
}

func main() {
rfc822, err1 := time.Parse(time.RFC822, time.RFC822)
rfc822z, err1z := time.Parse(time.RFC822Z, time.RFC822Z)

if err1 != nil || err1z != nil {
    fmt.Println(err1)
    fmt.Println(err1z)
    return
}
prt("rfc822", rfc822)
prt("rfc822z", rfc822z)
fmt.Println("rfc822 == rfc822z:", rfc822.Equal(rfc822z))

rfc850, err850 := time.Parse(time.RFC850, rfc822z.Format(time.RFC850))
if err850 != nil {
    fmt.Println(err850)
    return
}
prt("rfc850", rfc850)

}

@ianlancetaylor ianlancetaylor changed the title parsing reference times from package time seem to ignore three-letter timezones time: parsing reference times seems to ignore three-letter timezones Jan 16, 2015
@mirtchovski
Copy link
Contributor

go tip, ubuntu 12.02:

$ TZ=America/Edmonton go run t.go # MST
rfc822 in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136239440
rfc822z in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136239440 
rfc822 == rfc822z: true
rfc850 in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136239440

$ TZ=America/New_York go run t.go
rfc822 in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136214240
rfc822z in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 -0700 1136239440
rfc822 == rfc822z: false parsing time "Monday, 02-Jan-06 15:04:00 -0700" as "Monday, 02-Jan-06
15:04:05 MST": cannot parse "-0700" as "MST"

$ TZ=America/Los_Angeles go run t.go
rfc822 in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 MST 1136214240
rfc822z in RFC850 and unix seconds is Monday, 02-Jan-06 15:04:00 -0700 1136239440
rfc822 == rfc822z: false parsing time "Monday, 02-Jan-06 15:04:00 -0700" as "Monday, 02-Jan-06
15:04:05 MST": cannot parse "-0700" as "MST"
$

@bmea
Copy link

bmea commented Jan 18, 2015

A given time zone abbreviation can mean different things to different people. Each interpretation is just as valid as any other.

For example, MST can mean any one of:

  • Mountain Standard Time (UTC-0700);
  • Myanmar Standard Time (UTC+0630); or
  • Malaysia Standard Time (UTC+0800).

If an abbreviation has meaning in a particular location, that's enough to resolve ambiguity. Hence http://golang.org/pkg/time/#Parse:

When parsing a time with a zone abbreviation like MST, if the zone abbreviation has a defined offset in the current location, then that offset is used.

In Europe (for example), MST doesn't have any particular meaning. Thus http://golang.org/pkg/time/#Parse:

If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset.

@minux
Copy link
Member

minux commented Jan 18, 2015

it's working as intended.

@blalor
Copy link

blalor commented Feb 23, 2015

It's broken and misleading. If Go can't parse the timezone as provided in its own example format, it should throw an error. This points out the inherent limitations of the example-driven format. I think this problem wouldn't exist if Go supported token-based time parsing.

This example shows that even though time.Parse sets the location to PST, the offset is broken:

package main

import "fmt"
import "time"

func main() {
    str := "Mon, 2 Jan 2006 15:04:05 MST"
    // Mon Jan 2 15:04:05 MST 2006
    t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 MST", str)
    fmt.Printf("t: %v, err: %v", t, err)
}

The output is

t: 2006-01-02 15:04:05 +0000 MST, err: <nil>

So time.Parse can't even get its example timestamp correct. This means there's a whole class of timestamps that Go can't parse (rss pubDates for example), despite defining those very formats as constants in the time package!

@rogpeppe
Copy link
Contributor

Saying the time package can't parse those formats is overstating the
case a little.

There is no way for the time package to resolve the ambiguity itself, but
all the information is still available, and you can resolve the ambiguity yourself.
For example: http://play.golang.org/p/w4E9sOxCiY

If you don't need to keep the time zone offset around, you could just
add the offset yourself.

@bmea
Copy link

bmea commented Feb 23, 2015

// Mon Jan 2 15:04:05 MST 2006

Which MST is that?

t: 2006-01-02 15:04:05 +0000 MST, err:
So time.Parse can't even get its example timestamp correct.

Working as intended.
http://golang.org/pkg/time/#ParseInLocation
ParseInLocation is like Parse but differs in two important ways. First, in the absence of time zone information, Parse interprets a time as UTC; ParseInLocation interprets the time as in the given location.

@blalor
Copy link

blalor commented Feb 23, 2015

If I knew the location, I wouldn’t be worried about parsing it out of the string…

@rogpeppe
Copy link
Contributor

So is my suggested solution not adequate for doing that?

@rsc
Copy link
Contributor

rsc commented Apr 10, 2015

This is all very clearly documented.

time.Parse makes an exception for the time zone abbreviations in the location time.Local. It does not attempt to resolve other abbreviation, since there are ambiguities. (Which MST? The one that is closest to your own local time?) In this case if your time.Local is MST/MDT then time.Parse will understand those. But otherwise not.

If you have a list of what you think the abbreviations should mean, you can give them those meanings with a program like Rog posted.

@rsc rsc closed this as completed Apr 10, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
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

8 participants