Change timezone without changing time

Avatar of the author Willem Schots
23 Jan, 2024
~2 min.
RSS

When working with time and scheduling there are situations where you want to change the timezone of a time.Time value, but don’t want to adjust the clock value.

t.UTC(), t.Local and t.In(...) are the typical methods used to create time.Time values in new locations. However, these methods will always adjust the clock value on the new value. This is by design to ensure that the new value represents the same time instant as the original value.

For example, suppose you have a time of 13:37 in the UTC timezone. If you convert it to the UTC+1 timezone it will now read 14:37.

But what if you want to convert it to the UTC+1 timezone while continuing to read 13:37?

Do note that it’s very likely that the converted time will no longer represent the same time instant.

Use time.Date constructor

We can’t use any of the timezone methods, but we can use the time.Date constructor to create a copy in the desired timezone.

See the InSameClock function below.

main.go
package main

import (
	"fmt"
	"time"
)

// InSameClock returns a copy of t in the provided location. The copy
// will have the same clock reading as t and will represent a different
// time instant depending on the provided location.
// If t contains a monotonic clock reading this will also be stripped.
func InSameClock(t time.Time, loc *time.Location) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), loc)
}

func main() {
	// t1 is time in "UTC+3" timezone
	eastOfUTC := time.FixedZone("UTC+3", 3*60*60)
	t1 := time.Date(2024, 01, 22, 13, 37, 0, 0, eastOfUTC)

	// t2 is a time with the same clock reading in the UTC timezone.
	t2 := InSameClock(t1, time.UTC)

	fmt.Println(t1.String())
	fmt.Println(t2.String())
	fmt.Printf("same time instant: %v\n", t1.Equal(t2))
}

In the example above, initially have a time value t1 in the UTC+3 timezone.

We then use our InSameClock function to create t2, a time value with the exact same clock reading as t1 but in the UTC timezone.

t1 and t2 represent different time instants, you can run the example to verify this.

Make privacy claims you can back up

Join 800+ subscribers.
One email every few weeks.

I share what I learn building privacy-friendly systems. From confidential computing to Verbond and the occasional Go tip or trick. You can unsubscribe at any time.

A photo of Willem

Written by Willem Schots

I help teams prove what happens to their users' data, and I'm building Verbond, which shows where data can go before third-party code runs.

This site started as a place to learn Go. Most posts are now about privacy-friendly and verifiable systems, with the occasional Go post in between.

Want to talk about your system? Book a 30-minute call, or follow me on Bluesky and LinkedIn.