【问题标题】:Is there a more concise way to combine many comparisons in Ruby?有没有更简洁的方法来组合 Ruby 中的许多比较?
【发布时间】:2010-12-02 12:22:43
【问题描述】:

我目前有这个 if 语句:

if Time.now.day == 1 and Time.now.hour == 0 and Time.now.minute == 0 and Time.now.second == 0

有没有更简洁的方法来做到这一点?

【问题讨论】:

  • 顺便说一句,Time.now 每次调用时不会给你一个新的当前时间吗?首先将 Time.now 设置为局部变量,然后在 if 语句中使用它不是更好吗?我想这取决于你真正想要什么......
  • 它将返回不同的值,只是它们会相差很小的一秒。从理论上讲,时间可能会从 00:00:00 转换到 00:00:01。在 IRB 中试试这个:5.times { puts Time.now.to_f } 以了解测试条件的速度。

标签: ruby comparison if-statement


【解决方案1】:

您可以使用Time#to_a 将您的时间转换为数组(秒、分、时、日、月、年、wday、yday、isdst、zone):

Time.now.to_a  # => [20, 57, 16, 30, 11, 2010, 2, 334, false, "CET"]

然后只切掉你想要匹配的部分:

Time.now.to_a[0,4]  # => [20, 57, 16, 30]

然后您的特定检查可以像这样简洁:

if Time.now.to_a[0,4] == [0,0,0,1]

【讨论】:

    【解决方案2】:
    [:day,:hour,:minute,:second].map{|s|Time.now.send s}==[1,0,0,0]
    

    【讨论】:

    • @Jergason:你什么意思?这是惯用的 Ruby。
    • 困扰我的是{|s|Time.now.send s}。看来您应该能够消除s 点。
    • 你可以做 [...].map(&Time.now.method(:send))==[...]。计算一次时间有隐藏的好处。
    【解决方案3】:

    标准的 Ruby Time 库非常空闲,所以我只需添加自己的方法来简化此操作:

    class Time
      def beginning_of_month
        Time.local(self.year, self.month, 1)
      end
    
      def beginning_of_month?
        self == beginning_of_month
      end
    end
    

    所以你可以写:

    if Time.now.beginning_of_month?
    

    【讨论】:

    • 我也没有在标准文档上看到更改方法ruby-doc.org/core/classes/Time.html
    • 对不起,我不小心删除了我之前的评论。原始评论是(有点类似于):我运行它时看不到它工作。你用的是什么版本的红宝石?我的是1.8.7。运行时,它吐出这个错误: undefined method `change' for Tue Nov 30 16:07:18 +1100 2010:Time (NoMethodError)
    • @tim_wonil 你是对的,我认为我的 irb 在我不知情的情况下正在积极支持。
    【解决方案4】:

    怎么样?

    Time.now.strftime('%d %H:%M:%S') == '01 00:00:00'
    

    我喜欢这个,因为它非常自我记录;很明显,您是在与某天的午夜进行比较。

    说明:strftime() 方法可以轻松输出自定义日期和/或时间字符串。此格式输出月份中的日期、小时、分钟和秒。

    Time.now.strftime('%d %H:%M:%S') #=> "01 16:54:24"
    

    【讨论】:

      【解决方案5】:

      您可以将其与您创建的时间进行比较:

      if Time.now == Time.at(0)
      

      if Time.now == Time.utc(2000,"jan",1,20,15,1)
      

      【讨论】:

        【解决方案6】:

        我猜您正在尝试制作类似于cron 的东西,即您处于无限循环中并检查是否到了执行某些操作的时间。

        如果是这种情况,我认为您不应该相信您的时间戳检查将恰好落在一天的第一秒。如果延迟(出于任何原因)会发生什么,首先它在23:59:59 上触发,下一个循环发生在00:00:01 而不是:00 上?您将无法执行任何所需的操作。

        此外,您还需要包含一些 sleep,这样您的空循环就不会在等待时消耗您的所有资源。

        您可以改为保留最后一个操作时间戳,并将now 与下一个操作时间戳进行比较,如果now >= next_timestamp 则执行该操作。比如:

        last_action_on = Time.at(0)
        loop do
          now = Time.now
          next_action_on = Time.local(now.year, now.month, 1) # beginning of the current day
          if last_action_on < next_action_on && now >= next_action_on
            last_action_on = now
            do_action
          end
          sleep 1
        end
        

        【讨论】:

          【解决方案7】:
           %w(day==1 hour==0 minute==0 second==0).all? { |e| eval "Time.now.#{e}" }
          

          【讨论】:

            猜你喜欢
            • 2013-07-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-01
            相关资源
            最近更新 更多