如何使用 ruby​​ on rails 生成人类可读的时间范围

     2023-02-22     143

关键词:

【中文标题】如何使用 ruby​​ on rails 生成人类可读的时间范围【英文标题】:How to generate a human readable time range using ruby on rails 【发布时间】:2011-05-07 09:07:53 【问题描述】:

我正在尝试找到生成以下输出的最佳方法

<name> job took 30 seconds
<name> job took 1 minute and 20 seconds
<name> job took 30 minutes and 1 second
<name> job took 3 hours and 2 minutes

我开始这段代码

def time_range_details
  time = (self.created_at..self.updated_at).count
  sync_time = case time 
    when 0..60 then "#time secs"       
    else "#time/60 minunte(s) and #time-min*60 seconds"
  end
end

有没有更有效的方法来做到这一点。对于一些超级简单的事情,似乎有很多冗余代码。

另一个用途是:

<title> was posted 20 seconds ago
<title> was posted 2 hours ago

此代码类似,但我使用 Time.now:

def time_since_posted
  time = (self.created_at..Time.now).count
  ...
  ...
end

【问题讨论】:

【参考方案1】:

如果您需要比distance_of_time_in_words 更“精确”的内容,您可以按照以下方式编写内容:

def humanize(secs)
  [[60, :seconds], [60, :minutes], [24, :hours], [Float::INFINITY, :days]].map |count, name|
    if secs > 0
      secs, n = secs.divmod(count)

      "#n.to_i #name" unless n.to_i==0
    end
  .compact.reverse.join(' ')
end

p humanize 1234
#=>"20 minutes 34 seconds"
p humanize 12345
#=>"3 hours 25 minutes 45 seconds"
p humanize 123456
#=>"1 days 10 hours 17 minutes 36 seconds"
p humanize(Time.now - Time.local(2010,11,5))
#=>"4 days 18 hours 24 minutes 7 seconds"

哦,对你的代码有一点评论:

(self.created_at..self.updated_at).count

真的是获得差异的糟糕方法。简单使用:

self.updated_at - self.created_at

【讨论】:

只是好奇,为什么不好? (self.created_at..self.updated_at).count 感谢您的干净回答! @csanz: .count 在这种情况下会遍历两个时间戳之间的每秒数组并计算它们。好像你会通过实际计算 50 到 100 之间的所有数字来计算表达式 100-50 的结果。 我更喜欢 DateHelper 方法。如果您要费心将其转换为英语,那么您可能不想结合天数和秒数。这是一种人为的精确度。 正确,但主要取决于上下文。例如,我需要类似的东西来显示表格中每个项目的持续时间。我首先尝试了 DateHelper,但后来将其替换为自定义方法,该方法打印类似 5:30:25,rigt 对齐的内容。表格数据比 DH 中的“模糊”表达式更具可读性。 这段代码很棒,但如果超过 1,000 天(86_400_000 秒),它就不起作用。 humanize(86_400_001) =&gt; "0 days 0 hours 0 minutes 1 seconds" 是错误的。可以通过将数组的最后一个元素更新为 [Float::INFINITY, :days] 来修复此错误。【参考方案2】:

DateHelper 中有两种方法可以满足您的需求:

    time_ago_in_words

    time_ago_in_words( 1234.seconds.from_now ) #=> "21 minutes"
    
    time_ago_in_words( 12345.seconds.ago )     #=> "about 3 hours"
    

    distance_of_time_in_words

    distance_of_time_in_words( Time.now, 1234.seconds.from_now ) #=> "21 minutes"
    
    distance_of_time_in_words( Time.now, 12345.seconds.ago )     #=> "about 3 hours"
    

【讨论】:

请注意,distance_of_time_in_words 支持 i18n 并具有双重接口:它可以直接用于持续时间:distance_of_time_in_words(6270.873) #=&gt; environ 2 heures(法语)【参考方案3】:

chronic_duration 将数字时间解析为可读,反之亦然

【讨论】:

【参考方案4】:

如果您想在秒到天的范围内显示重要的持续时间,另一种选择是(因为它不必表现最好):

def human_duration(secs, significant_only = true)
  n = secs.round
  parts = [60, 60, 24, 0].map|d| next n if d.zero?; n, r = n.divmod d; r.
    reverse.zip(%w(d h m s)).drop_while|n, u| n.zero? 
  if significant_only
    parts = parts[0..1] # no rounding, sorry
    parts << '0' if parts.empty?
  end
  parts.flatten.join
end
start = Time.now
# perform job
puts "Elapsed time: #human_duration(Time.now - start)"

human_duration(0.3) == '0'
human_duration(0.5) == '1s'
human_duration(60) == '1m0s'
human_duration(4200) == '1h10m'
human_duration(3600*24) == '1d0h'
human_duration(3600*24 + 3*60*60) == '1d3h'
human_duration(3600*24 + 3*60*60 + 59*60) == '1d3h' # simple code, doesn't round
human_duration(3600*24 + 3*60*60 + 59*60, false) == '1d3h59m0s'

或者,您可能只对在无关紧要的情况下剥离秒部分感兴趣(也演示了另一种方法):

def human_duration(duration_in_seconds)
  n = duration_in_seconds.round
  parts = []
  [60, 60, 24].each|d| n, r = n.divmod d; parts << r; break if n.zero?
  parts << n unless n.zero?
  pairs = parts.reverse.zip(%w(d h m s)[-parts.size..-1])
  pairs.pop if pairs.size > 2 # do not report seconds when irrelevant
  pairs.flatten.join
end

希望对您有所帮助。

【讨论】:

【参考方案5】:

distance_of_time_in_words 有问题,如果您通过那里1 小时 30 分钟它将返回 大约 2 小时

只需添加助手:

 PERIODS = 
   'day' => 86400,
   'hour' => 3600,
   'minute' => 60
   


def formatted_time(total)
  return 'now' if total.zero?

  PERIODS.map do |name, span|
    next if span > total
    amount, total = total.divmod(span)
    pluralize(amount, name)
  end.compact.to_sentence
end

基本上只需几秒钟即可传递您的数据。

【讨论】:

【参考方案6】:

Rails 有一个DateHelper 用于查看。如果这不是您想要的,您可能需要自己编写。

@Mladen Jablanović 有一个很好的示例代码的答案。但是,如果您不介意继续自定义人性化示例方法,这可能是一个很好的起点。

def humanized_array_secs(sec)
  [[60, 'minutes '], [60, 'hours '], [24, 'days ']].inject([[sec, 'seconds']]) do |ary, (count, next_name)|
    div, prev_name = ary.pop

    quot, remain = div.divmod(count)
    ary.push([remain, prev_name])
    ary.push([quot, next_name])
    ary
  end.reverse
end

这为您提供了一个可以操作的值和单位名称数组。

如果第一个元素不为零,则为天数。您可能希望编写代码来处理多天,例如显示周、月和年。否则,剪掉前面的 0 值,并取接下来的两个。

def humanized_secs(sec)
  return 'now' if 1 > sec

  humanized_array = humanized_array_secs(sec.to_i)
  days = humanized_array[-1][0]
  case
    when 366 <= days
      "#days / 365 years"
    when 31 <= days
      "#days / 31 months"
    when 7 <= days
      "#days / 7 weeks"
    else
      while humanized_array.any? && (0 == humanized_array[-1][0])
        humanized_array.pop
      end
      humanized_array.reverse[0..1].flatten.join
  end
end

该代码甚至可以用于 ruby​​ while 语句。

【讨论】:

如何在 Ruby on Rails 4 中为 post 生成唯一的随机 id?

】如何在RubyonRails4中为post生成唯一的随机id?【英文标题】:HowtogenerateauniquerandomidforpostinRubyonRails4?【发布时间】:2016-03-2611:15:23【问题描述】:我想为我的博客应用程序中的帖子生成唯一的帖子标识符。目前我正在使用SecureRand... 查看详情

如何在 ruby​​-on-rails 应用程序上使用 Rack 发送 POST 模拟请求?

】如何在ruby​​-on-rails应用程序上使用Rack发送POST模拟请求?【英文标题】:HowcanIsendaPOSTmockrequestwithRackonaruby-on-railsapplication?【发布时间】:2022-01-2011:29:59【问题描述】:我正在测量一个Rails博客应用程序的各个方面所花费的时... 查看详情

如何在 Ruby-on-Rails 中生成 PDF 表单

】如何在Ruby-on-Rails中生成PDF表单【英文标题】:HowtogeneratePDFformsinRuby-on-Rails【发布时间】:2013-05-2721:04:41【问题描述】:我想使用RubyonRails生成带有单选按钮和提交按钮的PDF表单。有谁知道是否有宝石可以帮助完成这项任务?我... 查看详情

如何在 Ruby on Rails 中查看给定 ActiveRecord 查询将生成的 SQL

】如何在RubyonRails中查看给定ActiveRecord查询将生成的SQL【英文标题】:HowcanIseetheSQLthatwillbegeneratedbyagivenActiveRecordqueryinRubyonRails【发布时间】:2010-11-2313:46:31【问题描述】:我想查看给定ActiveRecord查询将生成的SQL语句。我承认我可... 查看详情

如何在 ruby​​ on rails 中为 gmail 联系人创建访问令牌

】如何在ruby​​onrails中为gmail联系人创建访问令牌【英文标题】:Howtogetcreateanaccesstokeninrubyonrailsforgmailcontacts【发布时间】:2011-11-2120:44:22【问题描述】:我正在使用Omniauth请求用户gmail凭据,因此我可以稍后请求用户朋友/联系... 查看详情

通过单击 Ruby on Rails 中的按钮生成表单

...,并且他们应该在填写多个表格后只提交一次。我不确定如何在r 查看详情

Ruby on Rails 如何使用 yield 进行布局?

】RubyonRails如何使用yield进行布局?【英文标题】:HowdoesRubyonRailsuseyieldforlayouts?【发布时间】:2011-06-1822:08:14【问题描述】:yield用于调用块。这在yield用于布局的Rails中如何工作?-#application.html.haml%body=yield它是在某处使用块还是... 查看详情

Ruby on Rails - 如何在 Rails 方法中使用 HTML 坐标?

】RubyonRails-如何在Rails方法中使用HTML坐标?【英文标题】:RubyonRails-HowtoUseHTMLCoordinatesinaRailsMethod?【发布时间】:2015-09-0808:08:14【问题描述】:感谢愿意回答我的人。我有一个方法,目前像post.distance_to([current_user.latitude,current_user... 查看详情

CoffeeScript - 如何在 ruby​​ on rails 中使用咖啡脚本?

】CoffeeScript-如何在ruby​​onrails中使用咖啡脚本?【英文标题】:CoffeeScript-Howtoworkwithcoffeescriptinrubyonrails?【发布时间】:2019-05-0207:06:06【问题描述】:我正在使用Rubyonrails中的CoffeeScript。我正在使用http://js2.coffee/将我的javascript... 查看详情

链接从“rails generate Scaffold”生成的两个表(Ruby on Rails 的新手)

...某人的教育信息、地址等信息保存到数据库表中。如果我使用Scaffold生成PersonTable( 查看详情

如何使用 Ruby on Rails 解析 JSON? [复制]

】如何使用RubyonRails解析JSON?[复制]【英文标题】:HowdoIparseJSONwithRubyonRails?[duplicate]【发布时间】:2010-12-2201:18:36【问题描述】:我正在寻找一种简单的方法来解析JSON,提取一个值并将其写入Rails中的数据库。具体来说,我正在... 查看详情

如何将 HSQLDB 与 Ruby on Rails 一起使用。

】如何将HSQLDB与RubyonRails一起使用。【英文标题】:HowcanIuseHSQLDBwithRubyonRails.【发布时间】:2010-12-2004:38:12【问题描述】:我想在Rails上使用带有Rubey的新数据库。那个数据库是HSQLDB。如何使用?【问题讨论】:【参考方案1】:最... 查看详情

如何使用 docker(ruby on rails)设置 anycable?

】如何使用docker(rubyonrails)设置anycable?【英文标题】:Howtosetupanycablewithdocker(rubyonrails)?【发布时间】:2021-04-0523:49:20【问题描述】:如何在docker上设置anycable(actioncable)端口?这是我的AnycableDockerfile来自红宝石:2.6.3-alpine3.10WORK... 查看详情

Ruby on Rails 使用视图助手中的变量在视图中动态生成字段名称

】RubyonRails使用视图助手中的变量在视图中动态生成字段名称【英文标题】:RubyonRailsDynamicallygeneratefieldnameinviewusingvariablefromviewhelper【发布时间】:2012-06-1700:30:08【问题描述】:在我看来,假设我有这样的事情:<%=f.text_field:nam... 查看详情

使用 Ruby on Rails 时如何创建 Facebook 共享功能?

】使用RubyonRails时如何创建Facebook共享功能?【英文标题】:HowtocreatefacebooksharingfunctionalitywhenusingRubyonRails?【发布时间】:2017-08-2301:17:50【问题描述】:我正在使用RubyonRails,并且正在尝试为网页创建facebook共享功能。在共享调试... 查看详情

如何注销 Facebook - 在 Rails 应用程序中使用代码(Ruby on Rails Omniauth)

】如何注销Facebook-在Rails应用程序中使用代码(RubyonRailsOmniauth)【英文标题】:Howtologoutfacebook-usingcodeinrailsapplication(RubyonRailsOmniauth)【发布时间】:2012-09-1614:24:36【问题描述】:我尝试通过rails中的omniauth从我的页面添加多个twitte... 查看详情

如何使用 Ruby on Rails 发出 HTTP 请求?

】如何使用RubyonRails发出HTTP请求?【英文标题】:HowtomakeaHTTPrequestusingRubyonRails?【发布时间】:2011-06-0215:18:10【问题描述】:我想从另一个网站获取信息。因此(也许)我应该向该网站发出请求(在我的情况下是HTTPGET请求)并接... 查看详情

如何使用 Ruby on Rails 发出 HTTP 请求?

】如何使用RubyonRails发出HTTP请求?【英文标题】:HowtomakeaHTTPrequestusingRubyonRails?【发布时间】:2011-06-0215:18:10【问题描述】:我想从另一个网站获取信息。因此(也许)我应该向该网站发出请求(在我的情况下是HTTPGET请求)并接... 查看详情