Getting started with Golang time
Time is what we all need, in real life or in our application / software. Generally, time in real life does not need any introduction, however, we have two types of time provided by operating systems, the "wall clock" and "monotonic clock".
The “Wall clock” type of time is the normal world time that is synchronized to other clocks globally and we have the “Monotonic Clock” which is not. If you want to check time or tell time, the wall clock is what you need and if you want measure time like doing subtractions, then the Monotonic clock is what you need. For the Wall clock, the calendrical calculations always assume a Gregorian calendar, with no leap seconds.
The Go time package have some functions and types that will help you solve time problems at any scale. We will look at some important Golang Time package functions and types with some examples to make you understand how to use Golang Time.
Important Must Know Golang time Functions
Golang time packages main functions, these functions take a duration of “d
” time.Duration
as the only argument, we will talk about Duration on the go time types section, for now just know “time.Duration
” is of type Int64
.
We have some main functions, the time.After
and time.Tick
function returns a channel of type Time, the time.Sleep
will return function nothing, whereas there are other functions like the time.Now()
and time.Date()
etc. let’s look at these functions with some examples.
Golang Time After Function [ time.After ]
func After(d Duration) <-chan Time
“time.After
” waits for the duration of time.Duration
d
passed into the function then sends the current time on the returned channel.
package main
import (
"fmt"
"time"
)
var c chan int
func handle(int) {
}
func main() {
select {
case m := <-c:
handle(m)
case <-time.After(10 * time.Second):
fmt.Println("timed out")
}
}
Output:
$ go run main.go
timed out
In the above code, we created a handle function and used the Golang select
syntax to spine up two goroutines, one with the handle function and the second is using the time.After
function with a duration of ten seconds. Therefore, the output of this code is “timed out” because it has waited for 10 seconds.
Golang Time Tick Function [ time.Tick ]
func Tick(d Duration) <-chan Time
Tick will return a channel that sends time to the receiver after waiting for the specified duration. The Golang time.Tick
function does not have a way to shut down so the Ticker cannot be recovered by the garbage collector; it "leaks".
Example code: -
package main
import (
"fmt"
"time"
)
func statusUpdate() string { return "" }
func main() {
c := time.Tick(5 * time.Second)
for next := range c {
fmt.Printf("%v %s\n", next, statusUpdate())
}
}
Output:
$ go run main.go
2022-09-20 12:20:05.820449 +0800 CST m=+5.008349401
2022-09-20 12:20:10.8183667 +0800 CST m=+10.006267101
exit status
Note that I stopped the process manually with CTRL+C , because in the above code, we started a Tick with 5 seconds duration, iterating over this channel will continue to print out the time every 5 seconds until it is manually stopped, so you will mostly use the time.Tick
when you don’t care about shutdown and leaks.
Golang Time Sleep Function [ time.Tick ]
func Sleep(d Duration)
This function does not have any return value but will pause the current goroutine for the specified duration “d
”. A negative or zero duration causes Sleep to return instantly, it will return nothing.
Example code: -
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Waiting for 5 seconds before closing main()")
time.Sleep(5 * time.Second)
fmt.Println("Closing main() after waiting for 5 seconds")
}
Output:
$ go run main.go
Waiting for 5 seconds before closing main()
Closing main() after waiting for 5 seconds
In the above code, we waited for five seconds after running the main app before closing it.
Golang Time Date Function [ time.Date() ]
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
The time.Date
function is used to create a time that will match the inputted arguments using a matching pattern which can found on the official go pkg website as: -
yyyy-mm-dd hh:mm:ss + nsec nanoseconds
The month, day, hour, min, sec, and nsec values may be outside their usual ranges and will be normalized during the conversion. For example, October 32 converts to November 1.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go launched at %s\n", t.Local())
}
Output: -
Go launched at 2009-11-11 07:00:00 +0800 CST
Golang Time Now Function [ time.Now() ]
func Now() Time
This will return the current time.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(t)
}
Output: -
$ go run main.go
2022-09-20 13:40:08.4551392 +0800 CST m=+0.003835401
Assigned t
to time.Now()
to get the current time then printed it out to console.
Golang Time Duration Type [ time.Duration ]
type Duration int64
Duration is a nanoseconds counter that is used to represent the time between two instants, its of type int64 as said in the beginning when we started with Golang Time package functions,
Example: -
package main
import (
"fmt"
"time"
)
func expensiveCall() {
time.Sleep(5 * time.Second)
}
func main() {
t0 := time.Now()
expensiveCall()
t1 := time.Now()
fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
}
Output:
$ go run main.go
The call took 5.0009154s to run.
In the above code, we started with a function expensiveCall
which has time.Sleep
function to make it sleep for 5 seconds, that is our duration d of the time.Sleep(5seconds)
, in the main function, I used the t0 := time.Now()
to start the application so as to get the current time, then called our function “expensiveCall()
” which is said to wait for 5 seconds based on the duration we passed, the next line also records the current time into t1 := time.Now()
, then we print the time difference between t0 and t1
with t1.Sub()
which will subtract t0 from t1 and return a duration.
Golang Time Format() - Formatting time output
In this section, you are going to learn how to parse time and date strings in Go, how to convert between different time and date formats, and how to print times and dates in the format you desire
There are three main standards against which we can parse the time:
- RFC3339
- UnixDate
- ANSIC
Here we have a simple code which prints current tame based on all the 3 standards
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println("RFC3339:", t)
fmt.Println("UnixDate", t)
fmt.Println("ANSIC", t)
}
Output:
$ go run main.go
RFC3339: 2022-09-20 23:35:09.892979205 +0530 IST m=+0.000045328
UnixDate 2022-09-20 23:35:09.892979205 +0530 IST m=+0.000045328
ANSIC 2022-09-20 23:35:09.892979205 +0530 IST m=+0.000045328
So the output format is same for all the 3 standards.
Now coming back to time formatting, we can utilise format()
function by passing the format in which we want to print the time output. Here we have created a small function which will take the input of date format and then will convert the current date and time into that format:
package main
import (
"fmt"
"time"
)
func displayDate() {
fmt.Println(time.Now().Date())
}
func main() {
displayDate()
}
Output:
$ go run main.go
2022 September 20
This is a very simple output where we are just formatting time.Now().Date()
output. Let's do some more examples:
package main
import (
"fmt"
"time"
)
func displayDate(format string) {
fmt.Println(time.Now().Format(format))
}
func main() {
// The output time will vary for you
// but you can check the time format in which we get the output
displayDate("2006-01-02 15:04:05") // The date and time are displayed.
displayDate("15:04:05, 2006-Jan-02 Mon") // The day of the week (Thu) and month (Jul) are displayed.
displayDate("15:04:05, 2006-Jan-02 Monday") // The day of the week is displayed in full.
displayDate("15:04:05, 2006-January-02 MST Mon") // The month is displayed in full; the time zone is also displayed (+08).
displayDate("3:4:05, 2006-1-02 MST Mon") // The time zone (+8) is displayed; a single digit is used for the hour.
displayDate("3:4:05 pm, 2006-1-02 MST Mon") // Morning is displayed as am.
displayDate("3:4:05 PM, 2006-1-02 MST Mon") // Morning is displayed as AM.
}
Output:
$ go run main.go
2022-09-20 23:46:53
23:46:53, 2022-Sep-20 Tue
23:46:53, 2022-Sep-20 Tuesday
23:46:53, 2022-September-20 IST Tue
11:46:53, 2022-9-20 IST Tue
11:46:53 pm, 2022-9-20 IST Tue
11:46:53 PM, 2022-9-20 IST Tue
Golang Time LoadLocation [ time.LoadLocation ]
You can utilize the LoadLocation()
function of the time package to convert your local time to the local time of another time zone. Our reference time zone will be the Asia/Kolkata
time zone. The Format()
function is used to tell Go how we would like to see our output formatted. The In()
function is a reference to a specific time zone we want our formatting to be present in.
package main
import (
"fmt"
"time"
)
func main() {
// Generate Epoch Time
fmt.Println("Epoch time:", time.Now().Unix())
// Print current time
t := time.Now()
// Print in RFC3339 format
fmt.Println(t, t.Format(time.RFC3339))
// print in weekday day month and year format
fmt.Println(t.Weekday(), t.Day(), t.Month(), t.Year())
// Sleep for 1 second
time.Sleep(time.Second)
// Print current time
t1 := time.Now()
// Print time different
fmt.Println("Time difference:", t1.Sub(t))
// Print time in below format
formatT := t.Format("01 January 2006")
fmt.Println(formatT)
// print time from certain location
loc, _ := time.LoadLocation("Asia/Kolkata")
indTime := t.In(loc)
fmt.Println("Kolkata:", indTime)
}
Output:
$ go run main.go Epoch time: 1663698144 2022-09-20 23:52:24.562269188 +0530 IST m=+0.000082417 2022-09-20T23:52:24+05:30 Tuesday 20 September 2022 Time difference: 1.000356892s 09 September 2022 Kolkata: 2022-09-20 23:52:24.562269188 +0530 IST
Explanation: The time.Now().Unix()
function returns the UNIX epoch time, which is the number of seconds that have elapsed since 00:00:00 UTC, 1 January, 1970
. The Format()
function allows you to convert a time variable to another format; in this case, the RFC3339
format.
You will see the time.Sleep()
function many times in this book as a naive way of emulating the delay from the execution of a true function. The time.Second
constant allows you to use a one-second duration in Go. If you want to define a duration of 10 seconds, you will need to multiply time.Second
by 10
. Other similar constants include time.Nanosecond
, time.Microsecond
, time.Millisecond
, time.Minute
, and time.Hour
. So, the smallest amount of time that can be defined with the time package is the nanosecond. Lastly, the time.Sub()
function allows you to find the time difference between two times.
Next we use time.LoadLocation
along with In()
function to get the time from the respective timezone. Next we print the time from Kolkata timezone on the console.
Manipulating Time Values
The time package defines methods for working with Time values, as described in below table. Some of these methods rely on the Duration
type:
Name | Description |
---|---|
Add(duration) | This method adds the specified Duration to the Time and returns the result. |
Sub(time) | This method returns a Duration that expresses the difference between the Time on which the method has been called and the Time provided as the argument. |
AddDate(y, m, d) | This method adds the specified number of years, months, and days to the Time and returns the result. |
After(time) | This method returns true if the Time on which the method has been called occurs after the Time provided as the argument. |
Before(time) | This method returns true if the Time on which the method has been called occurs before the Time provided as the argument. |
Equal(time) | This method returns true if the Time on which the method has been called is equal to the Time provided as the argument. |
IsZero() | This method returns true if the Time on which the method has been called represents the zero-time instant, which is January 1, year 1, 00:00:00 UTC. |
In(loc) | This method returns the Time value, expressed in the specified Location. |
Location() | This method returns the Location that is associated with the Time, effectively allowing a time to be expressed in a different time zone. |
Round(duration) | This method rounds the Time to the nearest interval represented by a Duration value. |
Truncate(duration) | This method rounds the Time down to the nearest interval represented by a Duration value. |
In the following code we try to manipulate the time:
package main
import (
"fmt"
"time"
)
func Printfln(template string, values ...interface{}) {
fmt.Printf(template+"\n", values...)
}
func main() {
t, err := time.Parse(time.RFC822, "09 Jun 22 04:35 IST")
if err == nil {
Printfln("After: %v", t.After(time.Now()))
Printfln("Round: %v", t.Round(time.Hour))
Printfln("Truncate: %v", t.Truncate(time.Hour))
} else {
fmt.Println(err.Error())
}
}
Output:
$ go run main.go After: false Round: 2022-06-09 04:30:00 +0530 IST Truncate: 2022-06-09 04:30:00 +0530 IST
The Duration
type is an alias to the int64
type and is used to represent a specific number of milliseconds. Custom Duration values are composed from constant Duration values defined in the time package
package main
import (
"fmt"
"time"
)
func Printfln(template string, values ...interface{}) {
fmt.Printf(template+"\n", values...)
}
func main() {
var d time.Duration = time.Hour + (30 * time.Minute)
Printfln("Hours: %v", d.Hours())
Printfln("Mins: %v", d.Minutes())
Printfln("Seconds: %v", d.Seconds())
Printfln("Millseconds: %v", d.Milliseconds())
rounded := d.Round(time.Hour)
Printfln("Rounded Hours: %v", rounded.Hours())
Printfln("Rounded Mins: %v", rounded.Minutes())
trunc := d.Truncate(time.Hour)
Printfln("Truncated Hours: %v", trunc.Hours())
Printfln("Rounded Mins: %v", trunc.Minutes())
}
Explanation:
The Duration is set to 90 minutes, and then the Hours, Minutes, Seconds, and Milliseconds methods are used to produce output. The Round and Truncate methods are used to create new Duration values, which are written out as hours and minutes.
Output:
$ go run main.go Hours: 1.5 Mins: 90 Seconds: 5400 Millseconds: 5400000 Rounded Hours: 2 Rounded Mins: 120 Truncated Hours: 1 Rounded Mins: 60
Golang time.Since() and time.Until()
The time
package defines two functions that can be used to create Duration values that represent the amount of time between a specific Time and the current Time
Since(time)
: This function returns a Duration expressing the elapsed time since the specified Time value.Until(time)
: This function returns a Duration expressing the elapsed time until the specified Time value.
package main
import (
"fmt"
"time"
)
func Printfln(template string, values ...interface{}) {
fmt.Printf(template+"\n", values...)
}
func main() {
toYears := func(d time.Duration) int {
return int(d.Hours() / (24 * 365))
}
future := time.Date(2051, 0, 0, 0, 0, 0, 0, time.Local)
past := time.Date(1965, 0, 0, 0, 0, 0, 0, time.Local)
Printfln("Future: %v", toYears(time.Until(future)))
Printfln("Past: %v", toYears(time.Since(past)))
}
The example uses the Until and Since methods to work out how many years until 2051 and how many years have passed since 1965.
$ go run main.go Future: 28 Past: 57
Golang time.ParseDuration()
The time.ParseDuration
function parses strings to create Duration values. This function returns a Duration and an error, indicating if there were problems parsing the specified string.
Following table describes the Duration
String Unit Indicators
Unit | Description |
---|---|
h | This unit denotes hours. |
m | This unit denotes minutes. |
s | This unit denotes seconds. |
ms | This unit denotes milliseconds. |
us or μs | These units denotes microseconds. |
ns | This unit denotes nanoseconds. |
No spaces are allowed between values, which can be specified as integer or floating-point amounts.
package main
import (
"fmt"
"time"
)
func Printfln(template string, values ...interface{}) {
fmt.Printf(template+"\n", values...)
}
func main() {
d, err := time.ParseDuration("1h30m")
if err == nil {
Printfln("Hours: %v", d.Hours())
Printfln("Mins: %v", d.Minutes())
Printfln("Seconds: %v", d.Seconds())
Printfln("Millseconds: %v", d.Milliseconds())
} else {
fmt.Println(err.Error())
}
}
The string specifies 1 hour and 30 minutes.
$ go run main.go Hours: 1.5 Mins: 90 Seconds: 5400 Millseconds: 5400000
Summary
We have learned that Golang time package supports the wall clock time and the monotonic time. Golang have some types and functions that works with channel as well as just work within a channel, like the time.After
and the time.Tick
, also the time.Now
that’s returns the current time and the time.Date
that is used to create time. we have talked about time.Duration
and how you need it to use the most of the time functions in Golang.
Reference
More information on these functions and types we were unable to talked about can be found in the Golang time package official documentation.