Re: [go-nuts] time and timezone conversion

3,438 views
Skip to first unread message

Rob Pike

unread,
Sep 17, 2012, 1:03:44 PM9/17/12
to Matthew Zimmerman, golan...@googlegroups.com

peterGo

unread,
Sep 17, 2012, 1:06:03 PM9/17/12
to golan...@googlegroups.com
Matthew.

The Go playground runs in a sandbox which doesn't have access to a real clock.

Running on a real computer in US Eastern Standard Time:

2012/09/17 12:38:42 09/17/2012 10:06am EDT - 1347890760 - Local
2012/09/17 12:38:42 09/17/2012 2:06pm UTC - 1347890760 - UTC
2012/09/17 12:38:42 09/17/2012 10:06am EDT - 1347890760 - Local

Peter

On Monday, September 17, 2012 10:23:53 AM UTC-4, Matthew Zimmerman wrote:
I'm sure I'm misunderstanding something, but shouldn't date.Format(timeformat) actually change when the time object has a different Location?  It looks as though EDT = UTC.

timeformat := "01/02/2006 3:04pm MST"
date, _ := time.Parse(timeformat, "09/17/2012 10:06am EDT")
log.Printf("%v - %v - %v", date.Format(timeformat), date.Unix(), date.Location())
edt := date.Location()
date = date.UTC()
log.Printf("%v - %v - %v", date.Format(timeformat), date.Unix(), date.Location())
date = date.In(edt)
log.Printf("%v - %v - %v", date.Format(timeformat), date.Unix(), date.Location())

2009/11/10 23:00:00 09/17/2012 10:06am EDT - 1347876360 - EDT
2009/11/10 23:00:00 09/17/2012 10:06am UTC - 1347876360 - UTC
2009/11/10 23:00:00 09/17/2012 10:06am EDT - 1347876360 - EDT

Kevin Gillette

unread,
Sep 17, 2012, 1:06:49 PM9/17/12
to golan...@googlegroups.com

A few things:

it's good to check the parse error -- even if you did check it, but omitted it from the playground snippet for brevity, someone will always mention it anyway.

The Unix* methods functions either import from UTC, or output in terms of UTC, so no matter what, date.Unix() for all these dates would be identical.

time.Time is a fmt.Stringer, so it's handy to just print it 'as is' for debugging, since that outputs all the possible information about the time. Outputting with the same format as the input while debugging, in general, is a good way to mask errors/bugs.

In this case, the output of all of those dates includes +0000, which means that, at least the playground deployment, doesn't recognize EDT, and is treating it as if it's UTC. In my opinion, this might be worth Parse returning an error in addition to the "best guess" date, which in this case is UTC.

peterGo

unread,
Sep 17, 2012, 1:13:58 PM9/17/12
to golang-nuts
s/US Eastern Standard Time/US Eastern Daylight Time/

Rob Pike

unread,
Sep 17, 2012, 1:15:42 PM9/17/12
to Kevin Gillette, golan...@googlegroups.com
> In my opinion, this might be worth Parse returning an error in addition to the "best guess" date, which in this case is UTC.


That's the issue I cited.

-rob

Matthew Zimmerman

unread,
Sep 17, 2012, 4:40:15 PM9/17/12
to golan...@googlegroups.com, Kevin Gillette
Rob, thanks that describes the issue quite well really and I've starred it.  For now though, this works everywhere that there's a real clock defined.  So what should I do in appengine if my (potential) userbase is worldwide?  I don't really want to manually keep track of the different timezone's and do calculations cause I'm going to mess it up for sure.

The appengine environment does recognize "America/New_York" however, but I can't use that in the time format for ParseTime, http://golang.org/src/pkg/time/format.go

So how about using it to find the offset, then manually using the offset to find the right UTC time, then convert the UTC time back to America/New_York?  Seems crazy to have to do this - is there another better way?  (Error checking not done for brevity)
timeString = "09/17/2012 4:38pm"
tz := "America/New_York"  - (as taken from user input or profile)
location , _ := time.LoadLocation(tz)
_ , offset := time.Now().In(location).Zone()
date , _ := time.Parse("01/02/2006 3:04pm",timeString)
date = time.Unix(date.Unix() - int64(offset),0).In(location)
Essentially, that parses the time with a user defined timezone and gets the time object in the right timezone.  Is there a better way?  I'm new to timezone management.

Thanks,
Matt

Kyle Lemons

unread,
Sep 17, 2012, 5:00:03 PM9/17/12
to Matthew Zimmerman, golan...@googlegroups.com, Kevin Gillette
You could use a time zone format that is lossless (stores offset instead of name) or store everything in UTC and convert it into the user's timezone on display

--
 
 

Matthew Zimmerman

unread,
Sep 17, 2012, 5:24:53 PM9/17/12
to golan...@googlegroups.com
Well, for me, I have to process the time to create schedules on the server side too (weekly, daily, etc). Wouldn't the offset change depending on the time of year? (DST)

Kyle Lemons

unread,
Sep 17, 2012, 8:58:07 PM9/17/12
to Matthew Zimmerman, golan...@googlegroups.com
On Mon, Sep 17, 2012 at 2:24 PM, Matthew Zimmerman <mzimm...@gmail.com> wrote:
Well, for me, I have to process the time to create schedules on the server side too (weekly, daily, etc).  Wouldn't the offset change depending on the time of year? (DST)

Sure, but it would still represent the correct time.  You can freely operate on timezones with different stored zones in Go.  The simpler way is to store it all in UTC though, and only display it in the user's zone. 

Uriel

unread,
Sep 17, 2012, 9:18:11 PM9/17/12
to Matthew Zimmerman, golan...@googlegroups.com
On Mon, Sep 17, 2012 at 11:24 PM, Matthew Zimmerman
<mzimm...@gmail.com> wrote:
> Well, for me, I have to process the time to create schedules on the server side too (weekly, daily, etc). Wouldn't the offset change depending on the time of year? (DST)

Yes, and this is one of the many reasons why having a location be part
of Time was a mistake, it just causes most confusion when it should be
purely a presentation matter.

Just ignore it an always use UTC, and then set the location when you
are going to print the date.

Uriel

Uriel

unread,
Sep 17, 2012, 9:17:13 PM9/17/12
to Kyle Lemons, Matthew Zimmerman, golan...@googlegroups.com, Kevin Gillette
On Mon, Sep 17, 2012 at 11:00 PM, Kyle Lemons <kev...@google.com> wrote:
> You could use a time zone format that is lossless (stores offset instead of
> name)

Don't do this.

> or store everything in UTC and convert it into the user's timezone on display

Always do this.

Uriel

Matthew Zimmerman

unread,
Sep 17, 2012, 10:20:05 PM9/17/12
to golan...@googlegroups.com, Matthew Zimmerman
Uriel, I'm confused by your response.  You seem to acknowledge the problem (of not computing within the Location) yet recommend processing everything in UTC.

I agree everything should be stored in UTC (appengine datastore enforces that) and converted for presentation to the user - I'm doing that.  But what I need to do is schedule a weekly meeting for instance, at the same (relative) time of day each week.  I cannot do that (bugfree) by managing time in UTC.

If I'm processing in UTC, how do I generate the daily meeting that's in EST?  I think the answer is to process with the Location set - e.g., .In(est).AddDate(0,0,1)  AddDate() normalizes it within timezones for me.  If I don't use the localization, 86400 seconds is always the Unix() difference between days.  When the date change crosses Nov 2nd becomes Nov 3rd, 90000 is now the Unix() difference and I go from EDT to EST.

I wish the playground had the TZ data to load so you could see it easier, but here's the "bug" I'd hit if I don't process in a Location.

Kyle Lemons

unread,
Sep 18, 2012, 2:00:03 AM9/18/12
to Matthew Zimmerman, golan...@googlegroups.com
Use AddDate.

http://play.golang.org/p/W2rxYSysl9 (fixed zone is because the playground doesn't have zoneinfo)

--
 
 

Reply all
Reply to author
Forward
0 new messages