简体   繁体   English

Rails 发现两个日期之间的差异

[英]Rails find difference between two dates

I want to calculate how long the user has been a member of my app.我想计算用户成为我的应用程序成员的时间。 I should display it as:我应该将其显示为:

User member for 2y, 9m

To do so I've created method inside of User model为此,我在用户 model 内部创建了方法

  def member_for
    #calculate number of months
    month = (Time.current.year * 12 + Time.current.month) - (created_at.year * 12 + created_at.month)
    #an array [years, months]
    result = month.divmod(12)

    if result[0].zero? && result[1].nonzero?
      "User member for #{result[1]}m"
    elsif result[1].zero? && result[0].nonzero?
      "User member for #{result[0]}y"
    elsif result[0].zero? && result[1].zero?
      'User member for 1m'
    else
      "User member for #{result[0]}y, #{result[1]}m"
    end
  end

But honestly this code smells, isn't there some built-in method in Rails6 to do this better and make the code look a little cleaner?但老实说这段代码有异味,难道 Rails6 中没有一些内置方法可以更好地做到这一点,让代码看起来更干净一些吗?

You can use ActiveSupport::Duration for this.您可以为此使用ActiveSupport::Duration All you need to do is pass the time difference to the ActiveSupport::Duration.build method.您需要做的就是将时间差传递给ActiveSupport::Duration.build方法。 For example:例如:

time_diff = Time.now - 1000.days.ago
ActiveSupport::Duration.build(time_diff.to_i)         # 2 years, 8 months, 3 weeks, 5 days, 28 minutes, and 47 seconds 
ActiveSupport::Duration.build(time_diff.to_i).parts   # 2 years, 8 months, 3 weeks, 5 days, 28 minutes, and 47 seconds 

If you want to avoid the caching / timezone headaches involved with distance_of_time_in_words * which will essentially invalidate your cached responses/fragments continously then just output a HTML5 time element and use a JS library like moment.js to calculate the elapsed time and display it to the user:如果您想避免与distance_of_time_in_words * 相关的缓存/时区头痛,这将基本上使您的缓存响应/片段持续无效,那么只需 output 一个 HTML5 时间元素并使用像moment.js这样的 JS 库来计算经过的时间并显示它用户:

module TimeHelper
  def time_tag(date_or_time, **options)
    tag.time(datetime: date_or_time.iso8601, **options)
  end
end
$ yarn install moment
// app/javascripts/packs/application.js
require('moment');
<% @users.each do |user| %>
  <p><%= time_tag(user.created_at, class: 'member-since') %></p>
<% end %>

 document.querySelectorAll('time.member-since').forEach((el) => { const m = moment(el.dateTime); const str = `User has been a member for ${m.toNow(true)}`; const textnode = document.createTextNode(str); el.appendChild(textnode); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script> <p><time datetime="2001-05-15T19:00" class="member-since" /></p> <p><time datetime="2005-05-15T09:00" class="member-since" /></p> <p><time datetime="2021-04-15T09:00" class="member-since" /></p>

See Difference between two dates in years, months, days in JavaScript for alternatives to moment.js.有关moment.js 的替代方案,请参阅 JavaScript 中两个日期的年、月、日之间的差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM