Go言語を真剣に勉強してみた〜番外編(時間の扱い方)〜


はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。
さて今回は「Go言語を真剣に勉強してみた〜番外編〜」と言うことで、Goでの時間の扱い方についてお話していきます。
今後も何かネタが浮かんだら「Go言語を真剣に勉強してみた〜番外編〜」と題してTIPS的な感じで書いていきます。

パッケージ

"time"パッケージを使います。

現在の時刻を取得する

time.go
package main

import "fmt"
import "time"

func main() {
    t := time.Now()
    fmt.Println(t)           // => "2015-05-05 07:23:30.757800829 +0900 JST"
    fmt.Println(t.Year())    // => "2015"
    fmt.Println(t.Month())   // => "May"
    fmt.Println(t.Day())     // => "5"
    fmt.Println(t.Hour())    // => "7"
    fmt.Println(t.Minute())  // => "23"
    fmt.Println(t.Second())  // => "30"
    fmt.Println(t.Weekday()) // => "Tuesday"
}

時刻オブジェクトを作成する

秒の後にナノセカンドまで指定するのを忘れがちなので注意。

time.go
package main

import "fmt"
import "time"

func main() {
    t := time.Date(2001, 5, 20, 23, 59, 59, 0, time.UTC)
    fmt.Println(t) // => "2001-05-20 23:59:59 +0000 UTC"
    t = time.Date(2001, 5, 20, 23, 59, 59, 0, time.Local)
    fmt.Println(t) // => "2001-05-20 23:59:59 +0900 JST"
}

時刻をフォーマットで扱う

time.go
package main

import (
    "fmt"
    "time"
)

func main()  {

    day := time.Now()
    //"2006年1月2日15時04分05秒"以外の時刻は正しいフォーマット文字列としては認識されない。
    const layout = "2006-01-02 15:04:05"
    fmt.Println(day.Format(layout))// => "2018-10-31 17:57:54"
}

ここで疑問になるのは、なぜ"2006-01-02 15:04:05"がフォーマットなのか?

それは、アメリカ式の時刻の順番です。"1月2日午後3時4分5秒2006年"(つまり「自然な順番」で1, 2, 3, 4, 5, 6)を指しているのです。Go開発者のRob Pikeさんがgolang-nutsメーリングリストで、最初からよく考えていればこの順番にはしなかったと言っていたが(英語圏でもイギリスとかだと違う順番だしね)、もうその順番になっているので変えられないし、それにきちんと文章化もされているともコメントしていた。従ってこれは単純にそういうものだと思うしかなさそうですね。

TIPS

では、せっかくなのでこういう時はどのような処理を書いていけば良いのかを記述していきます。

指定の日付が存在するかどうか調べる

time.go
package main

import "fmt"
import "time"

func main() {
    jd, err := isExist(2001, 1, 31)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(int(jd))
    }
    // => "2451940"
    jd, err = isExist(2001, 1, 32)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(int(jd))
    }
    // => "2001-1-32 is not exist"
}

// 指定の日付が存在するかどうか調べる。
// 存在しない日付を指定してもtime.Date()はよきに計らってくれるので、
// 指定した日付と違うtime.Timeが返ってくれば指定した日付が間違ってると判定。
func isExist(year, month, day int) (float64, error) {
    date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
    if date.Year() == year && date.Month() == time.Month(month) && date.Day() == day {
        return Julian(date), nil
    } else {
        return 0, fmt.Errorf("%d-%d-%d is not exist", year, month, day)
    }
}

// ユリウス日を求める
func Julian(t time.Time) float64 {
    // Julian date, in seconds, of the "Format" standard time.
    // (See http://www.onlineconversion.com/julian_date.htm)
    const julian = 2453738.4195
    // Easiest way to get the time.Time of the Unix time.
    // (See comments for the UnixDate in package Time.)
    unix := time.Unix(1136239445, 0)
    const oneDay = float64(86400. * time.Second)
    return julian + float64(t.Sub(unix))/oneDay
}

何日後、何日前の日付を求める

AddDateが使えます。引数はyear,month,dayの順です。

time.go
package main

import "fmt"
import "time"

func main() {
    t := time.Date(2001, 5, 31, 0, 0, 0, 0, time.Local)
    t = t.AddDate(0, 0, 1)
    fmt.Println(t) // => "2001-06-01 00:00:00 +0900 JST"

    t = time.Date(2001, 1, 1, 0, 0, 0, 0, time.Local)
    t = t.AddDate(0, 0, -1)
    fmt.Println(t) // => "2000-12-31 00:00:00 +0900 JST"
}

以上。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。

こちらの記事を今回参考にさせていただきました