首页 文章

Ruby中DateTime和Time之间的区别

提问于
浏览
206

Ruby中的 DateTimeTime 类之间有什么区别?哪些因素会导致我选择其中一个?

7 回答

  • 43

    较新版本的Ruby(2.0)在两个类之间并没有真正的显着差异 . 由于历史原因,一些图书馆将使用其中一个,但新代码不一定需要关注 . 选择一个以保持一致性可能是最好的,因此请尝试与您的库所期望的相匹配 . 例如,ActiveRecord更喜欢DateTime .

    在Ruby 1.9之前的版本中以及许多系统上,Time表示为一个32位有符号值,描述自1970年1月1日UTC以来的秒数,这是一个围绕POSIX标准 time_t 值的薄包装,并且有界:

    Time.at(0x7FFFFFFF)
    # => Mon Jan 18 22:14:07 -0500 2038
    Time.at(-0x7FFFFFFF)
    # => Fri Dec 13 15:45:53 -0500 1901
    

    较新版本的Ruby能够处理更大的值而不会产生错误 .

    DateTime是一种基于日历的方法,其中单独存储年,月,日,小时,分钟和秒 . 这是一个Ruby on Rails构造,用作SQL标准DATETIME字段的包装器 . 这些包含任意日期,几乎可以表示任何时间点,因为表达范围通常非常大 .

    DateTime.new
    # => Mon, 01 Jan -4712 00:00:00 +0000
    

    因此,令人放心的是,DateTime可以处理来自亚里士多德的博客文章 .

    选择一个时,差异在某种程度上是主观的 . 从历史上看,DateTime提供了以日历方式操作它的更好选项,但是其中许多方法也已移植到Time,至少在Rails环境中 .

  • 4

    [编辑2018年7月]

    以下所有内容在Ruby 2.5.1中仍然适用 . 来自reference documentation

    DateTime不考虑任何闰秒,不跟踪任何夏令时规则 .

    之前在这个帖子中没有注意到的是 DateTime 的几个优点之一:它知道日历改革而 Time 不是:

    [...] Ruby的Time类实现了一个公历格式,并没有日历改革的概念[...] .

    参考文件最后建议在专门处理近期,当前或未来的日期/时间时使用 Time 并且仅在使用 DateTime 时,例如莎士比亚的生日需要准确转换:(强调添加)

    那么什么时候应该在Ruby中使用DateTime以及何时使用Time?几乎可以肯定你会想要使用Time,因为你的应用可能正在处理当前的日期和时间 . 但是,如果您需要在历史上下文中处理日期和时间,则需要使用DateTime [...] . 如果你还需要处理时区,那么祝你好运 - 请记住,你可能会处理当地的太阳时代,因为直到19世纪铁路的引入才需要标准时间并最终时区 .

    [/编辑2018年7月]

    从ruby 2.0开始,其他答案中的大部分信息都已过时 .

    特别是, Time 现在几乎没有绑定 . 它可以比Epoch更多或更少甚至63位:

    irb(main):001:0> RUBY_VERSION
    => "2.0.0"
    irb(main):002:0> Time.at(2**62-1).utc # within Integer range
    => 146138514283-06-19 07:44:38 UTC
    irb(main):003:0> Time.at(2**128).utc # outside of Integer range
    => 10783118943836478994022445751222-08-06 08:03:51 UTC
    irb(main):004:0> Time.at(-2**128).utc # outside of Integer range
    => -10783118943836478994022445747283-05-28 15:55:44 UTC
    

    使用较大值的唯一结果应该是性能,这在使用 Integer 时更好(相对于 Bignum s( Integer 范围之外的值)或 Rational s(跟踪纳秒时)):

    自Ruby 1.9.2起,Time实现使用带符号的63位整数,Bignum或Rational . 整数是自Epoch以来的纳秒数,可以代表1823-11-12到2116-02-20 . 当使用Bignum或Rational时(在1823之前,在2116之后,在纳秒之下),时间比使用整数时更慢 . (http://www.ruby-doc.org/core-2.1.0/Time.html)

    换句话说,据我所知, DateTime no longer covers a wider range of potential values than Time .

    此外,应该注意两个先前未提及的 DateTime 限制:

    DateTime不考虑任何跳跃,不跟踪任何夏令时规则 . (http://www.ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#class-Date-label-DateTime)

    首先, DateTime has no concept of leap seconds:

    irb(main):001:0> RUBY_VERSION
    => "2.0.0"
    irb(main):002:0> require "date"
    => true
    irb(main):003:0> t = Time.new(2012,6,30,23,59,60,0)
    => 2012-06-30 23:59:60 +0000
    irb(main):004:0> dt = t.to_datetime; dt.to_s
    => "2012-06-30T23:59:59+00:00"
    irb(main):005:0> t == dt.to_time
    => false
    irb(main):006:0> t.to_i
    => 1341100824
    irb(main):007:0> dt.to_i
    => 1341100823
    

    其次, DateTime 对时区的理解非常有限,特别是 has no concept of daylight savings . 它几乎将时区作为简单的UTC X偏移处理:

    irb(main):001:0> RUBY_VERSION
    => "2.0.0"
    irb(main):002:0> require "date"
    => true
    irb(main):003:0> t = Time.local(2012,7,1)
    => 2012-07-01 00:00:00 +0200
    irb(main):004:0> t.zone
    => "CEST"
    irb(main):005:0> t.dst?
    => true
    irb(main):006:0> dt = t.to_datetime; dt.to_s
    => "2012-07-01T00:00:00+02:00"
    irb(main):007:0> dt.zone
    => "+02:00"
    irb(main):008:0> dt.dst?
    NoMethodError: undefined method `dst?' for #<DateTime:0x007f34ea6c3cb8>
    

    当输入DST时间然后转换为非DST时区而不跟踪 DateTime 本身之外的正确偏移时,这可能会造成麻烦(许多操作系统实际上可能已经为您处理了这个问题) .

    总的来说,我认为现在 Time 对大多数人来说是更好的选择应用 .

    另请注意添加的重要区别:当您向Time对象添加数字时,它会以秒为单位计算,但是当您向DateTime添加数字时,它会以天为单位计算 .

  • 0

    Outdated! See below...

    性能差异不够强调......时间是C,而DateTime是Ruby:

    >> Benchmark.bm do |bm|
    ?>   bm.report('DateTime:') do
    ?>     n1 = DateTime.now
    >>     n2 = DateTime.now
    >>     1_000_000.times{ n1 < n2 }
    >>   end
    >>   bm.report('Time:    ') do
    ?>     n1 = Time.now
    >>     n2 = Time.now
    >>     1_000_000.times{ n1 < n2 }
    >>   end
    >> end
          user     system      total        real
    DateTime:  4.980000   0.020000   5.000000 (  5.063963)
    Time:      0.330000   0.000000   0.330000 (  0.335913)
    

    更新(2012年2月):

    正如评论中已经提到的,1.9.3已经大大提高了 DateTime 性能:

    user     system      total        real
    DateTime:  0.330000   0.000000   0.330000 (  0.333869)
    Time:      0.300000   0.000000   0.300000 (  0.306444)
    
  • 9

    我认为“有什么不同”的答案是Ruby标准库中这个问题的一个不幸的常见答案:两个类/库是由不同的人在不同时间创建的 . 与精心策划的Java开发相比,这是Ruby发展的社区性质的不幸后果之一 . 开发人员需要新的功能,但不想踩到现有的API,因此他们只是创建一个新类 - 对于最终用户来说,没有明显的理由让这两个存在 .

    对于一般的软件库来说也是如此:通常,某些代码或API的结果是历史而非逻辑 .

    诱惑是从DateTime开始,因为它似乎更通用 . 日期......和时间,对吧?错误 . 时间也更好地更新日期,实际上可以解析DateTime不能的时区 . 它也表现得更好 .

    我到处都在使用Time .

    为了安全起见,我倾向于允许将DateTime参数传递给我的Timey API,并进行转换 . 另外,如果我知道两者都有我感兴趣的方法,我也接受,就像我写的用于将时间转换为XML(用于XMLTV文件)的方法

    # Will take a date time as a string or as a Time or DateTime object and
    # format it appropriately for xmtlv. 
    # For example, the 22nd of August, 2006 at 20 past midnight in the British Summertime
    # timezone (i.e. GMT plus one hour for DST) gives: "20060822002000 +0100"
    def self.format_date_time(date_time)
      if (date_time.respond_to?(:rfc822)) then
        return format_time(date_time)
      else 
        time = Time.parse(date_time.to_s)
        return format_time(time)
      end    
    end
    
    # Note must use a Time, not a String, nor a DateTime, nor Date.
    # see format_date_time for the more general version
    def self.format_time(time)
      # The timezone feature of DateTime doesn't work with parsed times for some reason
      # and the timezone of Time is verbose like "GMT Daylight Saving Time", so the only
      # way I've discovered of getting the timezone in the form "+0100" is to use 
      # Time.rfc822 and look at the last five chars
      return "#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"
    end
    
  • 88

    我发现使用DateTime, assuming you are using the ActiveSupport extensions 更容易解析和计算不同时区的一天的开始/结束 .

    在我的情况下,我需要根据用户的本地时间以字符串形式计算用户时区(任意)的一天结束时间,例如: “2012-10-10 10:10 0300”

    使用DateTime就像它一样简单

    irb(main):034:0> DateTime.parse('2012-10-10 10:10 +0300').end_of_day
    => Wed, 10 Oct 2012 23:59:59 +0300
    # it preserved the timezone +0300
    

    现在让我们以与时间相同的方式尝试:

    irb(main):035:0> Time.parse('2012-10-10 10:10 +0300').end_of_day
    => 2012-10-10 23:59:59 +0000
    # the timezone got changed to the server's default UTC (+0000), 
    # which is not what we want to see here.
    

    实际上,Time需要在解析之前知道时区(还要注意它是 Time.zone.parse ,而不是 Time.parse ):

    irb(main):044:0> Time.zone = 'EET'
    => "EET"
    irb(main):045:0> Time.zone.parse('2012-10-10 10:10 +0300').end_of_day
    => Wed, 10 Oct 2012 23:59:59 EEST +03:00
    

    所以,在这种情况下,使用DateTime肯定更容易 .

  • 66

    考虑他们如何使用自定义实例化以不同方式处理时区:

    irb(main):001:0> Time.new(2016,9,1)
    => 2016-09-01 00:00:00 -0400
    irb(main):002:0> DateTime.new(2016,9,1)
    => Thu, 01 Sep 2016 00:00:00 +0000
    irb(main):003:0> Time.new(2016,9,1).to_i
    => 1472702400
    irb(main):004:0> DateTime.new(2016,9,1).to_i
    => 1472688000
    

    在创建时间范围等时这可能很棘手 .

  • 170

    在某些情况下,行为似乎非常不同:

    Time.parse("Ends from 28 Jun 2018 12:00 BST").utc.to_s
    

    “2018-06-28 09:00:00 UTC”

    Date.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s
    

    “2018-06-27 21:00:00 UTC”

    DateTime.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s
    

    “2018-06-28 11:00:00 UTC”

相关问题