Welcome to new things

[Technical] [Electronic work] [Gadget] [Game] memo writing

Memo for using "time", the Go language's time calculation package

The Go language is often programmed by combining simple functions, and error checking occurs for each function, so the code in general tends to be long.

Even when I want to do something small, I need to write code accordingly, but it is tedious to write from scratch every time, so I would like to write down the processes I often do for my own copy and paste.

Here is a note for myself on how to use the time package to handle time in the Go language.

Location

Introduction.

Although the time is often handled in "JST", nowadays, the execution environment is not only the local PC, but also the server, Docker, Lambda, etc. Various locations can be assumed. However, nowadays, the execution environment is not only the local PC, but also the server, Docker, Lambda, etc. In some cases, the local time of the execution location may not be JST, so we first describe how to specify the location explicitly.

Time

The time is stored in the Time structure. The Time structure contains location information.

The two predefined locations in time are "UTC (time.UTC)" and "local (time.Local)".

To use other locations such as "JST", you need to read the time zone registered in the execution environment in time.LoadLocation() or create your own time zone in time.FixedZone(), To use other locations such as "JST", you need to read the time zone registered in the execution environment with time.LoadLocation() or create your own time zone with time.FixedZone().

Use Time.In() to generate Time for one location and Time for another.

t := time.Now().UTC() // Get current time in UTC
fmt.Println(t)        // 2020-05-12 20:14:31.2928348 +0000 UTC

// Read JST from time zone
tokyo, err := time.LoadLocation("Asia/Tokyo")
if err != nil {
    return err
}

timeTokyo := t.In(tokyo)
fmt.Println(timeTokyo) // 2020-05-13 05:14:31.2928348 +0900 JST

// Create your own JST (name optional)
jst := time.FixedZone("JST", +9*60*60)

timeJst := t.In(jst)
fmt.Println(timeJst) // 2020-05-13 05:14:31.2928348 +0900 JST

When getting the current time or creating a time, you might want to be aware of which location you are creating it in.

It may be possible to prepare a function to get the default location, following the time.Local configuration.

var jstLocation *time.Location
var jstOnce sync.Once

func jst() *time.Location {
    if jstLocation == nil {
        jstOnce.Do(func() {
            l, err := time.LoadLocation("Asia/Tokyo")
            if err != nil {
                l = time.FixedZone("JST2", +9*60*60)
            }
            jstLocation = l
        })
    }
    return jstLocation
}

func test() {
    t := time.Now().In(jst())
    fmt.Println(t)
}

Generate and retrieve time

Obtaining the current time

The current time can be obtained from time.Now(). The location is time.Local.

Generated by specifying a value

It is generated by specifying values ranging from years to nanoseconds.

Each value can be obtained using the Time method.

The month is an int value starting with 1, but the String() method is defined to allow output in English notation.

The week is an int value with Sunday starting at 0, but the String() method is defined to allow output in English notation.

The "date" can also be retrieved together using Time.Date().

t := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)

fmt.Println(t) //2020-01-02 03:04:05.123456789 +0900 JST

fmt.Println(t.Year())           // 2020
fmt.Println(t.Month())          // January
fmt.Printf("%d\n", t.Month())   // 1
fmt.Println(t.Day())            // 2
fmt.Println(t.Weekday())        // Thursday
fmt.Printf("%d\n", t.Weekday()) // 4
fmt.Println(t.Hour())           // 3
fmt.Println(t.Minute())         // 4
fmt.Println(t.Second())         // 5
fmt.Println(t.Nanosecond())     // 123456789

year, month, day := t.Date()
fmt.Println(year)  // 2020
fmt.Println(month) // January
fmt.Println(day)   // 3

character string format

Time can be generated from a string. It can also output time to a string in a specified format.

The format is not the common YYYY-MM-DD HH:mm:ss format, but is quite special, so I will first explain the format.

Format designation method

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

The format is specified by how the time "∗" is displayed in the format.

For example, the case of YYYY/MM/DD HH:mm:ss is as follows

t := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)

fmt.Println(t) // 2020-01-02 03:04:05.123456789 +0900 JST

fmt.Println(t.Format("2006/01/02 15:04:05")) // 2020/01/02 03:04:05

Format Notes

  • When zero-filling, place a zero in front of it.
  • When displaying nanoseconds, the decimal point is filled with zeros.
  • Since the original time is 3 p.m., hour is "3" in 12h and "15" in 24h.
  • The 24h display of hour is 2-digit with 15, so it is not possible to use a one-digit display with no zeros filled in.
  • The time zone is "-7" "MST" and MST is used to indicate the time zone
  • English notation can be used in the morning and afternoon, and PM should be listed.
  • The month can be written in English, so for 2020/1/2, enter January or Jan since it is January.
  • The day of the week in English can be used, e.g., Monday or Mon for Monday, 1/2/2020.
t := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)

fmt.Println(t) // 2020-01-02 03:04:05.123456789 +0900 JST

// 2020/1/2(Thu) 03:04:05(.123)AM JST +09:00
fmt.Println(t.Format("2006/1/2(Mon) 03:04:05(.000)PM MST -07:00"))

The reason why this particular date is the base of the format is because the base date is 01/02 03:04:05PM '06 -0700, The time is sequentially numbered 1, 2, 3... The reason why such a special date is used as the basis of the format is that the time is numbered 1, 2, 3... in English.

However, since it is not something that comes up quickly, I would make a note of the following format and use it while looking at the notes.

2006-01-02 [12h]03:04:05PM [24h]15:04:05 -07:00 MST January  Monday

Generate time from string

Generating time from a string is done by time.ParseInLocation().

The format in which the time is described is specified in the aforementioned manner.

If no location information is given in the string, the location of the second argument is applied.

t, err := time.ParseInLocation("2006-01-02", "2020-12-31", time.Local)
if err != nil {
    return err
}

fmt.Println(t) // 2020-12-31 00:00:00 +0900 JST

If the string contains location information, it will be applied at that location if it is the same as the location specified in the second argument, Otherwise, it will not be set.

In other words, setting a string to a location other than UTC or local will not be well identified.

unit of time

When performing time operations, we are dealing with lengths of time, the smallest unit being the nanosecond, which is an integer value.

However, since integers have too many digits to be understood if they are handled as they are, they are assigned a different type name, Duration, and the length of time is handled via Duration.

The Duration contains the Hour・Minute・Second・Millisecond... constants, which are used to write Duration to improve the readability of the time length.

For example, to calculate the time that adds "2 hours and 3 minutes" to the current time, the following is used.

t := time.Now().Add(time.Hour * 2 + time.Minute * 3)

calculation

addition and subtraction

The Time.Add() can be used to add or subtract time. The unit of time length is Duration as described above.

t := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)
tAdd := t.Add(time.Hour)  // 2020-01-02 04:04:05.123456789 +0900 JST
tSub := t.Add(-time.Hour) // 2020-01-02 02:04:05.123456789 +0900 JST

Differential (diff)

You can use Time.Sub() to find the time difference between two times. The unit of length of time is Duration.

The sequence is "a - b" if "a.Sub(b)" is the same as the formula.

a := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)
b := a.Add(-time.Hour)
fmt.Println(a.Sub(b))  // 1h0m0s

Adding and Subtracting Dates

Since it is troublesome to calculate Duration for dates such as "1 year later" or "3 days earlier," a dedicated method (Time.AddDate()) is provided for date addition and subtraction.

Specify the number of date additions and subtractions in the order of "year, month, day, and year" in the argument.

t := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.Local)
tt := t.AddDate(1, 0, -3) // 1 year 3 days ago
fmt.Println(t)            // 2020-01-02 03:04:05.123456789 +0900 JST
fmt.Println(tt)           // 2020-12-30 03:04:05.123456789 +0900 JST

Values below the time after the calculation are carried over as they are.

Unfortunately, no method is provided for determining date differences.

Comparison

Time has several methods for comparing times.

If you use Time.Sub() to find and check the absolute difference between two times, you only need to remember one method.

Since Time is a structure, the == operator can be used, but since it also compares locations, it should not be used as a method to check if they are the same time.

diff := a.Sub(b)

if diff == 0 {
    fmt.Println("同じ")
} else if diff > 0 {
    fmt.Println("aが後")
} else {
    fmt.Println("aが前")
}

Date Comparison

To compare two time dates in Time.Sub(), the hour and day must be set to zero before the date is compared.

Since there is no means provided to do these things in a benign manner, we will simply generate a new time from the time we wish to compare, with the hour and the day set to zero, and then compare them.

aZero := time.Date(a.Year(), a.Month(), a.Day(), 0, 0, 0, 0, time.Local)
bZero := time.Date(b.Year(), b.Month(), b.Day(), 0, 0, 0, 0, time.Local)

diff := aZero.Sub(bZero)

if diff == 0 {
    fmt.Println("同じ")
} else if diff > 0 {
    fmt.Println("aが後")
} else {
    fmt.Println("aが前")
}

Sleep

The "Sleep" function, which waits for the specified Duraion, is also defined in time.

time.Sleep(time.Duration.Second * 3)

Reference Articles

Impressions, etc.

The format designation doesn't look like a format at first glance..." I would have preferred something like YYYY-MM-DD HH:mm:ss....

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com