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.

Get my free newsletter every second week

Used by 500+ developers to boost their Go skills.

"I'll share tips, interesting links and new content. You'll also get a brief guide to time for developers for free."

Avatar of the author
Willem Schots

Hello! I'm the Willem behind willem.dev

I created this website to help new Go developers, I hope it brings you some value! :)

You can follow me on Bluesky, Twitter/X or LinkedIn.

Thanks for reading!