Force go process to use a specific time zone?

9,970 views
Skip to first unread message

Ryan

unread,
Jul 19, 2014, 3:17:06 PM7/19/14
to golan...@googlegroups.com
Hello,

Is there a way to force an entire go process to use a specific time zone? In java, you can pass -Duser.timezone=GMT to the JVM to force the entire process to use a specific time zone despite what the server/user account is configured as.

I have not found a way to do this and it is causing headaches in my local development environment which is configured to EDT/EST and my production servers are all UTC. 

The problem arises when external clients (e.g., mobile apps) pull time.Time variables over JSON and they are expecting UTC time strings and what they receive are EDT strings with offset values.

A similar headache arises when trying to parse the time strings that are returned by the JSON marshal function. I was hoping the format would be consistent, but it is any one of the following:
  • 2014-07-18T15:55:10.879-04:00 - This is what I receive when pulling data from my local env (i.e., EDT).
  • 2014-07-18T16:45:43-04:00 - This is also from the local env, but apparently, sometimes there aren't any milliseconds available.
  • 2014-07-18T22:45:41.825Z - This is pulled from UTC WITH milliseconds
  • 2014-07-18T22:31:03Z - This is also from UTC, but sometimes the milliseconds are not defined.
If I am able to configure the entire process to use UTC, I can remove two of the four date conversions.

If you cannot set the entire process to use a specific time zone, is there a way to override the way the JSON marshal function works so that I can add this custom conversion logic for time structs (or simply convert to UTC milliseconds from epoch)? In this case, storing the time as ms from epoch in the database is not a desirable option because it makes reading the raw data difficult.

Thanks!

-Ryan

Ian Lance Taylor

unread,
Jul 19, 2014, 4:40:17 PM7/19/14
to Ryan, golang-nuts
I assume you are using some Unix-like system.

First I'll note that Go stores a timezone with each time.Time value,
so if you are seeing a zone offset it must be coming from somewhere.
Go won't add a local time zone. It might help to show some code.

That said, when the local time zone does matter, for example when
calling time.Time.Local, you can set it by setting the environment
variable TZ. Just set TZ to the empty string to use UTC as the local
time zone.

Ian

Ryan

unread,
Jul 19, 2014, 5:05:35 PM7/19/14
to golan...@googlegroups.com, r...@deftlabs.com
Hi Ian,

Thanks for the response. When marshalling or converting to string, it seems like go does add a local time zone (code below). I do not see the Local field on the Time struct.

The only way I have found to create UTC times is to manually set this with time structs I create is by calling:

    location, _ := time.LoadLocation("UTC")
    time := time.Now().In(location)
    return &time

This approach only works when I create the time struct. When it comes from a 3rd party library (e.g., db driver), I have no control over setting this unless I manually add code to each struct after it has been retrieved, and this is highly undesirable.

Thanks,

-Ryan

Here is some test code:

package main

import (
    "fmt"
    "time"
    "encoding/json"
)           

type testJson struct { TheTime time.Time `json:"theTime"` }

func main() {
    now := time.Now()
    fmt.Println(now)

    test := &testJson{ TheTime: now }
    if raw, err := json.Marshal(test); err != nil { fmt.Println(err)
    } else { fmt.Println(string(raw)) }
}      

The output for this code is:

2014-07-19 16:55:38.328988572 -0400 EDT

{"theTime":"2014-07-19T16:55:38.328988572-04:00"}

Ryan

unread,
Jul 19, 2014, 5:12:11 PM7/19/14
to golan...@googlegroups.com, r...@deftlabs.com

Ahh... I misread your comment about setting the TZ environment variable. That does indeed work, but I would prefer to be able to set something on server startup to ensure everything is always in UTC.

Ryan

unread,
Jul 19, 2014, 5:24:34 PM7/19/14
to golan...@googlegroups.com, r...@deftlabs.com
If anyone is interested, the solution I added to my makefile is:

run: compile
    @rm -f /tmp/something.pid
    @export TZ="UTC"; bin/something -config conf/something_local_conf.json

This does not set the TZ in the shell so you can still enjoy looking at file timestamps in your local time zone.

Thanks Ian for the pointer.

Ian Lance Taylor

unread,
Jul 19, 2014, 5:31:11 PM7/19/14
to Ryan, golang-nuts
On Sat, Jul 19, 2014 at 2:05 PM, Ryan <r...@deftlabs.com> wrote:
>
> Here is some test code:
>
> package main
>
> import (
> "fmt"
> "time"
> "encoding/json"
> )
>
> type testJson struct { TheTime time.Time `json:"theTime"` }
>
> func main() {
> now := time.Now()
> fmt.Println(now)
>
> test := &testJson{ TheTime: now }
> if raw, err := json.Marshal(test); err != nil { fmt.Println(err)
> } else { fmt.Println(string(raw)) }
> }

I see, what's happening with this code is that time.Now returns the
time in the local timezone.

location, _ := time.LoadLocation("UTC")
time := time.Now().In(location)
return &time

You don't need LoadLocation, it's easier to write

time := time.Now().UTC()

Ian
Reply all
Reply to author
Forward
0 new messages