ある期間の開始日時が分かっていて、現在まで何年何ヶ月以上経過しているのかの差分を取って欲しい、みたいな要件が 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。