This tutorial will teach you how to work with Time in Go (Golang) - including how to parse and format date-time strings, add and subtract time durations, and get the current system time.

banner

The main library that we’ll use when working with times and dates is the time standard library.

Getting the Current System Time

Let’s begin with an example of creating a new Time instance from the current system time:

package main

import (
	"fmt"
	"time"
)

func main() {
	// `now` is an instance of time.Time
	now := time.Now()
	fmt.Println(now.String())
}

Output (try it yourself):

2009-11-10 23:00:00 +0000 UTC m=+0.000000001

After importing the time standard library, we can call the time.Now() function - which will return the current system time.

Calling the String() method returns the time as a formatted string.

We can also return the time string in a custom format.

Formatting Time to a String

We can use the Format method of any Time instance to return a string in our custom format.

For example, if we run:

now := time.Now()
// the time and date in this string is intentional, as we will discuss soon
fmt.Println(now.Format("2 Jan 06 03:04PM"))

We will get the output (try it yourself):

10 Nov 09 11:00PM

The date and time in the argument of the Format method must be the same as the Layout constant, which is defined as:

01/02 03:04:05PM '06 -0700

Note, that 01/02 refers to the American convention of MM/DD, which would be the 2nd January.
“06” refers to the year 2006, and “-0700” refers to the timezone

The time library uses this as a reference to map different components of a string to the time that it’s referring to.

inputs are mapped to the reference string to generate the output

We can also use some of the formats defined in the constants to conveniently format our string into recognized standard formats.

For example, we can use the time.UnixDate layout format to return a unix-formatted date string:

now := time.Now()
fmt.Println(now.Format(time.UnixDate))

Output (Try it yourself):

Tue Nov 10 23:00:00 UTC 2009

Parsing Time Strings

The time.Parse function takes a string as an input and returns a time instance.

This string can be in a number of formats, depending on your code. The time library uses the same layout mechanism that we saw in the previous section to convert a string into a Time instance.

Let’s see an example where we parse a custom-formatted string using the Parse function:

//                           layout                input time
myTime, err := time.Parse("2 Jan 06 03:04PM", "10 Nov 10 11:00PM")
// parsing the time may return an error if the layout format doesn't
// match the input time
if err != nil {
	panic(err)
}
fmt.Println(myTime)

This is basically the inverse of the Format method.

parse uses the layout string to convert an input string to a time instance

Duration - Adding and Subtracting Time

Go uses the Duration type to show the difference between two instants of time.

myTime, err := time.Parse("2 Jan 06 03:04PM", "10 Nov 10 11:00PM")
if err != nil {
	panic(err)
}
now := time.Now()
difference := myTime.Sub(now)
fmt.Println(difference)

Output (try it yourself):

8760h0m0s

Here, the difference variable is of type Duration, and as the name suggests, it represents some elapsed duration of time.

Note, that if the first time instance is before the second, the duration will be a negative value

We can convert this duration into different units like hours or milliseconds:

fmt.Println(difference.Hours())
fmt.Println(difference.Milliseconds())

This will give us the integer values of the duration:

8760
31536000000

Note that the largest representable duration is approximately 290 years, so if you need to represent a duration larger than that, you’d be better off using your own type

We can also add a duration to an existing time using the Add method:

now := time.Now()
later := now.Add(3 * time.Hour)
fmt.Println("now: ", now, "\nlater: ", later)

Output (try it yourself):

now:  2009-11-10 23:00:00 +0000 UTC m=+0.000000001 
later:  2009-11-11 02:00:00 +0000 UTC m=+10800.000000001

Since duration is internally represented as a number, we can multiply duration constants like Minute, Second and Millisecond with integers.

3 * time.Hour // 3 hours
16 * time.Minute // 16 minutes
120 * time.Second // 120 seconds

This is useful for code readability since you know the unit of time just be seeing the constant used.

Time Comparison

If we just want to know if an instant of time is greater than or lesser than another one, we can use the Before and After methods, which return a boolean value:

myTime, err := time.Parse("2 Jan 06 03:04PM", "10 Nov 10 11:00PM")
if err != nil {
	panic(err)
}
now := time.Now()
fmt.Println(now.Before(myTime))
fmt.Println(now.After(myTime))

Output (try it yourself):

true
false

This is more concise and readable for pure comparison, rather than using Sub and checking for a positive or negative duration.

Getting Unix/Epoch Time

The Unix or Epoch time is the total number of seconds elapsed since January 1, 1970 UTC. It is a convenient way to represent a timezone-independent instant of time since it is returned as an integer value, which can be stored efficiently in databases and storage systems.

We can use the Unix and UnixMilli methods to get the epoch time from a Time instance:

now := time.Now()
fmt.Println(now.Unix())
fmt.Println(now.UnixMilli())

Output (try it yourself):

1257894000
1257894000000

Conclusion and Further Reading

This post has covered most of the concepts you need to know to get started working with times and dates in Go.

Some key points to remember:

  1. Most applications take user input in the form of strings. We can use the Format and Parse functions to convert between arbitrary strings and native Time representations.
  2. To perform operations on time in Go, it’s always better to use the built in Add and Subtract methods. Similarly, use Before and After for time comparison.
  3. For data storage, converting to an integer in the form of epoch seconds or milliseconds is more optimal. This will also allow you to perform arithmetic operations on your time if you need to.

If you want a comprehensive list of all the functions and methods available, check out the library documentation page.