Posted at

日付の差分を「○年△ヶ月」で取得する in Rails

More than 3 years have passed since last update.

ある期間の開始日時が分かっていて、現在まで何年何ヶ月以上経過しているのかの差分を取って欲しい、みたいな要件が Rails でありました。


はじめに考えた

Rails にはdistance_of_time_in_words_to_nowというまさになヘルパーメソッドがあるのでそれの利用を検討したんですが、このメソッドは「1分」「3分」「5分」みたいに近い時間は細かく扱ってくれるけど、期間が長くなると「約1ヶ月」「約2年」みたいに結構マルっと丸めてくれるので用途に合いませんでした。ということで自前で実装することにしました。


日付の差分を「○年△ヶ月」で取得する

  def distance_of_time_in_words_to_now(from_time)

distance_of_time_in_words(from_time, Time.now)
end

def distance_of_time_in_words(from_time, to_time)
from_time = from_time.to_date if from_time.respond_to?(:to_date)
to_time = to_time.to_date if to_time.respond_to?(:to_date)
years = 0
months = 0
loop {
from = from_time + years.year + months.month
if (to_time - (from + 1.year)) >= 0 then years += 1
elsif (to_time - (from + 1.month)) >= 0 then months += 1
else break
end
}
distance = ''
distance += "#{years}年 " if years != 0
distance += "#{months}ヶ月"
end

from を「1年」or「1ヶ月」ずつズラしていって「○年△ヶ月」を計算するようにしました。もう少し書き足せば「○年△ヶ月□日」とかもイケそうですね。


まとめ

こういうときの悩みどころは「1年」や「1ヶ月」の扱いだと思います。「1年 = 366日」の年もあれば「1ヶ月 = 28日」の月もあるわけで、どうやってその辺をうまく「1年」「1ヶ月」として扱うかということ。

自前で「?年?月だからこの月は 28日」とか「?年だから 366日」とか実装することを考えると・・・いや考えたくないですね。今回は ActiveSupport にその辺を任せることでうまく実装できました。ありがとう ActiveSupport。