AR ホームベーカリー

オイラのアウトプット用ホームベーカリー!

Rails の一ヶ月

ビジネスロジックでの判定で、いわゆる「一ヶ月前」という実装を愚直に 1.month.ago (ago(1.month)) などとした場合。

「これは当日を含むのか」とか「一ヶ月って30日?」「例えば閏年で 1/30 から一ヶ月後って 2/29 と 3/1 どっち? 一ヶ月前になると逆パターンだけどどう?」みたいな質問をされて、「前者はそら当日含むやろ!」とは思ったんだけど、後者は「確かに一ヶ月の長さって固定じゃないもんな」と気付いて、真面目に調べるなどしてみた。

結論

日数ベースではなく、ちゃんと「暦」として解釈して一ヶ月後になる。

blog.aiandrox.com

なので 2/29 の ago(1.month) だと 1/31 になるし、1/31 のsince(1.month) だと 2/28 (or 29) になる。

# 2024/1/31 の一ヶ月後 => 2024/2/29
[1] pry(main)> Time.parse('2024-1-31').since(1.month)
2024-02-29 00:00:00 +0900
# 2024/1/30 の一ヶ月後 => 2024/2/29
[2] pry(main)> Time.parse('2024-1-30').since(1.month)
2024-02-29 00:00:00 +0900
# 2024/1/29 の一ヶ月後 => 2024/2/29
[3] pry(main)> Time.parse('2024-1-29').since(1.month)
2024-02-29 00:00:00 +0900
# 2024/1/28 の一ヶ月後 => 2024/2/28
[4] pry(main)> Time.parse('2024-1-28').since(1.month)
2024-02-28 00:00:00 +0900
# 2024/2/29 の一ヶ月前 => 2024/1/29
[5] pry(main)> Time.parse('2024-2-29').ago(1.month)
2024-01-29 00:00:00 +0900
# 2024/2/28 の一ヶ月前 => 2024/1/28
[6] pry(main)> Time.parse('2024-2-28').ago(1.month)
2024-01-28 00:00:00 +0900
# 2024/3/31 の一ヶ月前 => 2024/2/29
[7] pry(main)> Time.parse('2024-3-31').ago(1.month)
2024-02-29 00:00:00 +0900

なぜそうなっているか

qiita.com

なるほどー、 ActiveRecord かしこいなあ!

という、何気なく保証される一ヶ月に対する学びのメモであった。