LoginSignup
12
4

More than 5 years have passed since last update.

Go言語で時間を扱う(pkg/time)機能まとめ

Posted at

ちょくちょく調べなおすことがあるので、この際いっきにまとめてみた。

まずはドキュメントを読んでみましょう。
https://golang.org/pkg/time/
部分的にDocumentのExampleを参考にしてるところはあります。

基本的な使い方

Now()で現在時刻、Date()で特定の時刻が取れます。

package main

import (
        "fmt"
        "time"
)

func main() {
        fmt.Println("----- Basic usage -----")
        now := time.Now()
        fmt.Println("Now()        : " + now.String())
        time1 := time.Date(2018, 10, 15, 16, 48, 32, 12345, time.Local)
        fmt.Println("Date()       : " + time1.String())
        fmt.Println()
}
----- Basic usage -----
Now()        : 2018-12-21 18:02:48.2384152 +0900 JST m=+0.024933301
Date()       : 2018-10-15 16:48:32.000012345 +0900 JST

ここ以降は出力の関係上 "strconv"もimportしておいてください。
また説明が重複するため、package, import 部分は省略します。

値取得関係の関数

日時などの値を単純に取得する関数です。

fmt.Println("----- Functions -----")
fmt.Println("Year()       : " + strconv.Itoa(now.Year()))
fmt.Println("Month()      : " + now.Month().String())
fmt.Println("int(now.Month()) : " + strconv.Itoa(int(now.Month())))
fmt.Println("Day()        : " + strconv.Itoa(now.Day()))
fmt.Println("Hour()       : " + strconv.Itoa(now.Hour()))
fmt.Println("Minute()     : " + strconv.Itoa(now.Minute()))
fmt.Println("Second()     : " + strconv.Itoa(now.Second()))
fmt.Println("Nanosecond() : " + strconv.Itoa(now.Nanosecond()))
fmt.Println("Weekday()    : " + now.Weekday().String())
fmt.Println("int(Weekday()) : " + strconv.Itoa(int(now.Weekday())))
fmt.Println("Unix()       : " + strconv.FormatInt(now.Unix(), 10))
fmt.Println("UnixNano()   : " + strconv.FormatInt(now.UnixNano(), 10))

iso_year, iso_week := now.ISOWeek()

fmt.Println("ISOWeek() year : " + strconv.Itoa(iso_year))
fmt.Println("ISOWeek() week : " + strconv.Itoa(iso_week))
fmt.Println()
----- Functions -----
Year()       : 2018
Month()      : December
int(now.Month()) : 12
Day()        : 21
Hour()       : 18
Minute()     : 2
Second()     : 48
Nanosecond() : 238415200
Weekday()    : Friday
int(Weekday()) : 5
Unix()       : 1545382968
UnixNano()   : 1545382968238415200
ISOWeek() year : 2018
ISOWeek() week : 51

Month()だと英文字の月名になるのが要注意ですね。なんで数字じゃないんだ。
intでキャストする必要があります。Weekday()、お前は許す。。

またIOSWeek()は年の53週間中何週間目がわかるから便利ですね。

便利な関数

じゃあ年月日を取るために Year(), Month(), Day() を使うか~っと思ったら、ちょっと待って。
下記のDate(), Clock()が便利ですよ。

fmt.Println("----- Simple Functions -----")
fmt.Println("Date()  Clock()")
year, month, day := now.Date()
hour, min, sec   := now.Clock()
fmt.Println(year)
fmt.Println(int(month))
fmt.Println(day)
fmt.Println(hour)
fmt.Println(min)
fmt.Println(sec)
fmt.Println()

fmt.Println("YearDay()    : " + strconv.Itoa(now.YearDay()))
fmt.Println("UTC()        : " + now.UTC().String())
fmt.Println("Local()      : " + now.Local().String())

zoneName, zoneOffset := now.Zone()

fmt.Println("Zone() (name,offset) : " + "( " + zoneName + " , " + strconv.Itoa(zoneOffset) + " )")
fmt.Println()
----- Simple Functions -----
Date()  Clock()
2018
12
21
18
2
48

YearDay()    : 355
UTC()        : 2018-12-21 09:02:48.2384152 +0000 UTC
Local()      : 2018-12-21 18:02:48.2384152 +0900 JST
Zone() (name,offset) : ( JST , 32400 )

Date()、Clock()はいっきに取れるから便利ですね。
また年間で何日目なのか?がわかるYearDay()も便利ですね。
UTC←→JST変換も楽です。zone情報もわかりますね。

加減算

時間の加算減算です。

fmt.Println("----- Add -----")
fmt.Println("Now()           : " + now.String())

now = now.Add(time.Duration(-1) * time.Hour)
fmt.Println("time 1 hour ago : " + now.String())
fmt.Println()
----- Add -----
Now()           : 2018-12-21 18:02:48.2384152 +0900 JST m=+0.024933301
time 1 hour ago : 2018-12-21 17:02:48.2384152 +0900 JST m=-3599.975066699

もちろんHour以外にもDayでもMinuteでも可能です。

フォーマット変換

指定のフォーマットから文字列時刻を読み取ります。

fmt.Println("----- Parse() Format()-----")
var timeParse01 = time.Time{}
timeParse01, _  = time.Parse("2006/01/02 15:04:05 (MST)", "2018/12/21 13:45:38 (JST)")

fmt.Println("Parse()          : " + timeParse01.String())
fmt.Println("Format(ANSIC)    : " + timeParse01.Format(time.ANSIC))
fmt.Println("Format(RFC1123Z) : " + timeParse01.Format(time.RFC1123Z))
fmt.Println()
----- Parse() Format()-----
Parse()          : 2018-12-21 13:45:38 +0900 JST
Format(ANSIC)    : Fri Dec 21 13:45:38 2018
Format(RFC1123Z) : Fri, 21 Dec 2018 13:45:38 +0900

パースするところで、2006とか01とか02ってなんなんだ?と思ってましたが、そういうフォーマットの指定方法なんですね。
ここを見るとわかります。
https://golang.org/src/time/format.go

const (
    ANSIC       = "Mon Jan _2 15:04:05 2006"
    UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
    RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
    RFC822      = "02 Jan 06 15:04 MST"
    RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
    RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
    RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
    RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
    RFC3339     = "2006-01-02T15:04:05Z07:00"
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
    Kitchen     = "3:04PM"
    // Handy time stamps.
    Stamp      = "Jan _2 15:04:05"
    StampMilli = "Jan _2 15:04:05.000"
    StampMicro = "Jan _2 15:04:05.000000"
    StampNano  = "Jan _2 15:04:05.000000000"
)

const (
    _                        = iota
    stdLongMonth             = iota + stdNeedDate  // "January"
    stdMonth                                       // "Jan"
    stdNumMonth                                    // "1"
    stdZeroMonth                                   // "01"
    stdLongWeekDay                                 // "Monday"
    stdWeekDay                                     // "Mon"
    stdDay                                         // "2"
    stdUnderDay                                    // "_2"
    stdZeroDay                                     // "02"
    stdHour                  = iota + stdNeedClock // "15"
    stdHour12                                      // "3"
    stdZeroHour12                                  // "03"
    stdMinute                                      // "4"
    stdZeroMinute                                  // "04"
    stdSecond                                      // "5"
    stdZeroSecond                                  // "05"
    stdLongYear              = iota + stdNeedDate  // "2006"
    stdYear                                        // "06"
    stdPM                    = iota + stdNeedClock // "PM"
    stdpm                                          // "pm"
    stdTZ                    = iota                // "MST"
    stdISO8601TZ                                   // "Z0700"  // prints Z for UTC
    stdISO8601SecondsTZ                            // "Z070000"
    stdISO8601ShortTZ                              // "Z07"
    stdISO8601ColonTZ                              // "Z07:00" // prints Z for UTC
    stdISO8601ColonSecondsTZ                       // "Z07:00:00"
    stdNumTZ                                       // "-0700"  // always numeric
    stdNumSecondsTz                                // "-070000"
    stdNumShortTZ                                  // "-07"    // always numeric
    stdNumColonTZ                                  // "-07:00" // always numeric
    stdNumColonSecondsTZ                           // "-07:00:00"
    stdFracSecond0                                 // ".0", ".00", ... , trailing zeros included
    stdFracSecond9                                 // ".9", ".99", ..., trailing zeros omitted

    stdNeedDate  = 1 << 8             // need month, day, year
    stdNeedClock = 2 << 8             // need hour, minute, second
    stdArgShift  = 16                 // extra argument in high bits, above low stdArgShift
    stdMask      = 1<<stdArgShift - 1 // mask out argument
)

時間単位の変更

X時間は何分/何秒なのか?とかの単位変換計算が楽になります。

fmt.Println("----- ParseDuration() -----")
duration, _ := time.ParseDuration("2h35m10s")
fmt.Println("Duration String      : " + duration.String())
fmt.Println("Duration in minutes  : " + strconv.FormatFloat(duration.Minutes(), 'f', 0, 64))
fmt.Println("Duration in seconds  : " + strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
fmt.Println()
----- ParseDuration() -----
Duration String      : 2h35m10s
Duration in minutes  : 155
Duration in seconds  : 9310

どれくらいの時間の隔たりがあるか

二つの時間の差分がSub()、その時間から今までがSince()、今から未来の時間までがUntil()。
このへんも便利ですね。

fmt.Println("----- Sub() Since() Until() -----")
time01 := time.Date(2018, 10, 10, 15,  0,  0, 0, time.Local)
time02 := time.Date(2018, 10, 25, 15, 30, 10, 0, time.Local)

fmt.Println("time01   : " + time01.String())
fmt.Println("time02   : " + time02.String())

time01Subtime02 := time01.Sub(time02)
time02Subtime01 := time02.Sub(time01)

fmt.Println("time01.Sub(time02)   : " + time01Subtime02.String())
fmt.Println("time02.Sub(time01)   : " + time02Subtime01.String())
fmt.Println()

time03 := time.Date(2018, 12, 10, 0, 0, 0, 0, time.Local)
time04 := time.Date(2018, 12, 25, 0, 0, 0, 0, time.Local)

fmt.Println("Now()    : " + now.String())
fmt.Println("time03   : " + time03.String())
fmt.Println("time04   : " + time04.String())

fmt.Println("time.Since(time03)   : " + time.Since(time03).String())
fmt.Println("time.Until(time04)   : " + time.Until(time04).String())
fmt.Println()
----- Sub() Since() Until() -----
time01   : 2018-10-10 15:00:00 +0900 JST
time02   : 2018-10-25 15:30:10 +0900 JST
time01.Sub(time02)   : -360h30m10s
time02.Sub(time01)   : 360h30m10s

Now()    : 2018-12-21 17:02:48.2384152 +0900 JST m=-3599.975066699
time03   : 2018-12-10 00:00:00 +0900 JST
time04   : 2018-12-25 00:00:00 +0900 JST
time.Since(time03)   : 282h2m48.3541336s
time.Until(time04)   : 77h57m11.6458664s

どっちが新しい?古い?

自分はUnixタイムで比較してましたが、こんな関数もあるんですね。
After()、Before() の方がわかりやすい!可読性がよくなります。これならぱっと見わかりやすくなりますね。


fmt.Println("----- After() Before() -----")
date11m := time.Date(2018, 11, 1, 0, 0, 0, 0, time.Local)
date12m := time.Date(2018, 12, 1, 0, 0, 0, 0, time.Local)

fmt.Println(date11m)
fmt.Println(date12m)

isDate11mAfterDate12m := date11m.After(date12m)
isDate12mAfterDate11m := date12m.After(date11m)

fmt.Printf("date11m.After(date12m)  = %v\n", isDate11mAfterDate12m)
fmt.Printf("date12m.After(date11m)  = %v\n", isDate12mAfterDate11m)

isDate11mBeforeDate12m := date11m.Before(date12m)
isDate12mBeforeDate11m := date12m.Before(date11m)

fmt.Printf("date11m.Before(date12m) = %v\n", isDate11mBeforeDate12m)
fmt.Printf("date12m.Before(date11m) = %v\n", isDate12mBeforeDate11m)
fmt.Println()
----- After() Before() -----
2018-11-01 00:00:00 +0900 JST
2018-12-01 00:00:00 +0900 JST
date11m.After(date12m)  = false
date12m.After(date11m)  = true
date11m.Before(date12m) = true
date12m.Before(date11m) = false

同じ時間か?

時差があっても同じ時刻か比較できます。ここtimeパッケージのExampleを参考にしました。

fmt.Println("----- Equal() -----")
//時差が8時間の "Beijing Time" を作ります。
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

timeBeijin := time.Date(2018, 2, 1, 20, 15, 45, 0, beijing)
timeUtc    := time.Date(2018, 2, 1, 12, 15, 45, 0, time.UTC)

fmt.Println(timeBeijin)
fmt.Println(timeUtc)

datesEqualUsingEqualOperator := timeBeijin == timeUtc
datesEqualUsingFunction      := timeBeijin.Equal(timeUtc)

fmt.Printf("datesEqualUsingEqualOperator = %v\n", datesEqualUsingEqualOperator)
fmt.Printf("datesEqualUsingFunction = %v\n", datesEqualUsingFunction)
fmt.Println()
----- Equal() -----
2018-02-01 20:15:45 +0800 Beijing Time
2018-02-01 12:15:45 +0000 UTC
datesEqualUsingEqualOperator = false
datesEqualUsingFunction = true

timeBeijinとtimeUtcは時刻は違いますが、地球上の上では時差を換算すると同じ時刻ですからTrueになりますね。
(UTC)12:15 + (Beijin時差)8hr = (Beijin Time)20:15

それにしても上記のように書けば時差ロケーションが作れるんですね。

四捨五入や切り下げ

時間の四捨五入ってめんどくさいですよね。でもこれなら簡単です。
Round()は四捨五入みたいな感じで、Truncate()は切り捨てですね。


fmt.Println("----- Round() Truncate() -----")
time10    := time.Date(2018, 12, 10, 14, 15, 45, 987654321, time.Local)

fmt.Println("time10                      : " + time10.String())
fmt.Println("time10.Round(time.Hour)     : " + time10.Round(time.Hour).String())
fmt.Println("time10.Round(time.Minute)   : " + time10.Round(time.Minute).String())
fmt.Println("time10.Round(time.Second)   : " + time10.Round(time.Second).String())
fmt.Println("time10.Truncate(time.Hour)  : " + time10.Truncate(time.Hour).String())
fmt.Println("time10.Truncate(time.Minute): " + time10.Truncate(time.Minute).String())
fmt.Println("time10.Truncate(time.Second): " + time10.Truncate(time.Second).String())
fmt.Println()
----- Round() Truncate() -----
time10                      : 2018-12-10 14:15:45.987654321 +0900 JST
time10.Round(time.Hour)     : 2018-12-10 14:00:00 +0900 JST
time10.Round(time.Minute)   : 2018-12-10 14:16:00 +0900 JST
time10.Round(time.Second)   : 2018-12-10 14:15:46 +0900 JST
time10.Truncate(time.Hour)  : 2018-12-10 14:00:00 +0900 JST
time10.Truncate(time.Minute): 2018-12-10 14:15:00 +0900 JST
time10.Truncate(time.Second): 2018-12-10 14:15:45 +0900 JST

Parse処理うまくいったかな?

IsZero() ってなんのためにあるのかな?と思ってましたが、確認のためのようですね。

fmt.Println("----- IsZero() -----")
timeRight, _  := time.Parse("2006/01/02 15:04", "2018/12/21 13:45")
// Parse処理で不適切な形式をしてして失敗させます。
timeFail, _   := time.Parse("2006/01/02 15:04", "2018/12/21 hoge 13:45")

fmt.Println("timeRight   : " + timeRight.String())
fmt.Println("timeFail    : " + timeFail.String())
fmt.Println("timeRight.IsZero()   : " + strconv.FormatBool(timeRight.IsZero()))
fmt.Println("timeFail.IsZero()    : " + strconv.FormatBool(timeFail.IsZero()))
fmt.Println()
----- IsZero() -----
timeRight   : 2018-12-21 13:45:00 +0000 UTC
timeFail    : 0001-01-01 00:00:00 +0000 UTC
timeRight.IsZero()   : false
timeFail.IsZero()    : true

なるほど。パースに失敗すると0001-01-01....になってしまうんだな。

サンプルソース全文

こちらです
https://gist.github.com/36ca5e2245b38bf0aa4eb05ee9a3c8df

12
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
4