Subtract days, hours, seconds and more durations from time

Avatar of the author Willem Schots
12 Feb, 2024
~3 min.
RSS

There are many situations in which you might want to subtract a duration from an existing time value.

One example is when creating a “last x hours” filter. You will want to create a time value that is x hours before the current time.

To do such a subtraction we (somewhat confusingly) need to use the Add method on the time.Time type. This method allows you to add or subtract a time.Duration from a time.Time value if you supply a negative duration.

Note that we don't use the Sub method. This method doesn't do what we want: It returns the difference between time.Time values. It does not subtract a duration from a time value.

If we such a duration on a timeline, you can see how we “move backwards” to create a new time value:

Move backwards on timeline
Moving backward: t1 - 2 seconds = t2

Depending on your situation you will want to use a time.Duration value of a different resolution.

In Go, a time.Duration value has a resolution of 1 nanosecond. You can multiple it with the available “unit” constants to convert to seconds, hours and days. See the examples below.

Subtracting seconds

In the example below we create t2 by subtracting 2 seconds from t1.

main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	t1 := time.Date(2024, 2, 8, 13, 37, 11, 0, time.UTC)
	t2 := t1.Add(-2 * time.Second) // Note the negative two.

	fmt.Println(t1.String())
	fmt.Println(t2.String())
}

Subtracting hours

This works similarly for hours, if we want t2 to be 3 hours before t1, we can do the following:

main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	t1 := time.Date(2024, 2, 8, 13, 37, 11, 0, time.UTC)
	t2 := t1.Add(-3 * time.Hour)

	fmt.Println(t1.String())
	fmt.Println(t2.String())
}

Adding days

You won’t find a time.Day constant in the time package. Mainly because this is where “ambiguity sets in”. Due to timezones and daylight saving time, days will not always take exactly 24 hours. In such situations you might want to look at t.AddDate.

However, if you are working in UTC (where every day does have 24 hours), you can use the following code.

main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	t1 := time.Date(2024, 2, 8, 13, 37, 11, 0, time.UTC)
	t2 := t1.Add(-24*time.Hour)

	fmt.Println(t1.String())
	fmt.Println(t2.String())
}

Please note that this is still not entirely correct due to leap seconds. But the Go time package does not support those to start with, so I’m skipping them here as well.

Positive duration

By providing a positive duration, you can add durations to time.Time values.

Location

The time.Time values created by the Add method will always be in the same location as the original time value.

Monotonic clock

If the original time.Time value is created via time.Now(), it will often contain a monotonic element. Calling Add on such a value will create a new value that also contain a monotonic element. With the monotonic element adjusted for the duration provided to Add.

This is the only way to create new time.Time values that have monotonic elements without calling time.Now().

🎓

Subscribe to my Newsletter and Keep Learning.

Gain access to more content and get notified of the latest articles:

I send emails every 1-2 weeks and will keep your data safe. You can unsubscribe at any time.

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 Mastodon, Twitter/X or LinkedIn.

Thanks for reading!