time.Since()とtimeパッケージについて深ぼる

[到達していたい状態]
- timeパッケージとは何かを人に説明できる。
- time.Since()を使いこなせる。
[やること]
- timeパッケージについて記事や本で調べる

パッケージタイムは時間の計測と表示の機能を提供します。
暦計算は常にグレゴリオ暦を想定しており、うるう秒はありません。
要するにtime packageは時間の計測と表示の機能を提供している。
現在の時刻を取得する
Goでは現在の時刻を、time.Time型で表します。
timeパッケージのNow関数を利用すると、現在時刻を表すtime.Time型の値を取得できます。
func main() {
t := time.Now()
fmt.Printf("型: %T\n", t) // => 型: time.Time
fmt.Printf("値: %v\n", t) // => 値: 2023-06-24 12:37:29.155645 +0900 JST m=+0.000126510
}
指定した時刻を生成する
timeパッケージのDate関数を使えば、指定した時刻を表すtime.Time型の値を生成できます。
以下では、時間を全て0にしたtime.Time型の値を生成できます。
func main() {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
fmt.Printf("型: %T\n", today) // => 型: time.Time
fmt.Printf("値: %v\n", today) // => 値: 2023-06-24 00:00:00 +0900 JST
}
time.Dateの最後に与えられている引数はタイムゾーンを表しています。time.Localは実行環境のタイムゾーンと同等の日時を得られます。time.UTCを引数として渡した場合、タイムゾーンがUTCの日時を取得できます。
func main() {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
fmt.Printf("型: %T\n", today) // => 型: time.Time
fmt.Printf("値: %v\n", today) // => 値: 2023-06-24 00:00:00 +0000 UTC
}
UTCの時刻をローカルの時刻に変換する
Localメソッドを利用することで、時刻のタイムゾーンをローカルのタイムゾーンに変換した新しい時刻を生成できます。
func main() {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
fmt.Printf("型: %T\n", today) // => 型: time.Time
fmt.Printf("値: %v\n", today) // => 値: 2023-06-24 00:00:00 +0000 UTC
// JSTの時刻はUTCの時刻に比べて、9時間プラスされている
jst := today.Local()
fmt.Printf("値: %v\n", jst) // => 値: 2023-06-24 09:00:00 +0900 JST
}
また、UTCメソッドで、時刻のタイムゾーンをUTCに変換した新しい時刻を生成できます。
func main() {
now := time.Now()
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
fmt.Printf("型: %T\n", today) // => 型: time.Time
fmt.Printf("値: %v\n", today) // => 値: 2023-06-24 00:00:00 +0000 UTC
// JSTの時刻はUTCの時刻に比べて、9時間プラスされている
jst := today.Local()
fmt.Printf("値: %v\n", jst) // => 値: 2023-06-24 09:00:00 +0900 JST
// UTCの時刻はJSTの時刻に比べて、9時間マイナスされている
utc := jst.UTC()
fmt.Printf("値: %v\n", utc) // => 値: 2023-06-24 00:00:00 +0000 UTC
}
指定時間のスリープ
timeパッケージに定義されているSleep関数を利用することで、実行しているゴルーチンを指定した時間停止できます(引数にはtime.Duration型の値を指定する)。
ちなみに、時間の間隔を表現したい場合、time.Duration型を利用します。
func main() {
time.Sleep(5 * time.Second)
fmt.Println("5秒間停止させました")
}

time.Since()を利用して、処理時間を計測する
timeパッケージのSince関数を用いることで、処理にかかった時間を計測できます。
計測地点を自分で設定して、計測したい処理の後で、Since関数を呼び出します。
func main() {
t := time.Now()
time.Sleep(5 * time.Second)
fmt.Printf("経過時刻 %vms\n", time.Since(t).Milliseconds())
}

tickerは一定の間隔で繰り返し何かをしたいときに使う
tickerは一定の間隔で繰り返し何かをしたいときに使います。
(厳密にいうと、tickerと、ticker.Cチャネルを使うことで、定期的に繰り返し実行できます。)
tickerを生成することで、指定された間隔で定期的に値をticker.Cチャネルに送信します。ticker.Cチャネルが値を受信した場合のみ、処理を実行するように実装すれば、定期的に繰り返し実行することができます。
func main() {
// time.Tickerは、指定された間隔で定期的に値を送信するための機能を提供します。
// 5秒ごとに値が送信されるtime.Tickerを作成しています。
ticker := time.NewTicker(2 * time.Second)
done := make(chan bool)
go func() {
for {
select {
case <-done:
// doneチャネルが値を受信した場合、以下の処理が実行される
return
// ticker.Cは、time.Ticker型の値から読み取れるチャネルです
// ticker.Cチャネルは、time.Tickerが設定された間隔ごとに現在の時刻を送信します。
case t := <-ticker.C:
// ticker.Cチャネルが値を受信した場合、以下の処理が実行される
fmt.Println("Tick at", t)
}
}
}()
time.Sleep(10 * time.Second)
// tickerをオフにして、tickerから送信されるのをストップする
ticker.Stop()
// doneというチャネルにtrueを送信する
done <- true
fmt.Println("Ticker stopped")
}
実行結果
➜ cmd go run main.go
Tick at 2023-06-24 13:35:43.555469 +0900 JST m=+2.000965444
Tick at 2023-06-24 13:35:45.555745 +0900 JST m=+4.001222992
Tick at 2023-06-24 13:35:47.555711 +0900 JST m=+6.001171560
Tick at 2023-06-24 13:35:49.555755 +0900 JST m=+8.001197303
Tick at 2023-06-24 13:35:51.555797 +0900 JST m=+10.001221344
Ticker stopped

time.Time型を指定した場合のMySQLの注意点
構造体にtime.Time型を指定した場合、MySQLの接続情報にパラメータとしてparseTime=trueを含める必要がある。