Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting timezone globally in golang

Tags:

time

go

I'm trying to modify golang timezone for my application

I have took a look at time package, initializing timezone happens in

time/zoneinfo_unix.go @ initLocal

The function simply tries to read environment variable TZ and if it's valid it loads it

and if it's not it falls back /etc/localtime and if it's not valid it falls back to UTC


what i have tried so far

1- works fine -But i don't want to use either of those approaches - :

  • in my docker file i pass an ENV to the container, TZ = Africa/Cairo
  • getting into the container bash, running $ export TZ = Africa/Cairo

2- Didn't work

  • in my app initialization (the app initialization is in a separate package that is being imported in the main), i use os.SetEnv("TZ", "Africa/Cairo")

When i simplify the main and use os.SetEnv("TZ", "Africa/Cairo") without importing any other packages other than "os - time" it works as expected


Any ideas about how to make the second approache work ?

Docker image: golang:1.11.2

like image 801
Abd El-Rahman Rafaat Avatar asked Jan 25 '19 10:01

Abd El-Rahman Rafaat


1 Answers

You can achieve what you want from inside your app using os.Setenv("TZ", "Africa/Cairo"), what matters is that you must call this before any other package uses anything from the time package.

How to ensure that? Create a package that does nothing else except sets the timezone (later you may add other things to it, but for our example that's enough).

Like this:

package tzinit

import (
    "os"
)

func init() {
    os.Setenv("TZ", "Africa/Cairo")
}

Import this tzinit package first thing in your main package like this:

package main

import _ "path/to/tzinit"

// Your other, "regular" imports:
import (
    "fmt"
    "os"
    "time"
    ...
)

And so setting the TZ env var will happen before any other package could access the time package.

Note that I used a separate import declaration just for tzinit, and the reason for this is because many code editors / IDEs will rearrange your imports alphabetically, this will ensure that importing tzinit will remain the first import.

A word of warning.

The Spec: Package initialization states the requirements and rules of initializing packages, and the order in which imports are processed is not specified (only thing guaranteed is that all referenced package will be initialized recursively before it can be used). This means that although current compilers process them as listed, you cannot rely on this for 100%. There's also the issue of having multiple source files even for the main package, supplying them in different order to the compiler may also change the initialization order. The spec has this as a "recommendation":

To ensure reproducible initialization behavior, build systems are encouraged to present multiple files belonging to the same package in lexical file name order to a compiler.

So to be on the safe side, best would be to set the TZ environment variable before the Go app is launched.

like image 154
icza Avatar answered Sep 18 '22 20:09

icza