ค้นหาจำนวนเดือนระหว่างสองวันใน Ruby on Rails


95

ฉันมีวัตถุ Ruby on Rails DateTime สองอัน จะหาจำนวนเดือนระหว่างนั้นได้อย่างไร? (โปรดทราบว่าอาจอยู่คนละปี)


5
ถูกถามและตอบที่นี่: stackoverflow.com/questions/5887756/…
Tim Baas

ขอบคุณที่ชี้ให้เห็น ฉันค้นหา แต่ไม่ได้สะดุดมัน
phoenixwizard

อ้างอิงลิงค์นี้stackoverflow.com/questions/1065320/…
sangeethkumar

ฉันต้องการลิงค์เป็นตัวเลข ฉันทำได้โดยวิธีการที่ Massimiliano Peluso อ้างถึง
phoenixwizard

ฉันให้มันเพื่อเป็นข้อมูลอ้างอิงของคุณ .. ขอบคุณอย่างไรก็ตาม ..
sangeethkumar

คำตอบ:


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

ข้อมูลเพิ่มเติมที่http://www.ruby-forum.com/topic/72120


25
การแก้ปัญหานี้ไม่พิจารณาวัน จำนวนเดือนระหว่าง 28/4/2000 ถึง 1/5/2000 ไม่ใช่ 1 เดือน แต่เป็น 0.
dgilperez

15
ฉันต้องการหนึ่งโดยไม่ต้องคำนึงถึงวันดังนั้นสิ่งนี้จึงเหมาะกับฉัน +1
WattsInABox

1
อีกรูปแบบหนึ่งสำหรับคำตอบที่ยอดเยี่ยมนี้:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
Stepan Zakharov

มันแสดง # เดือนที่ไม่ถูกต้องหากเราพยายามดึงข้อมูลเดือนระหว่าง 2 ปีคือ 2017-05-20 ถึง 2018-05-20 ผลลัพธ์จะแสดง 1 เดือน
Curious Developer

1
@CuriousDeveloper แสดงเดือนที่ถูกต้องคือ 12
ts

40

คำตอบที่ถูกต้องกว่าจะพิจารณาจากระยะทางหลายวัน

ตัวอย่างเช่นถ้าคุณพิจารณาว่าเดือนระยะทางจาก28/4/2000และ1/5/2000เป็น0มากกว่า1แล้วคุณสามารถใช้:

(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 (ฉันยอมแพ้ในการจัดรูปแบบ ... คิดไม่ออก)
Toby Joiner

แม้ว่าคุณจะใช้วัตถุ Date แต่ความคิดเห็นของ @ toby-joiner จะยังคงถูกต้อง เหตุผลก็คือว่า <ตุลาคม> - <ธันวาคม> คือ -2 เดือน แต่ Time.at (-2months) .month ให้เดือนเท่ากับ -2 (เช่น -2% 12 # => 10) วิธีที่คุณแนะนำจะใช้ได้ผลหากสองเดือนตามกันและห่างกันไม่ถึงหนึ่งปี แต่จะล้มเหลวหากสองเดือนอยู่ในลำดับย้อนกลับ (เช่นตุลาคม - ธันวาคม) หรือหากสองเดือนห่างกันมากกว่าหนึ่งปี
elreimundo

2
ฉันชอบแนวคิดเบื้องหลัง แต่จะไม่ถูกต้องหากช่วงวันที่ยาวขึ้นจริงๆ ในตัวอย่างของDate.new(2014, 10, 31), Date.new(1997, 4, 30)ฉันฉันได้รับ 213 แทนที่จะเป็น 210 เดือน เหตุผลก็1.month.secondsคือจำนวนวินาทีใน 30 วันไม่ใช่จำนวนวินาทีเฉลี่ยในหนึ่งเดือน การลงคะแนนเพื่อให้ผู้อื่นปราศจากข้อผิดพลาด
Joe Eifert

1
สิ่งนี้จะไม่ได้ผลหากคุณเลือกเดือนที่ไม่ใช่ 30 วัน
dima

2
วิธีนี้ไม่แม่นยำนัก
พเนจร

9

คุณสามารถเรียบเรียงคำถามใหม่ว่า "มีวันแรกกี่วันระหว่างวันที่เริ่มต้นของเดือน" แล้วใช้การแปลงข้อมูลรูปแบบการทำงาน:

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

และหากต้องการกลับไปที่คำถามเดิมคุณสามารถสรุปจำนวนวัน (เช่นที่คุณทำกับคำถามแรก) และหาค่าเฉลี่ยของผลรวม
Joe Eifert

9

สมมติว่าทั้งสองเป็นวันที่: ((date2 - date1).to_f / 365 * 12).round ง่าย


ทางออกที่ดีมาก! สะอาดเรียบง่ายและใช้งานได้ตลอดหลายปีเช่นช่วงเดือนระหว่างกุมภาพันธ์ 2018 ถึงธันวาคม 2017
jeffdill2

1
ต้องใช้เวลาพิจารณาชั่วโมงนาทีและวินาที ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
scarver2

1
@ scarver2 จำนวนที่คุณได้รับจากการคำนวณของคุณเป็นทางออก สิ่งที่เรากำลังทำคือใช้เวลาหลายวันและแปลงเป็นเดือนมันไม่แม่นยำอย่างยิ่งเพราะมันใช้เวลา 30.4167 วันต่อเดือน แต่มันใกล้มากแล้วมันก็วนไปเรื่อย ๆ
Andreykul


2

อีกวิธีหนึ่งที่ฉันพบ (สร้างขึ้นจากโซลูชันที่โพสต์ไว้ที่นี่แล้ว) คือถ้าคุณต้องการให้ผลลัพธ์รวมเศษส่วนของเดือน 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
ลอง raplacing กับพื้นถ้าคุณต้องการแสดงเฉพาะเดือนที่ผ่านไปจริง
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 จะมีคำอธิบายเกี่ยวกับสิ่งที่โค้ดทำและเหตุใดจึงทำงานเป็นโซลูชัน
Single Entity

1

ฉันต้องการจำนวนเดือนที่แน่นอน (รวมทศนิยม) ระหว่างวันที่สองวันและเขียนวิธีการต่อไปนี้

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

ถ้าเปรียบเทียบสมมุติว่า 26 กันยายนถึง 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

btw อาศัย 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

นี่เป็นอีกวิธีหนึ่ง ซึ่งจะช่วยในการคำนวณจำนวนทั้งเดือนระหว่างวันที่สองวัน

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.