Ruby on Railsで2つの日付間の月数を見つける


95

Ruby on RailsのDateTimeオブジェクトが2つあります。それらの間の月数を見つける方法は?(異なる年に属している可能性があることを覚えておいてください)



指摘してくれてありがとう。私は探しましたが、つまずかなかった。
フェニックスウィザード2016

このリンクを参照してくださいstackoverflow.com/questions/1065320/...
sangeethkumar

リンクを数字で表示したい。Massimiliano Pelusoが言及した方法でそれを実現しました
フェニックスウィザード

ただ私はあなたの参照のためにそれを与えました..とにかくありがとう..
sangeethkumar

回答:


179
(date2.year * 12 + date2.month) - (date1.year * 12 + date1.month)

詳細についてはhttp://www.ruby-forum.com/topic/72120をご覧ください


25
このソリューションでは、日数は考慮されません。2000
4

15
何日も考えずに必要なので、これでうまくいきます。+1
WattsInABox 2013年

1
この素晴らしい答えのもう1つのバリエーション:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
ステパンザカロフ

2017-05-20から2018-05-20までの2年間の月を取得しようとすると、誤った月数が表示されます。出力は1か月を示します。
好奇心旺盛な開発者

1
@CuriousDeveloperそれは正しい月、つまり12
ts

39

より正確な答えは、遠くの日を考慮します。

たとえば、月の距離がでなくである28/4/2000と考える場合は、次のように使用できます。1/5/200001

(date2.year - date1.year) * 12 + date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)

1
たとえば、誰かが常に月の22日に給与を受け取った回数を計算するには
Matthias

15

してみてください

((date2.to_time - date1.to_time)/1.month.second).to_i

irb>Time.at("2014-10-01".to_time - "2014-12-01".to_time).month => 10 (私はフォーマットをあきらめます...それを理解することはできません)
トビージョイナー

Dateオブジェクトを使用しても、@ toby-joinerのコメントは正しいままです。その理由は、<10月>-<12月>は-2か月ですが、Time.at(-2months).monthは-2に相当する月(つまり-2%12#=> 10)を与えるためです。提案された方法は、2か月の間隔が1年未満の場合は機能しますが、2か月の順序が逆の場合(10月から12月など)、または2か月の間隔が1年を超える場合は失敗します。
elreimundo、2015年

2
私はその背後にあるアイデアが好きですが、期間が本当に長くなっている場合は正しくありません。私の例でDate.new(2014, 10, 31), Date.new(1997, 4, 30)は、210か月ではなく213を受け取りました。その理由1.month.secondsは、30日の秒数であり、1か月の平均秒数ではありません。他の人がバグのない状態を保つための反対投票。
Joe Eifert、2016

1
30日ではない月を選択した場合、これは機能しません
dima

2
この方法はあまり正確ではありません。
vagabond

9

「日付の月の初めの間に最初の何日あるか」という質問を言い換えると、関数形式のデータ変換を使用できます。

(date1.beginning_of_month...date2.beginning_of_month).select { |date| date.day == 1 }.size

元の質問に戻るには、日数を合計し(最初の質問と同じように)、合計の平均を取ることができます。
Joe Eifert、2016

9

両方が日付であると仮定すると、 ((date2 - date1).to_f / 365 * 12).round 単純です。


とても良い解決策です!クリーン、シンプル、でも何年全体で動作します-すなわち2018年2月と12月2017年の間に数ヶ月の範囲
jeffdill2

1
時間、分、秒を考慮に入れる必要がある ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
scarver2

1
@ scarver2計算から得られる数値はかなりずれています。私たちがしているのは、数日をかけて月に変換することだけです。毎月30.4167日を想定しているため、それほど正確ではありませんが、非常に近く、とにかく丸められます。
Andreykul


2

私が見つけたもう1つの解決策(既にここに投稿された解決策に基づいて構築されたもの)は、結果に1か月の端数が含まれるようにする場合のものです。たとえば、距離は1.2 monthsです。

((date2.to_time - date1.to_time)/1.month.second).round(1) #Tenth of a month Ex: 1.2
((date2.to_time - date1.to_time)/1.month.second).round(2) #Hundreth, ex: 1.23 months
etc...

1
実際に経過した月のみを表示したい場合は、床でラプラプラウンドを試してください
Matthias

2
def difference_in_months(date1, date2)
  month_count = (date2.year == date1.year) ? (date2.month - date1.month) : (12 - date1.month + date2.month)
  month_count = (date2.year == date1.year) ? (month_count + 1) : (((date2.year - date1.year - 1 ) * 12) + (month_count + 1))
  month_count
end

1
これについて詳しく説明していただければ役に立ちますか?一般に、SOの回答には、コードが何をするのか、なぜコードがソリューションとして機能するのかについての説明が含まれます
単一エンティティ

1

2つの日付の間の正確な月数(小数を含む)が必要であり、次のメソッドを作成しました。

def months_difference(period_start, period_end)
  period_end = period_end + 1.day
  months = (period_end.year - period_start.year) * 12 + period_end.month - period_start.month - (period_end.day >= period_start.day ? 0 : 1)
  remains = period_end - (period_start + months.month)

  (months + remains/period_end.end_of_month.day).to_f.round(2)
end

9月26日と9月26日(同日)を比較すると、1日として計算します。必要がない場合は、メソッドの最初の行を削除できます。period_end = period_end + 1.day

次の仕様に合格しています。

expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 31))).to eq 1.0
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 30))).to eq 0.97
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 10, 31))).to eq 3.0
# Overlapping february (28 days) still counts Feb as a full month
expect(months_difference(Date.new(2017, 1, 1), Date.new(2017, 3, 31))).to eq 3.0
expect(months_difference(Date.new(2017, 2, 10), Date.new(2017, 3, 9))).to eq 1.0
# Leap year
expect(months_difference(Date.new(2016, 2, 1), Date.new(2016, 2, 29))).to eq 1.0

ところで、それはRailsのActiveSupportに依存しています
mtrolle

1

これはブルートフォーシングバリアントです。

date1 = '2016-01-05'.to_date
date2 = '2017-02-27'.to_date
months = 0

months += 1 while (date2 << (count+1)) >= date1
puts months # => 13

date2 常により大きい必要があります date1


0

ここに別の方法があります。これは、2つの日付間の月数を計算するのに役立ちます

def months_difference(date_time_start, date_time_end)
  curr_months = 0
  while (date_time_start + curr_months.months) < date_time_end
    curr_months += 1
  end
  curr_months -= 1 if (date_time_start + curr_months.months) > date_time_end
  curr_months.negative? ? 0 : curr_months
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.