Time zones are crucial to any application that deals with dates and times. Of course, this is especially true for apps that serve users across continents and locations. Time zones determine the offset from Coordinated Universal Time (UTC) for specific locations around the world. They play a vital role in ensuring accurate and reliable time handling.

Go provides the time package in its standard library for working with time and time zones. You can fetch and convert time zones at various locations using the time package.

The Time Package

The time package provides functionality for working with times and dates, measuring and displaying time, and manipulating dates using a Gregorian calendar without leap seconds.

The time package provides a Time struct type containing the location field you can use to set time zones.

You can import the time package with an import statement.

        import "time"

Here’s the time struct type and its fields. The fields are unexported, so they’re absent from the official documentation.

        package main

type Time struct {
    // wall is the wall time in the format returned by the runtime.nanotime()
    // function.
    wall uint64

    // ext is the monotonic clock reading in the format returned by
    // runtime.nanotime().
    ext int64

    // loc is a pointer to the Location struct associated with this time.
    loc *Location
}

type Location struct {
    // name is the time zone name, such as "UTC" or "PST".
    name string

    // zone contains information about the time zone abbreviation, offset,
    // and rule for a single time zone in the location.
    zone []zone

    // tx contains information about when the time zone abbreviation or
    // offset changes for a location.
    tx []zoneTrans

    // extend contains the name of a parent time zone if this location
    // extends from another one.
    extend string

    // cacheStart and cacheEnd are Unix timestamps that deine the range
    // for which the cacheZone field is valid.
    cacheStart int64
    cacheEnd int64

    // cacheZone points to the zone that is currently valid for the time
    // range defined by cacheStart and cacheEnd.
    cacheZone *zone
}

Many methods use the Time and Location structs, including the time zone methods.

Loading Time Zone Information

Loading Time Zone Information is one of the basic operations when working with time zones. The LoadLocation method provides functionality for loading time zone information from the IANA Time Zone Database. The LoadLocation method takes in the time zone's name and returns the location information and an error for handling. Once it has loaded the time zone information, it creates a time struct instance associated with the time zone.

        import (
    "fmt"
    "time"
)

func main() {
    // Load the time zone location for America/New_York
    loc, err := time.LoadLocation("America/New_York")

    if err != nil {
        fmt.Println("Error loading location:", err)
        return
    }

    // Get the current time at a location
    now := time.Now().In(loc)
    fmt.Println("Current time in New York:", now)
}

The In method of the Now function takes in a location and prints the time there:

result of printing the current time in NY

Additionally, you can use the FixedZone method to load the current time in a location if you know the location string and the offset of the time zone from UTC. First, you’ll need to load the current time in UTC, and then you’ll use the FixedZone method to load the location based on the string and offset before passing the location to the In the method of the time instance.

        import (
    "fmt"
    "time"
)

func main() {
    // Get the current time in UTC
    now := time.Now().UTC()

    // Set the time zone for Lagos
    lagos := now.In(time.FixedZone("WAT", 3600))

    // Print the current time in both locations
    fmt.Println("Current time in Lagos:", lagos)
}

The main function prints the current time in Lagos to the console.

Measuring Time Zone Duration

The time package provides the Zone method for retrieving the abbreviation and offset of the time zone associated with a time.Time value. The Zone method returns the string representing the abbreviation of the time zone (e.g. "EST" for "America/New_York") and an integer representing the number of seconds east of the UTC.

        import (
    "fmt"
    "time"
)

func main() {
    // Load the time zone location for America/New_York
    loc, err := time.LoadLocation("America/New_York")

    if err != nil {
        fmt.Println("Error loading location:", err)
        return
    }

    // Get the current time in UTC and the specified location
    t1 := time.Now()
    t2 := t1.In(loc)

    // Get the offset in seconds for each time zone
    //for the time zones
    _, offset1 := t1.Zone()
    _, offset2 := t2.Zone()

    // Calculate the duration of the time zone shift
    // between UTC and America/New_York
    duration := offset2 - offset1

    fmt.Printf("The time zone shift duration" +
      " between UTC and New York is: %d seconds", duration)
}

In the main function, the Zone method measures the duration of the time zone shift between two time zones (time.Time values). The t1 variable is the current time in UTC, and the t2 variable is the current time in the "America/New_York" time zone.

The function prints the duration variable (the difference in offset between the time zones) representing the time zone shift in seconds.

Evaluating Time Between Time Zones

You can evaluate time between time zones if you know the duration between the time zones. You can use the Add method of the In method of your time.Time struct instance to add a duration to the time in a time zone.

        import (
    "log"
    "time" // import the time package
)

func evaluateTime(t time.Time, duration time.Duration) time.Time {
    // load the location for Africa/Lagos
    location, err := time.LoadLocation("Africa/Lagos")

    if err != nil {
        log.Println("There was an error loading the location")
    }
    
    return t.In(location).Add(duration)
}

The evaluateTime function takes in a time.Time instance and a duration of type time.Duration, returning the time in the time zone. It loads the current time in "Africa/Lagos" and adds a duration to the time.

Manipulate Time and Date With the Time Package

The time package is very versatile for working with both times and dates. The time package provides functions like Unix() for converting time to Unix time, Sleep() for pausing goroutines, and Format() for formatting time values to string.