What is UTC?
How to get the current time?
How to represent a time in different timezones?
How to parse a time ?
How to format a time with a specific layout?
How to compare two points in time?
How to add minutes, days, years, seconds to a time?
What is a wall clock?
What is a monotonic clock?
Timezone
Time offset
UTC
Wall clock
Monotonic clock
Unix Epoch
In many cases, you need to have the current date and time. To get this information, you can call the function time.Now()
// dates-and-time/main.go \n\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n now := time.Now()\n fmt.Printf("%s", now)\n}
\nHere we are calling time.Now()
and then we are printing the result. time.Now()
returns a variable of type time.Time
. Here is the output of the previous script :
2019-02-12 13:13:55.429243 +0100 CET m=+0.000329111
\nOn the figure 1 you can see the signification of the different portions printed.
\nYou can see that you have the date and the time. In the result, you also have the timezone.
\nis a time offset. It means that the current time displayed is the Coordinated Universal Time (UTC) + 01 hour and 00 minutes. This time offset is commonly named UTC+01:00
\nCET means central Central European Time. This is the other name of the time offset UTC+01:00
\nThe timezone is an important element for communicating time between people. If you are developing an API and you output time in a field, you have to tell your users which timezone you use. For instance “13:13:55” in Brazil and “13:13:55” in Stockholm does not refer to the same point in time, not at all!
\n2009-11-10 23:00:00 +0000 UTC m=+0.000000001
\nHere is another outputed result of time.Now()
. You can see here that the timezone is different. The time displayed here is the Coordinated Universal Time (UTC).
The “Unix Epoch” is the number of seconds elapsed since 1 January 1970 00:00:00 UTC.
\nWith a variable of type time.Time
you can get the Unix Epoch with the method Unix()
:
now := time.Now()\nlog.Println(now.Unix())\n// > 2021/02/11 18:29:35 1613064575
\nThis way of representing time is unambiguous. There is no time zone involved, and you can store it into a single integer!
\n\nFrom the point of view of the computer, what we call commonly “time” comes in different flavors. But to better understand those flavors, we first need to understand how a computers keep track of time.
\n\nAttached to the motherboard of your computer, you can find a small hardware device that keeps track of time.
\nInside this device, you can generally find a piece of quartz that will oscillate at a constant rate. To oscillate, it needs little energy.
\nWhen the computer is unplugged, this device will continue to track time (until there is no battery left).
\n\nThe wall clock is mainly used for telling the time to the user.
\n\nThere is another clock: the monotonic clock. This clock is used to tell the elapsed time between two points in the time.
\nThe wall clock is subject to change. The clock might be slightly ahead, for example. Consequently, the system might need to synchronize it with a reference clock.
\nConsequently, we cannot trust this clock to offer a precise measure of the time elapsed.
\nWe need a clock that adds time at a constant rate to measure an elapsed time correctly. This is the monotonic clock.
\nYou can find the idea of constant time variation in its name: monotonous means “Tedious, repetitious, or lacking in variety.”
Go use this clock is compute durations.
\n\nIn this section, we are going to study a very common use case: formatting the time. You can format and display the time in your program in many ways; some are specified by a norm (for instance, the RFC 3339), some are not and come directly from ingenious developers’ minds.
\n\nFormat
method? The method Format
has a single parameter: a string.
This string informs Go how the time needs to be formatted. If you come from another language, you might expect something like that :
\nYYYY-MM-DD h:i:s
\nHere YYYY means to display the years with four digits; MM indicates to the program to display the months with two digits... But in Go, the format is written differently :
\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n now := time.Now()\n fmt.Println(now.Format("Mon Jan 2 "))\n}
\nWe first get the current time by calling the function time.Now()
Then we format this time with the method Format
The result is printed
This code block will output the following string :
\nWed Feb 13
\n\nThe format is \"Mon Jan 2 \"
. This is because the format in Go is defined based on a reference date which is :
Mon Jan 2 15:04:05 -0700 MST 2006
\nMonday
January 2 from the year 2006 at 15:04:05
MST means Mountain Standard Time. This is the timezone (UTC minus 7 hours).
In the time
package, you will find some constants with common formats :
Specification | \nGo Constant | \nExample | \n
---|---|---|
RFC 3339 | \ntime.RFC3339 | \n2019-02-13T13:48:10+01:00 | \n
ANSIC | \ntime.ANSIC | \nWed Feb 13 13:49:17 2019 | \n
RFC 822 | \ntime.RFC822 | \n13 Feb 19 13:49 CET | \n
RFC 822 | \ntime.RFC822Z | \n13 Feb 19 13:50 +0100 | \n
RFC 1123 | \ntime.RFC1123 | \nWed, 13 Feb 2019 13:51:06 CET | \n
RFC 339 (with ns) | \ntime.RFC3339Nano | \n2019-02-13T13:51:44.298774+01:00 | \n
UNIX | \ntime.UnixDate | \nWed Feb 13 13:52:29 CET 2019 | \n
Here is an example of how to use the format time.RFC3339
:
// dates-and-time/formatting/main.go \npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n fmt.Println(time.Now().Format(time.RFC3339))\n}
\nThis application will output :
\n2019-02-15T13:20:36+01:00
\n\nIf you expose dates to your users, you want to print them in their respective timezone :
\n// dates-and-time/location/main.go\npackage main\n\n//...\n\nfunc main() {\n now := time.Now()\n fmt.Printf("%s\\n", now)\n\n loc, err := time.LoadLocation("America/New_York")\n if err != nil {\n panic(err)\n }\n\n nowNYC := now.In(loc)\n fmt.Printf("%s\\n", nowNYC)\n}
\nOutput :
\n2021-02-11 18:45:36.949939 +0100 CET m=+0.000601934\n2021-02-11 12:45:36.949939 -0500 EST
\nThose two dates represent the same point in time but in two different locations: France and New York.
\nThe function time.LoadLocation
takes a string as parameter, which represents a timezone name from the IANA1 Time Zone Database2.
You can use the Parse
function from the time
package. This function takes two arguments :
The format of the time you want to parse (Go needs to know which format your input data has)
A string that contains your time formatted
This function will return a time.Time
or an error (if the parsing of the time has failed). Here is an example :
// dates-and-time/parse/main.go \n\ntimeToParse := "2019-02-15T07:33-05:00"\nt,err := time.Parse("2006-01-02T15:04-07:00",timeToParse)\nif err != nil {\n panic(err)\n}\n\nfmt.Println(t)
\nWe put the string \"2019-02-15T07:33-05:00\"
into the variable timeToParse
.
Then we call time.Parse
How did I manage to find the right format? You have to look at an example and then build your format string to make each part of the date match with the reference date.
\nThe format time.RFC3339
is used by default when a date is unmarshaled from JSON.
To get the time elapsed between two points, you can use the method Sub
of time.Time
:
// dates-and-time/elapsed/main.go \n\nstart := time.Now()\nerr := ioutil.WriteFile("/tmp/thisIsATest", []byte("TEST"), 0777)\nif err != nil {\n panic(err)\n}\nend := time.Now()\nelapsed := end.Sub(start)\nfmt.Printf("process took %s", elapsed)
\nWe save the current time in the variable start
We write data to a file.
Then we get the current time again. We save that time into the variable end
The elapsed duration is computed with the call end.Sub(start)
We print the duration returned (elapsed
is of type time.Duration
)
The type time.Duration
denotes elapsed time between two moments. Here is its definition in the standard library :
// A Duration represents the elapsed time between two instants\n// as an int64 nanosecond count. The representation limits the\n// largest representable duration to approximately 290 years.\ntype Duration int64
\nIts underlying type is int64
. It represents the number of nanoseconds between two points in time.
The type time.Time
has two handy methods :
Before\n\nAfter
\nThose two methods accept a time.Time
as input.
Let’s take an example :
\n// dates-and-time/comparison/main.go \n\nlocation, err := time.LoadLocation("UTC")\nif err != nil {\n panic(err)\n}\n\nfirstJanuary1980 := time.Date(1980,1,1,0,0,0,0,location)\n\ntimeToParse := "2019-02-15T07:33-02:00"\nt,err := time.Parse("2006-01-02T15:04-07:00",timeToParse)\nif err != nil {\n panic(err)\n}\n\nnow := time.Now()\nif t.After(firstJanuary1980) && t.Before(now) {\n fmt.Println(t, "is between ", firstJanuary1980, "and",now)\n}else {\n fmt.Println("not in between")\n}
\n\nWhen you need to add a specific number of days, months, or year, you can use the method AddDate
a number of year(s)
a number of month(s)
a number of days(s)
When you need to add a more specific amount of time, you can use Add
(ex: nanoseconds, microseconds, milliseconds, seconds, minutes, hours).
time.Duration
as input which represents a number of nanoseconds.// dates-and-time/add/main.go \n\nnow := time.Now()\n\n// + 12 years\n// + 1 Month\n// + 3 days\nnow = now.AddDate(12,1,3)\n\n\nnow = now.Add(time.Nanosecond * 1)\nnow = now.Add(time.Microsecond * 5)\nnow = now.Add(time.Millisecond * 5)\nnow = now.Add(time.Second * 5)\nnow = now.Add(time.Minute * 5)\nnow = now.Add(time.Hour * 5)
\nThe package time defines constants that represent a nanosecond, microsecond, millisecond, second, minute, and hour in nanoseconds. We can use those constants to create custom durations.
\n\nYou want to display to your users each day between a start date and an end date.
\nTo achieve this, you can use the AddDate
method.
Those three quantities will be added to the date. The modified date is then returned :
\nstart, err := time.Parse("2006-01-02", "2019-02-19")\nstartPlus1Day := start.AddDate(0,0,1)
\nWe added one day, zero month, and zero year to the start date. We can use this function inside a for loop to iterate over each day between two limit dates :
\n// dates-and-time/iterate/main.go \n\nfunc main() {\n start, err := time.Parse("2006-01-02", "2019-02-19")\n if err != nil {\n panic(err)\n }\n end , err := time.Parse("2006-01-02", "2020-07-17")\n if err != nil {\n panic(err)\n }\n for i := start; i.Unix() < end.Unix(); i = i.AddDate(0, 0, 1) {\n fmt.Println(i.Format(time.RFC3339))\n }\n}
\nHere we define two dates : start
and end
. Those dates will represent our start and stop points in time.
Then we can create a for loop. A for loop has three parts :
\nThe init: this instruction is executed just once before the for loop as started
The condition: this expression must return a boolean (true or false). It is evaluated before every iteration. If it’s false, the loop will stop.
The post statement: this statement is executed after each iteration
The init phase of our for loop is simple we create a new variable namedi
. Then we check before each iteration that the end date (variable end
) is bigger than the current iteration date (variable i
). The post statement will add one day to the current iteration date (with the AddDate
method).
With this loop, we will iterate over each day between the start
and end
date.
What if you want to iterate over hours, minutes or seconds? You will have to use the Add
method :
for i := start; i.Unix() < end.Unix(); i = i.Add(time.Minute*2) {\n fmt.Println(i.Format(time.RFC3339))\n}
\nInstead of adding one day to the date, we add 2 minutes. Hence the for loop will take us from the 2nd February 2019 at midnight to the 17th July 2019 with 2 minutes steps. That’s exactly 370.080 iterations!
\n\nWhat is the signification of UTC?
How to get the current time?
What is the underlying type of time.Duration
?
True or False.2021-02-11 19:23:03.465196 +0100 CET
, 2021-02-11 13:23:03.465196 -0500 EST
and 2021-02-11 18:25:06.465196 +0000 UTC
represent three different points in time.
How to add 5 minutes to a time t
?
How to add two years and one day to a time t
?
What is the signification of UTC?
\nHow to get the current time?
\nWhat is the underlying type of time.Duration
?
True or False.2021-02-11 19:23:03.465196 +0100 CET
, 2021-02-11 13:23:03.465196 -0500 EST
and 2021-02-11 18:25:06.465196 +0000 UTC
represent 3 different points in time.
False, they represent the same point in time.
2021-02-11 18:25:06.623301 +0000 UTC
is the representation of this instant in UTC
2021-02-11 19:23:03.465196 +0100 CET
is the representation of this instant with the timezone of Paris (France)
2021-02-11 13:23:03.465196 -0500 EST
is the representation of this instant with the timezone of New York (US)
How to add 5 minutes to a time t
?
t = t.Add(time.Minute*5)
How to add two years and one day to a time t
?
t = t.AddDate(2,0,1)
The package time
contains all you need to manipulate time.
To get the current time, you can use time.Now()
which will return a time.Time
.
To convert a time.Time
into a string you can use the method Format
. It takes a string as parameter: the layout.
To parse a string representing a time, you can use the function time.Parse(layout, value string)(time.Time, error)
The layout is a string that represents the “format” of the time.
The layout is exprimed with a reference date : “Mon Jan 2 15:04:05 MST 2006”
Common formats are defined as constants in the time
package. The most commonly used is time.RFC3339
The methods Before
and After
can be used to compare two times
time.Duration
represents the elapsed duration between two points in time.
You can represent a time in a different time zone with the method In
that takes a *time.Location
as input (which can be loaded with time.LoadLocation(tzName)
)
Previous
\n\t\t\t\t\t\t\t\t\tEnum, Iota & Bitmask
\n\t\t\t\t\t\t\t\tNext
\n\t\t\t\t\t\t\t\t\tData storage : files and databases
\n\t\t\t\t\t\t\t\t