Goのtime.AddDate()で月加算がズレる件の対処方法
更新日:2025/3/13/(木) 12:38
タグ:Go
概要
time.AddDate()で月末の月加算がずれることに気づいた際のメモ
下記の記事がとても参考になりました
https://tech.mirrativ.stream/entry/2023/10/31/120000
問題点
- time.AddDate()で月末の月加算がずれる
- 12月末 + 2ヶ月 = 2月末としたいが、3/2や3/3となる
func main() { start := time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC) twoMonthLater := start.AddDate(0, 2, 0) fmt.Println(twoMonthLater) } // 出力: 2024-03-02 00:00:00 +0000 UTC
解決方法
- 独自に月を加算する関数を作成
// AddMonthsPreservingEndOfMonth は、指定された月数を日付 t に加算します。元の日付が月の末日付近であった場合、は日付の調整を行います。 // 標準の time.AddDate 関数では、月末のない月の処理が行えないためこの関数を作成しました。 // 例えば、1月31日に1ヶ月をtime.AddDateで加算すると、3月3日となりますが、 // この関数では加算後の月の末日(2月の最終日28日または29日)に調整します // // 引数: // - t: 基準の日付 // - months: 加算する月数 // // 返り値: // - time.Time: 月を加算した後の新しい日付 func AddMonthsPreservingEndOfMonth(t time.Time, months int) time.Time { // 基準日の日付部分を取得 day := t.Day() // 加算後の日付の最終日を取得 year, month, dayLimit := t.AddDate(0, months+1, -day).Date() // 基準日が月末付近だった際の日付の調整 // 左辺は基準日の日付が30日や31日で加算後の月に30日や31日が存在しない場合に対応するため // 右辺は基準日の月の月末が30日で加算後の月の月末が31日の場合に対応するため if day > dayLimit || t.Month() != t.AddDate(0, 0, 1).Month() { day = dayLimit } h, m, s := t.Clock() return time.Date(year, month, day, h, m, s, t.Nanosecond(), t.Location()) } func main() { start := time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC) twoMonthLater := AddMonthsPreservingEndOfMonth(start, 2) fmt.Println(twoMonthLater) } // 出力: 2024-02-29 00:00:00 +0000 UTC