2009-06-30 33 views
12

Trong dự án Rails, tôi muốn tìm sự khác biệt giữa hai ngày và sau đó hiển thị nó bằng ngôn ngữ tự nhiên. Một cái gì đó nhưTrong Rails, thời gian hiển thị giữa hai ngày bằng tiếng Anh

>> (date1 - date2).to_natural_language 
"3 years, 2 months, 1 week, 6 days" 

Về cơ bản this cho ruby.

Google và API Rails chưa bật lên bất kỳ thứ gì. Tôi đã tìm thấy một số điều sẽ cho bạn sự khác biệt trong một đơn vị (ví dụ, bao nhiêu tuần giữa hai ngày) nhưng không phải cái gì đó sẽ tính toán chính xác năm, tháng, tuần, ngày tất cả cùng nhau. ActionView mô-đun

Trả lời

20

Những câu trả lời khác có thể không cung cấp cho các loại đầu ra mà bạn đang tìm kiếm, bởi vì thay vì đưa ra một chuỗi năm, tháng, v.v. ông Rails người giúp đỡ chỉ hiển thị các đơn vị lớn nhất. Nếu bạn đang tìm kiếm thứ gì đó bị hỏng, đây là một tùy chọn khác. Dính vào phương pháp này thành một helper:

def time_diff_in_natural_language(from_time, to_time) 
    from_time = from_time.to_time if from_time.respond_to?(:to_time) 
    to_time = to_time.to_time if to_time.respond_to?(:to_time) 
    distance_in_seconds = ((to_time - from_time).abs).round 
    components = [] 

    %w(year month week day).each do |interval| 
    # For each interval type, if the amount of time remaining is greater than 
    # one unit, calculate how many units fit into the remaining time. 
    if distance_in_seconds >= 1.send(interval) 
     delta = (distance_in_seconds/1.send(interval)).floor 
     distance_in_seconds -= delta.send(interval) 
     components << pluralize(delta, interval) 
    end 
    end 

    components.join(", ") 
end 

Và rồi trong một lần xem bạn có thể nói cái gì đó như:

<%= time_diff_in_natural_language(Time.now, 2.5.years.ago) %> 
=> 2 years, 6 months, 2 days 

Phương pháp đưa ra chỉ đi xuống ngày, nhưng có thể dễ dàng mở rộng thêm trong nhỏ đơn vị nếu muốn.

+0

Điều này có vẻ thực sự hứa hẹn. Thật không may tôi là một nhận được "undefined phương pháp' pluralize 'cho # > "lỗi (trong giao diện điều khiển). –

+0

Đó là vì đa nguyên là một phương thức trợ giúp ActionView: http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html. Nếu bạn nói 'bao gồm ActionView :: Helpers :: TextHelper' trong script/console, số nhiều sẽ được định nghĩa.Như đã đề cập trong câu trả lời, bạn nên gắn phương thức trong trình trợ giúp xem (trong ứng dụng/người trợ giúp) và sau đó tham chiếu đến nó từ một khung nhìn. –

2
+0

Điều này thực sự tốt (và tôi bực mình trước đây tôi không tìm thấy), nhưng nó vẫn chỉ mang lại cho tôi một xấp xỉ thô. Tức là, nó sẽ cho tôi "3 tháng", không phải "3 tháng, 4 ngày". –

3

distance_of_time_in_words là chính xác nhất ở đây. Câu trả lời của Daniel là hành động sai lầm: 2.5 năm trước nên sản xuất chính xác 2 năm, 6 tháng. Vấn đề là tháng chứa 28-31 ngày, và năm có thể là bước nhảy vọt.

Tôi ước gì tôi biết làm thế nào để sửa lỗi này :(

7

tôi đã cố gắng Daniel's solution và tìm thấy một số kết quả không chính xác trong một vài trường hợp thử nghiệm, do thực tế rằng nó không xử lý một cách chính xác số lượng biến của ngày tìm thấy trong tháng:

> 30.days < 1.month 
    => false 

vì vậy, ví dụ:

> d1 = DateTime.civil(2011,4,4) 
> d2 = d1 + 1.year + 5.months 
> time_diff_in_natural_language(d1,d2) 
=> "1 year, 5 months, 3 days"

sau đây sẽ cung cấp cho bạn chính xác số {năm, tháng, ngày, giờ, phút, giây}:

def time_diff(from_time, to_time) 
    %w(year month day hour minute second).map do |interval| 
    distance_in_seconds = (to_time.to_i - from_time.to_i).round(1) 
    delta = (distance_in_seconds/1.send(interval)).floor 
    delta -= 1 if from_time + delta.send(interval) > to_time 
    from_time += delta.send(interval) 
    delta 
    end 
end 
> time_diff(d1,d2) 
=> [1, 5, 0, 0, 0, 0]

0
def date_diff_in_natural_language(date_from, date_to) 
    components = [] 
    %w(years months days).each do |interval_name| 
    interval = 1.send(interval_name) 
    count_intervals = 0 
    while date_from + interval <= date_to 
     date_from += interval 
     count_intervals += 1 
    end 
    components << pluralize(count_intervals, interval_name) if count_intervals > 0 
    end 
    components.join(', ') 
end 
Các vấn đề liên quan