Какая разница между DateTime и Time в Ruby?

И какие факторы заставят меня выбрать тот или иной?

185
11 авг. '09 в 18:59
источник поделиться
6 ответов

Более новые версии Ruby (2.0+) на самом деле не имеют существенных различий между этими двумя классами. Некоторые библиотеки будут использовать один или другой по историческим причинам, но новый код не обязательно должен быть затронут. Выбор одного для согласованности, вероятно, лучше всего, поэтому попробуйте и запишите то, что ожидают ваши библиотеки. Например, ActiveRecord предпочитает DateTime.

В версиях до Ruby 1.9 и во многих системах Время представлено как 32-разрядное знаковое значение, описывающее количество секунд с 1 января 1970 года 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, которая служит оболочкой вокруг стандартных полей DATETIME. Они содержат произвольные даты и могут представлять почти любой момент времени, поскольку диапазон выражения обычно очень велик.

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

Так что это обнадеживает, что DateTime может обрабатывать сообщения в блоге от Аристотеля.

При выборе одного, различия сейчас несколько субъективны. Исторически DateTime предоставил лучшие возможности для манипулирования им в календарном режиме, но многие из этих методов были перенесены на время, по крайней мере, в среду Rails.

159
11 авг. '09 в 19:16
источник

Связанные вопросы


Похожие вопросы

Начиная с ruby ​​2.0, большая часть вышеупомянутой информации устарела.

В частности, Time теперь практически несвязано. Это может быть больше или меньше, чем на 63 бита от Epoch:

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 (значения вне диапазона Integer) или Rational (когда отслеживаются наносекунды)):

Так как Ruby 1.9.2, реализация времени использует подписанное 63-битное целое число, Bignum или Rational. Целое число - это число наносекунд с эпохи, которое может составлять 1823-11-12 до 2116-02-20. Когда используется Bignum или Rational (до 1823 года, после 2116, в наносекундах), Time работает медленнее, когда используется целое число. (http://www.ruby-doc.org/core-2.1.0/Time.html)

Другими словами, насколько я понимаю, DateTime больше не охватывает более широкий диапазон значений потенциала, чем Time.

Кроме того, вероятно, следует отметить два ранее не упомянутых ограничения DateTime:

DateTime не рассматривает какие-либо leapseconds, не отслеживает никаких правил летнего времени. (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>

Это может вызвать проблемы, когда время вводится как DST, а затем преобразуется в не-DST часовой пояс, не отслеживая правильные смещения вне самого DateTime (многие операционные системы уже могут позаботиться об этом для вас).

В целом, я бы сказал, что сейчас Time лучший выбор для большинства приложений.

Также обратите внимание на важное различие при добавлении: когда вы добавляете число в объект Time, оно подсчитывается в секундах, но когда вы добавляете число в DateTime, оно подсчитывается через дни.

70
12 янв. '14 в 17:14
источник

Устаревшие! См. Ниже...

Разница в производительности не может быть подчеркнута достаточно... Время - 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)
66
13 авг. '09 в 23:45
источник

Я думаю, что ответ на вопрос "какая разница" является одним из неудачных общих ответов на этот вопрос в стандартных библиотеках Ruby: два класса /lib создавались по-разному разными людьми в разное время. Это одно из неудачных последствий общинного характера эволюции Ruby по сравнению с тщательно спланированной разработкой чего-то вроде Java. Разработчики хотят новой функциональности, но не хотят наступать на существующие API, поэтому они просто создают новый класс - для конечного пользователя нет очевидной причины для существования этих двух.

Это верно для программных библиотек в целом: часто причина того, что какой-то код или API - это то, как он оказывается скорее историческим, чем логичным.

Искушение - начать с DateTime, потому что оно кажется более общим. Дата... и время, правильно? Неправильно. Время также делает даты лучше, и на самом деле может анализировать временные интервалы, где DateTime не может. Также он работает лучше.

Я повсюду использовал Time.

Чтобы быть в безопасности, я, как правило, допускаю, чтобы аргументы DateTime передавались в мои API-интерфейсы Timey, и либо конвертировали. Также, если я знаю, что у обоих есть метод, который меня интересует, я принимаю либо, как этот метод, который я написал для преобразования времени в 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
42
12 авг. '09 в 13:33
источник

Я нашел такие вещи, как синтаксический анализ и вычисление начала/конца дня в разных часовых поясах, легче сделать с 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

Теперь попробуем его так же, как и Time:

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 default UTC (+0000), 
# which is not what we want to see here.

На самом деле, время должно знать часовой пояс перед разбором (также обратите внимание на 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 определенно проще работать.

9
02 нояб. '12 в 19:08
источник

Рассмотрим, как они обрабатывают временные интервалы по-разному с пользовательскими экземплярами:

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

Это может быть сложно при создании временных диапазонов и т.д.

4
02 сент. '16 в 0:40
источник

Посмотрите другие вопросы по меткам или Задайте вопрос