Tìm số tháng giữa hai Ngày trong Ruby on Rails


95

Tôi có hai đối tượng DateTime Ruby on Rails. Làm thế nào để tìm số tháng giữa chúng? (Hãy nhớ rằng họ có thể thuộc các năm khác nhau)


5
Đã được đặt câu hỏi và trả lời tại đây: stackoverflow.com/questions/5887756/…
Tim Baas,

Cảm ơn đã chỉ ra điều đó. Tôi đã tìm kiếm nhưng không tình cờ gặp nó.
phoenixwizard


Tôi muốn liên kết bằng số. Tôi đã nhận nó thực hiện bằng phương pháp này được gọi bởi Massimiliano Peluso
phoenixwizard

Chỉ cần tôi đưa nó cho bạn tham khảo .. Cảm ơn Dù sao ..
sangeethkumar

Câu trả lời:


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

thêm thông tin tại http://www.ruby-forum.com/topic/72120


25
Giải pháp này không xem xét ngày. Số tháng giữa 28/4/2000 và 2000/01/05 không phải là 1 tháng, nhưng 0.
dgilperez

15
Tôi cần một cái mà không cần xem xét ngày để điều này làm việc cho tôi. +1
WattsInABox,

1
Chỉ là một biến thể cho câu trả lời tuyệt vời này:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
Stepan Zakharov

Nó hiển thị số tháng không chính xác nếu chúng tôi cố gắng tìm nạp các tháng giữa 2 năm, tức là 2017-05-20 đến 2018-05-20. Kết quả hiển thị 1 tháng.
Nhà phát triển tò mò

1
@CuriousDeveloper Nó đang hiển thị các tháng chính xác, tức là 12
ts,

40

Một câu trả lời chính xác hơn sẽ xem xét các ngày ở xa.

Ví dụ, nếu bạn xem xét rằng tháng khoảng cách từ 28/4/20001/5/20000hơn 1, sau đó bạn có thể sử dụng:

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

1
ví dụ như để tính số lần ai đó đã nhận được tiền lương của mình luôn được tại ngày 22 của tháng
Matthias

15

Hãy thử

((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 (Tôi bỏ về định dạng ... không thể tìm nó ra)
Toby Joiner

Ngay cả khi bạn sử dụng đối tượng Date, nhận xét của @ toby-joiner sẽ vẫn đúng. Lý do là <Tháng 10> - <Tháng 12> là -2 tháng, nhưng Time.at (-2 tháng) .tháng cho tháng tương đương -2 (tức là -2% 12 # => 10). Phương pháp được đề xuất của bạn sẽ hoạt động nếu hai tháng nối tiếp nhau và cách nhau chưa đầy một năm, nhưng sẽ thất bại nếu hai tháng ngược lại (ví dụ: tháng 10 - tháng 12) hoặc nếu hai tháng cách nhau hơn một năm.
elreimundo

2
Tôi thích ý tưởng đằng sau nó, nhưng nó không chính xác nếu khoảng thời gian ngày càng dài. Trong ví dụ của Date.new(2014, 10, 31), Date.new(1997, 4, 30)tôi, tôi nhận được 213 thay vì 210 tháng. Lý do 1.month.secondslà số giây trong 30 ngày chứ không phải số giây trung bình trong một tháng. Từ chối để những người khác không có lỗi.
Joe Eifert

1
điều này sẽ không hoạt động nếu bạn chọn một tháng không phải là 30 ngày
dima

2
phương pháp này không chính xác lắm.
vagabond

9

Bạn có thể diễn đạt lại câu hỏi là "có bao nhiêu ngày đầu tiên trong khoảng thời gian từ đầu tháng của các ngày", rồi sử dụng các phép biến đổi dữ liệu kiểu chức năng:

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

Và để quay lại câu hỏi ban đầu, bạn có thể tính tổng các ngày (giống như bạn đang làm với câu hỏi đầu tiên) và lấy giá trị trung bình của các tổng.
Joe Eifert

9

Giả sử cả hai đều là ngày tháng: ((date2 - date1).to_f / 365 * 12).round đơn giản.


Giải pháp rất hay! Sạch sẽ, đơn giản và thậm chí hoạt động trong nhiều năm - tức là phạm vi các tháng từ tháng 2 năm 2018 đến tháng 12 năm 2017.
jeffdill2

1
Cần tính đến hàng giờ, phút và giây ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
Scarver2

1
@ Scarver2 Con số bạn nhận được từ tính toán của bạn là một con số sai lầm. Tất cả những gì chúng tôi đang làm là mất nhiều ngày và chuyển đổi chúng thành tháng, nó không phải là siêu chính xác vì nó giả định là 30.4167 ngày mỗi tháng, nhưng nó rất gần và sau đó nó vẫn làm tròn.
Andreykul

3
start_date = Date.today
end_date   = Date.today+90
months = (end_date.month+end_date.year*12) - (start_date.month+start_date.year*12)

//months = 3

2

Một giải pháp khác mà tôi đã tìm thấy (được xây dựng dựa trên một giải pháp đã đăng ở đây) là nếu bạn muốn kết quả bao gồm các phần nhỏ của một tháng. Ví dụ khoảng cách là 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
thử raplacing tròn với sàn nếu bạn whish để chỉ hiển thị những tháng thực sự mất hiệu lực
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
Sẽ rất hữu ích nếu bạn có thể giải thích về điều này? Nói chung trên SO câu trả lời bao gồm một lời giải thích về những gì mã lệnh thực hiện và tại sao nó hoạt động như một giải pháp
Độc Entity

1

Tôi cần số tháng chính xác (bao gồm cả số thập phân) giữa hai ngày và đã viết phương pháp sau cho nó.

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

Nếu so sánh, giả sử ngày 26 tháng 9 với ngày 26 tháng 9 (cùng ngày), tôi tính nó là 1 ngày. Nếu bạn không cần, bạn có thể xóa dòng đầu tiên trong phương thức:period_end = period_end + 1.day

Nó vượt qua các thông số kỹ thuật sau:

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

btw nó dựa trên ActiveSupport Rails'
mtrolle

1

Đây là một biến thể cưỡng bức vũ phu:

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 phải luôn lớn hơn date1


0

Đây là một phương pháp khác. Điều này sẽ giúp tính toán số tháng nguyên giữa hai ngày

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.