在Ruby中DateTime和Time有什么区别?

哪些因素会导致我select其中一个?

较新版本的Ruby(2.0+)在两个类之间并没有真正的显着差异。 由于历史原因,一些图书馆会使用其中一种,但是新的代码并不一定需要担心。 为了一致性而select一个可能是最好的,所以尝试和你的图书馆期望的网格。 例如,ActiveRecord倾向于使用DateTime。

在Ruby 1.9之前的版本和许多系统上,时间被表示为一个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能够处理较大的值而不会产生错误。

date时间是基于日历的方法,年,月,日,小时,分钟和秒分别存储。 这是一个Ruby on Rails构造,用作SQL标准DATETIME字段的包装。 这些包含任意date,并且可以表示几乎任何时间点,因为expression范围通常非常大。

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

所以DateTime可以处理来自亚里士多德的博客post让人放心。

当select一个,现在的差异是有些主观的。 历史上DateTime已经提供了更好的select来以日历方式操作它,但是其中的许多方法也已经移植到Time,至less在Rails环境中。

截至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不再覆盖比Time更广泛的潜在值

另外,还应该注意两个以前未提及的DateTime限制:

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

首先, DateTime没有闰秒的概念:

 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对时区的理解非常有限,特别是没有夏时制的概念 。 它几乎处理时区作为简单的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> 

如果将时间作为DSTinput,然后转换为非DST时区,而无法追踪DateTime本身之外的正确偏移量(许多操作系统实际上已经为您处理过),则这可能会造成麻烦。

总的来说,现在我认为Time是大多数应用程序的更好select。

还要注意一个重要的不同点:当您将一个数字添加到Time对象时,它将以秒为单位进行计数,但是当您将一个数字添加到DateTime时,则以天计算。

过时! 见下文…

性能差异不能被强调足够…时间是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) 

更新(2/2012):

正如评论中已经提到的那样,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) 

我认为“有什么区别”的答案是Ruby标准库中这个问题的一个不幸常见的答案:两个类/ lib在不同的时间由不同的人创build。 与精心策划的Java开发相比,这是Ruby进化的社区本质的不幸后果之一。 开发人员需要新的function,但不希望踩到现有的API,因此他们只是创build一个新的类 – 对最终用户来说,两者不存在明显的原因。

一般情况下,软件库都是如此:通常情况下,某些代码或API的原因是历史的,而不是逻辑的。

诱惑是从DateTime开始,因为它看起来更通用。 date…和时间,对吧? 错误。 时间也是更好的date,事实上可以parsingDateTime不能的地方。 它也performance更好。

我到处都是使用时间。

为了安全起见,我倾向于允许将DateTimeparameter passing到我的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 (ie 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 

我发现像分析和计算一天中不同时区的开始/结束这样的事情,使用DateTime更容易, 假设您使用的是ActiveSupport扩展

在我的情况下,我需要根据用户的本地时间(例如“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. 

实际上,时间需要知道parsing前的时区(也请注意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肯定更容易。

考虑他们如何处理时区与自定义实例不同:

 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 

创build时间范围时,这可能会非常棘手