0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Goのtime.AddDate()で月加算がズレる件の対処方法

Posted at

概要

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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?