2009-12-14 58 views
14

Câu hỏi này là ở đây cho các ngôn ngữ khác, vì vậy hãy để đây là một cho Ruby.Làm thế nào để tính toán bao nhiêu năm trôi qua kể từ một ngày nhất định trong Ruby?

Làm cách nào để tính số năm hoàn thành đã trôi qua từ một ngày nhất định? Như bạn có thể đã đoán, đó là để tự động tính tuổi của người đó. Gần nhất một là distance_of_time_in_words Rails helper, vì vậy mẫu sau

Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old. 

mang

Jack is over 59 years old. 

Nhưng tôi cần chức năng chính xác hơn giúp tạo ra chỉ số. Có cái nào không?

Nếu có một số chức năng trợ giúp của Ruby on Rails cho điều này, điều này là OK, mặc dù giải pháp Ruby thuần túy sẽ tốt hơn.

Chỉnh sửa: ý chính của câu hỏi là cần có giải pháp không gần đúng. Tại số 2 nd của tháng 3 Jack phải là 59 tuổi và ngày hôm sau anh ta phải 60 tuổi. Leap năm và như vậy nên được đưa vào tài khoản.

Trả lời

37

Bạn có muốn tuổi như mọi người thường hiểu nó, hoặc bạn đang tìm kiếm một biện pháp chính xác của thời gian trôi qua? Nếu trước đây, không cần phải lo lắng về những năm nhuận và những biến chứng khác. Bạn chỉ cần tính toán một sự khác biệt trong năm và giảm nó nếu người đó đã không có một sinh nhật nào trong năm nay. Nếu sau này, bạn có thể chuyển đổi giây trôi qua thành năm, như các câu trả lời khác đã đề xuất.

def age_in_completed_years (bd, d) 
    # Difference in years, less one if you have not had a birthday this year. 
    a = d.year - bd.year 
    a = a - 1 if (
     bd.month > d.month or 
     (bd.month >= d.month and bd.day > d.day) 
    ) 
    a 
end 

birthdate = Date.new(2000, 12, 15) 
today  = Date.new(2009, 12, 14) 

puts age_in_completed_years(birthdate, today) 
+1

Có vẻ như không có bạn chỉ trả lời câu hỏi, mà còn xây dựng câu hỏi theo cách tốt hơn :-) –

+1

+1, nhưng nếu tôi được sinh ra, hãy nói Date.new (1980, 2, 29)? ;-) –

+1

@Mike Bummer - không sinh nhật cho bạn. Điểm tốt. Sửa mã. – FMc

4
require 'date' 

def years_since(dt) 
    delta = (Date.today - Date.parse(dt))/365 
    delta.to_i 
end 
0

Làm thế nào về một cái gì đó như:

def years_diff(from_time,to_time) 
    (((to_time - from_time).abs)/ (365 * 24 * 60 * 60)).to_i 
end 

years_diff(Time.now,Time.local(1950,03,22)) #=> 59 
years_diff(Time.now,Time.local(2009,03,22)) #=> 0 
years_diff(Time.now,Time.local(2008,03,22)) #=> 1 
+1

này sẽ không xảy ra để làm việc khi ngày hiện tại là gần sinh nhật (năm nhuận!), và đối với một người trên 1460 tuổi, nó sẽ mang lại nhiều lỗi ngày càng tăng. –

5

Tôi có một viên ngọc/plugin gọi dotiw mà có một distance_of_time_in_words_hash rằng sẽ trả về một băm như: { :years => 59, :months => 11, :days => 27 }. Từ đó bạn có thể làm việc ra nếu nó gần một giới hạn nhất định.

1

Ý tưởng tương tự như FM nhưng với tuyên bố nếu được đơn giản hóa. Rõ ràng, bạn có thể thêm đối số thứ hai thay vì sử dụng thời gian hiện tại.

def age(birthdate) 
    now = DateTime.now 
    age = now.year - birthdate.year 
    age -= 1 if(now.yday < birthdate.yday) 
    age 
end 
+1

' yday' là một funciton thú vị, cảm ơn. Thật không may, nó sẽ xử lý năm nhuận khác nhau, nếu người được sinh ra muộn hơn trong tháng hai. –

+0

đồng ý với Pavel. 'yday' không hữu ích cho việc so sánh các ngày kéo dài nhiều năm vì năm nhuận. –

1

Tôi nghĩ rằng đây sẽ luôn luôn làm việc, ngay cả đối với một người nào đó với một sinh nhật gần một ngày bước nhảy vọt:

require 'date' 

def calculate_age(start_date, end_date) 
    end_date.year - start_date.year - ((end_date.month > start_date.month || (end_date.month == start_date.month && end_date.day >= start_date.day)) ? 0 : 1) 
end 

puts calculate_age(Date.strptime('03/02/1968', '%m/%d/%Y'), Date.strptime('03/02/2010', '%m/%d/%Y')) 

Độ tuổi tính toán với phương pháp này trong ví dụ cuộc gọi trên là 42, đó là chính xác mặc dù Năm 1968 là một năm nhuận và ngày sinh nhật gần một ngày nhuận.

Ngoài ra, cách này không cần phải tạo biến cục bộ.

4

Một cách tiếp cận để xử lý năm nhuận

Bất cứ khi nào bạn đang tính năm trôi qua kể từ khi một ngày, bạn phải quyết định làm thế nào để xử lý các bước nhảy vọt năm. Đây là cách tiếp cận của tôi, mà tôi nghĩ là rất dễ đọc, và có thể mất nhiều năm trong bước tiến mà không sử dụng bất kỳ "trường hợp đặc biệt" logic.

def years_completed_since(start_date, end_date) 

    if end_date < start_date 
    raise ArgumentError.new(
     "End date supplied (#{end_date}) is before start date (#{start_date})" 
    ) 
    end 

    years_completed = end_date.year - start_date.year 

    unless reached_anniversary_in_year_of(start_date, end_date) 
    years_completed -= 1 
    end 

    years_completed 
end 

# No special logic required for leap day; its anniversary in a non-leap 
# year is considered to have been reached on March 1. 
def reached_anniversary_in_year_of(original_date, new_date) 
    if new_date.month == original_date.month 
    new_date.day >= original_date.day 
    else 
    new_date.month > original_date.month 
    end 
end 
0

Làm thế nào về điều này:

def age_in_years(date) 
    # Difference in years, less one if you have not had a birthday this year. 
    today = Date.today 
    age = today.year - date.year 
    age = age - 1 if [date.day, date.month, today.year].join('/').to_date > Date.today 
end 
2

bạn có thể sử dụng đá quý ruby ​​adroit-age

Nó hoạt động cho năm nhuận cũng ..

age = AdroitAge.find_age("23/01/1990") 

Cập nhật

require 'adroit-age' 

dob = Date.new(1990,1,23) 
or 
dob = "23/01/1990".to_date 

age = dob.find_age 
#=> 23 
0

d2.year - d1.year - (d2.month > d1.month || (d2.month == d1.month && d2.day >= d1.day) ? 0 : 1)

+0

Chào mừng bạn đến với SO! Hãy cố gắng cung cấp một số giải thích với câu trả lời của bạn. – codeMagic

1

tôi đã đưa ra những điều sau đây, dựa trên một lập luận tương tự như @FMc Thứ nhất, tính toán diff giữa năm nay và năm sinh nhật của. Sau đó, tổng hợp nó vào sinh nhật và kiểm tra ngày kết quả: nếu nó lớn hơn ngày hôm nay, giảm diff bởi 1. Để được sử dụng trong các ứng dụng Rails vì nó phụ thuộc vào phương pháp yearsActiveSupport 's

def age(birthday, today) 
    diff = today.year - birthday.year 
    (birthday + diff.years > today) ? (diff - 1) : diff 
end 
Các vấn đề liên quan