ファイル名にタイムスタンプを入れたいなと思ってtime パッケージを調べてたんですが、便利な機能が意外とあるなと気づいたのでまとめてみました。
ちょくちょく調べることがあるので、この際いっきにまとめてみることにした。
自分でも知らない機能があったりして、面白かったです。
まずはドキュメントを読んでみましょう。
time - The Go Programming Language
あ部分的にDocumentのExampleを参考にしてるところはあります。
- 基本的な使い方
- 値取得関係の関数
- 便利な関数
- 加減算
- フォーマット変換
- 時間単位の変更
- どれくらいの時間の隔たりがあるか
- どっちが新しい?古い?
- 同じ時間か?
- 四捨五入や切り下げ
- Parse処理うまくいったかな?
- サンプルソース全文
- (2018/12/26)追記
基本的な使い方
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
Now()で現在時刻、Date()で特定の時刻が取れます。
ここ以降は出力の関係上 "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ってなんなんだ?と思ってましたが、そういうフォーマットの指定方法なんですね。
ここを見るとわかります。
src/time/format.go - The Go Programming Language
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 )
時間単位の変更
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
X時間は何分/何秒なのか?とかの単位変換計算が楽ですね。
どれくらいの時間の隔たりがあるか
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
二つの時間の差分がSub()、その時間から今までがSince()、今から未来の時間までがUntil()。
このへんも便利ですね。
どっちが新しい?古い?
自分はUnixタイムで比較してましたが、こんな関数もあるんですね。
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
After()、Before() の方がわかりやすい!可読性がよくなります。これまで時間の比較はエポックタイムで比較してたんですが、これならぱっと見わかりやすくなりますね。
同じ時間か?
時差があっても同じ時刻か比較してくれます。
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
それにしても上記のように書けば時差ロケーションが作れるんですね。
四捨五入や切り下げ
時間の四捨五入ってめんどくさいですよね。でもこれなら簡単です。
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
Round()は四捨五入みたいな感じで、Truncate()は切り捨てですね。
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....になってしまうんだな。
サンプルソース全文
こちらです
Tips of Tim pkg
(2018/12/26)追記
qiitaにも書いてみました。
qiita.com