概要
本日は2024はうるう年で2月29日が追加され、1年が366日ある年です。
そんな2024/02/29に落ちるテストがあっておもしろかったので共有です
テスト概要
ユーザーの会員期限の再アクティベートのテスト。一度会員になって失効して再度会員になったときに正常に有効化できるか、というような旨のてすとです。
- 失効期限を今日から1年後にする
- 失効期限を1年前に戻す
- 期限が切れていることを期待する
- 再度アクティベートする
という流れの3でうるう年の今日だけ有効期限が切れなくなっていました。
原因
Golang でうるう年2/29の1年後を取得すると、翌年の2025年は2/29 がないので3/1 に繰り上げされ、1年後の1年前が今日じゃなくて翌日になっていたため!
例:
1/ 失効期限を今日から1年後にする
→ 2025年に2/29 はないので3/1
2/ 失効期限を1年前に戻す
→ 2025年3/1 だったので2024 3/1 になる
3/ 期限が切れていることを期待する
Now() = 2029 2/29 なので< 2024/ 3/1
会員期限は迎えていない!閏年に救われている!
↓
失敗
対応
1年足すのをやめて日数を足すようにした
PlayGround での確認
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"time"
)
func main() {
// 普通に考えて1年後にすすめて1年前にもどしたらその日に戻る
t := time.Date(2023, 2, 28, 0, 0, 0, 0, time.UTC)
fmt.Printf("初期状態: %s\n", t)
tAdd1year := t.AddDate(1, 0, 0)
fmt.Printf("1年後: %s\n", tAdd1year)
fmt.Printf("1年後の1年前: %s\n", tAdd1year.AddDate(-1, 0, 0))
println("===============")
// うるう年2/29は例外!
t = time.Date(2024, 2, 29, 0, 0, 0, 0, time.UTC) // 閏年の2/29
fmt.Printf("初期状態: %s\n", t)
tAdd1year = t.AddDate(1, 0, 0)
fmt.Printf("1年後: %s\n", tAdd1year)
fmt.Printf("1年後の1年前: %s\n", tAdd1year.AddDate(-1, 0, 0)) // 3/1になっている
}
ref: https://go.dev/play/p/f4z9CXbIi8d
memo:
1ヶ月増減はセーフ
12ヶ月増減はアウト
365日増減はセーフ