|
| 1 | +package times |
| 2 | + |
| 3 | +import ( |
| 4 | + "time" |
| 5 | + |
| 6 | + "github.com/devlights/gomy/output" |
| 7 | +) |
| 8 | + |
| 9 | +// CalcNextMonth は、翌月の日付を求めるサンプルです。 |
| 10 | +// |
| 11 | +// # REFERENCES |
| 12 | +// - https://pkg.go.dev/time@go1.21.4 |
| 13 | +func CalcNextMonth() error { |
| 14 | + // |
| 15 | + // 日付が範囲外の存在しない値になったとき、Goはその値を存在する日付に変換する。 |
| 16 | + // この変換を「正規化」という。なので、翌月を求める際に元の値によっては |
| 17 | + // 翌々月となってしまうことがある。 |
| 18 | + // |
| 19 | + |
| 20 | + const ( |
| 21 | + LOC = "Asia/Tokyo" |
| 22 | + ) |
| 23 | + |
| 24 | + var ( |
| 25 | + jst, _ = time.LoadLocation(LOC) |
| 26 | + original = time.Date(2023, 10, 31, 0, 0, 0, 0, jst) |
| 27 | + ) |
| 28 | + |
| 29 | + output.Stdoutl("[original]", original.Format(time.RFC3339)) |
| 30 | + |
| 31 | + // |
| 32 | + // 11月には31日が存在しないため |
| 33 | + // そのままAddDateすると、正規化されて12月02日となってしまう。 |
| 34 | + // |
| 35 | + |
| 36 | + var ( |
| 37 | + nextMonth1 = original.AddDate(0, 1, 1) |
| 38 | + ) |
| 39 | + |
| 40 | + output.Stdoutl("[nextmonth1]", nextMonth1.Format(time.RFC3339)) |
| 41 | + |
| 42 | + // |
| 43 | + // ちゃんと計算して求めるやり方 (書籍「実用 GO言語」) |
| 44 | + // 年月日以外の部分(時分秒とナノ秒)は面倒なので0固定 |
| 45 | + // |
| 46 | + |
| 47 | + var ( |
| 48 | + year, month, day = original.Date() // 元の日付 |
| 49 | + first = time.Date(year, month, 1, 0, 0, 0, 0, jst) // 元の日付の月初 |
| 50 | + year2, month2, _ = first.AddDate(0, 1, 0).Date() // 月初の値を使って翌月の年と月を取得 |
| 51 | + nextMonth2 = time.Date(year2, month2, day, 0, 0, 0, 0, jst) // 元の日付の日を当てて翌月値を仮作成 |
| 52 | + ) |
| 53 | + |
| 54 | + if month2 != nextMonth2.Month() { |
| 55 | + // 正規化が発生して翌々月になってるので調整 |
| 56 | + // - 2月進めて1日戻すと翌月の末日になる |
| 57 | + nextMonth2 = first.AddDate(0, 2, -1) |
| 58 | + } |
| 59 | + |
| 60 | + output.Stdoutl("[nextmonth1]", nextMonth2.Format(time.RFC3339)) |
| 61 | + |
| 62 | + return nil |
| 63 | +} |
0 commit comments