Handling time is a common task for programmers. In Go, the standard library time
provides the necessary capabilities.
This article will introduce some important functions and methods in the time
package, hoping to help those who often need to deal with time-related issues in Go.
Handle Time Zones
In programming, we often encounter the issue of an eight-hour time difference. This is caused by differences in time zones. To better handle them, we need to understand several time definition standards.
GMT (Greenwich Mean Time) is based on the Earth’s rotation and revolution to calculate time. It defines noon as the time when the sun passes through the Royal Greenwich Observatory in the suburbs of London, UK. GMT was the former world standard time.
UTC (Coordinated Universal Time) is more precise than GMT, calculated based on atomic clocks. In situations where precision to the second is not required, UTC can be considered equivalent to GMT. UTC is the current world standard time.
From the Prime Meridian at Greenwich, going east is positive, going west is negative. The globe is divided into 24 standard time zones, with neighboring time zones differing by one hour.
|
|
In mainland China, the standard time used is in the GMT+8 time zone, known as China Standard Time (CST).
|
|
This is the result under the default time zone, and +0800 CST
is indicated in the time.Now()
printout.
Suppose we are in the Los Angeles time zone in the United States, what result do we get?
|
|
As seen, the result at this time is -0700 PDT
, which is Pacific Daylight Time. Due to the time zone difference, the results of the two executions differ by 15 hours.
Note that when using Docker containers, the system’s default time zone is UTC time (0 time zone), which is eight hours behind Beijing time as we need, leading to the classic scenario of the eight-hour time difference problem.
Strategies for dealing with time zone issues can be found in detail in the loading logic of the initLocal()
function in src/time/zoneinfo_unix.go
. For example, you can solve it by specifying the environment variable TZ
or modifying the /etc/localtime
file.
Because time zone issues are very important, they are discussed in the first part of the article. Let’s now move on to the usage of the time
package.
Time Instant time.Time
The core object in the time
package is the time.Time
struct. Its definition, used to represent a specific moment in time, is as follows:
|
|
In computer time handling, two types of clocks are mainly involved:
- Wall clock, also known as clock time, used to represent specific dates and times.
- Monotonic clocks, which always guarantee that time moves forward without the issue of wall clock rollback, making them suitable for measuring durations.
The wall
and ext
fields are used to record wall clock and monotonic clock times, with nanosecond precision. The bits of these fields are associated with specific information such as years, months, days, hours, minutes, and seconds.
The loc
field records the time zone location. When loc
is nil
, it defaults to UTC time.
Because time.Time
is used to represent time instants with nanosecond precision, it is typically stored and passed as a value in programs, rather than a pointer.
That is, in time variables or struct fields, we should use time.Time
rather than *time.Time
.
Getting time.Time
We can get the current local time using the Now
function:
|
|
Or, using the Date
function, we can get a specified time based on the year, month, day, and other parameters, along with the time zone:
|
|
Converting Timestamps
In the computer world, UTC time 0 on January 1, 1970, is considered Unix time 0. To convert a time instant into a Unix timestamp, we calculate the number of seconds, microseconds, etc., elapsed from Unix time 0 to the specified instant.
|
|
Getting Basic Fields
|
|
Duration time.Duration
time.Duration
represents the time elapsed between two time.Time
instants. It uses an int64
to represent the count of nanoseconds, allowing for approximately 290 years of representation.
|
|
In Go, time.Duration
is simply a number in nanoseconds. If a duration is equal to 1000000000, it represents 1 second, or 1000 milliseconds, or 1000000 microseconds, or 1000000000 nanoseconds.
For example, the duration between two time instants separated by 1 hour can be calculated as:
|
|
The time
package defines constant values for these durations:
|
|
Additionally, time.Duration
provides methods to get values at various time granularities:
|
|
Time Calculation
After learning about time instants and durations, let’s see how to perform time calculations.
|
|
Add
adds or subtracts (positived
means addition, negatived
means subtraction) atime.Duration
to atime.Time
. We can add or subtract durations of specific nanosecond levels to a specific instant in time.
|
|
Sub
returns the duration between two time instants.
|
|
AddDate
adds or subtracts values based on the year, month, and day dimensions to atime.Time
.
Of course, calculating based on the current time instant time.Now()
is the most common requirement. Therefore, the time
package also provides the following convenient time calculation functions:
|
|
Since
is a shortcut for time.Now().Sub(t)
.
|
|
Until
is a shortcut for t.Sub(time.Now())
.
Usage Example
|
|
Formatting Time
In other languages, a universal time template is typically used to format time. For example, in Python, %Y
represents year, %m
represents month, %d
represents day, and so on.
However, Go is different. It uses a fixed time (it’s important to note that using other times is not allowed) as the layout template, and this fixed time is the birth time of the Go language.
|
|
Formatting time involves two conversion functions:
|
|
Parse
converts a time string to atime.Time
object based on the layout it can correspond to.
|
|
Format
converts atime.Time
object to a time string based on the given layout.
Example
|
|
In the time
package, Go provides some predefined layout template constants that can be directly used.
|
|
Here’s a table of optional layout parameters:
|
|
Timezone Conversion
At the beginning of the article, we discussed timezone issues. If in your code, you need to get the result of the same time.Time
in different time zones, you can use its In
method.
|
|
It’s straightforward to use. Let’s see an example code:
|
|
Conclusion
In general, the functions and methods provided by the time
package for time processing meet our usage needs.
Interestingly, Go’s time formatting conversion must adopt Go’s birth time. It’s quite self-centered.