Time is not a primitive type of variable. It's a complex value that contains information about various intervals of time: hours, minutes seconds, etc. In this topic, you will learn how the time variable works in Golang, how to compare time, and what to do if you want to change the time.
Time initialization
First of all, you need to know that time is a structured variable. The library time has a struct to represent time. It's called time.Time. This structure keeps time in nanoseconds, and it has a few methods that can help you in your projects. This topic focuses on how basic functions work, and if you'd like additional information, you can look at the official golang documentation.
You can use the similar syntax (like var or :=) to initialize a time.Time variable, as you do with primitive types. However, it has some interesting features: time.Time is a structure with private fields, which means that you can initialize it only with a default value. And the default is the first of January of the first year at 00:00 o'clock by UTC: 0001-01-01 00:00:00 +0000 UTC.
The correct way to create a variable with the time you need is to use the function time.Date(). It takes eight arguments and returns a struct of the time.Time type.
Let's see what arguments time.Date() takes:
year
month
day
hour
minute
second
nanosecond
location (timezone)
If you just want to get the current time, you don't need to write it yourself. Use the time.Now() function. It doesn't require any arguments and returns the time.Time structure as well:
package main
import (
"fmt"
"time"
)
func main() {
// YEAR MONTH D H M S nS Location
starWars := time.Date(1977, time.May, 4, 0, 0, 0, 0, time.UTC)
fmt.Println(starWars)
fmt.Println(starWars.Date())
fmt.Println(time.Now())
}
// Output:
// 1977-05-04 00:00:00 +0000 UTC
// 1977 May 4
// 2022-04-05 15:51:03.410972 +0500 +05 m=+0.000249376Pay attention to the time.Date() variable initialization. To represent month and location, you should use built-in constants and functions. If you want to get a month's name from its number, the function time.Month() will help you. For example, time.Month(10) will return time.October.
Time comparison
What if you wanted to compare time variables? You could try to use comparison operators like >, <, >=, <=, ==. None of them would work except for ==. The "equal" operator can compare two variables of the same type, but since we are talking about structures, it's not the correct operation.
Naturally, the time library contains features that can help you solve this problem. There are three functions: Before, After, and Equal. All of them are called by source time, take the compared time, and return a boolean value.
Beforereturnstrueif the original date has happened before the date it's compared withAfterreturnstrueif the original date has happened after the date it's compared withEqualreturnstrueif the original and compared dates are the same
package main
import (
"fmt"
"time"
)
func main() {
darwin, _ := time.LoadLocation("Australia/Darwin")
presentMcFly := time.Date(1985, time.October, 26, 1, 20, 0, 0, time.UTC)
futureMcFly := time.Date(1955, time.November, 12, 22, 4, 0, 0, time.UTC)
fmt.Println(presentMcFly.Before(futureMcFly))
fmt.Println(presentMcFly.After(futureMcFly))
fmt.Println(presentMcFly.Equal(futureMcFly))
futureMcFlyInDarwin := time.Date(1955, time.November, 13, 7, 34, 0, 0, darwin)
fmt.Println(futureMcFly.Equal(futureMcFlyInDarwin))
fmt.Println(futureMcFly == futureMcFlyInDarwin)
}
// Output:
// false
// true
// false
// true
// falseAs you see in the code above, the date stored in presentMcFly happened after the futureMcFly date. Hence, the expected output is:
Beforecalled onpresentMcFlywill returnfalseAftercalled onpresentMcFlywill returntrueEqualcalled onpresentMcFlywill returnfalse
The last two outputs in the code above show the difference between the == operator and the time.Equal() function. The variable futureMcFlyInDarwin sends McFly to Australia, to the timezone of Darwin. If you try to compare futureMcFlyInDarwin with futureMcFly the usual way (using ==), it will return false. On the other hand, the time.Equal() will return true, because the date and the time are the same, just in a different timezone.
Operations with time
Like usual comparison operators that don't work properly with time variables, the usual arithmetic operators (+ - / *) wouldn't work on them either. However, Golang has some methods to modify time variables. There are not a lot of them, though: only addition and subtraction.
Before continuing, we need to say a few words about the difference in time. In Golang, time difference is a specific type called Duration, which stores value in nanoseconds (just like time.Time). However, nanoseconds are not an easy-to-use feature if you need to set another value. Thus, for convenience, Golang has constants equivalent to the most-used time intervals: nanosecond, microsecond, millisecond, second, minute, and hour.
package main
import (
"fmt"
"time"
)
func main() {
twoSecond := time.Millisecond*1000 + time.Second
sevenDays := time.Hour * 24 * 7
oneYear := time.Hour * 24 * 365
threeYearsAndTwoMonths := oneYear*3 + time.Hour*24*30
fmt.Println(twoSecond)
fmt.Println(sevenDays)
fmt.Println(oneYear)
fmt.Println(threeYearsAndTwoMonths)
}
// Output:
// 2s
// 168h0m0s
// 8760h0m0s
// 27000h0m0sPay attention to the output: Duration has a formatted output, but it uses an integer value with all other operations. If you want to get 10 seconds, for example, just take the time.Second constant and multiply it by ten.
Let's return now to the addition and subtraction of time. Corresponding features are called Add and Sub. Both functions are called on the source variable, but:
Addreturns a newtime.Timevalue that differs from the original value by the given interval;Subtakes thetime.Timevariable and returns the difference between it and the second provided value as aDurationtype.
package main
import (
"fmt"
"time"
)
func main() {
CopernicusBDay := time.Date(1473, time.February, 19, 0, 0, 0, 0, time.UTC)
NewtonBDay := CopernicusBDay.Add(time.Hour * 1489080)
EinsteinBDay := time.Date(1879, time.March, 14, 0, 0, 0, 0, time.UTC)
fmt.Println("Timeline:")
fmt.Printf("Nicolaus Copernicus: %v\n", CopernicusBDay)
fmt.Printf(" | %v\n", NewtonBDay.Sub(CopernicusBDay))
fmt.Printf("Isaac Newton: %v\n", NewtonBDay)
fmt.Printf(" | %v\n", EinsteinBDay.Sub(NewtonBDay))
fmt.Printf("Albert Einstein: %v\n", EinsteinBDay)
}
// Output:
// Timeline:
// Nicolaus Copernicus: 1473-02-19 00:00:00 +0000 UTC
// | 1489080h0m0s
// Isaac Newton: 1643-01-04 00:00:00 +0000 UTC
// | 2070384h0m0s
// Albert Einstein: 1879-03-14 00:00:00 +0000 UTCConclusion
The main thing about time.Time is that it's not a simple variable type. It's a complex structure that contains a lot of information about time. To work with it, you need to know certain special features:
to initialize the time variable, use the
time.Dateortime.Nowfunctions;the structure
time.Timehas its own comparison operations (Before,After, andEqual);the structure
time.Timesupports two modifying operations — addition and subtraction (AddandSub, respectively);time.Timehas a set of constants for time intervals, names of months, and timezones.