Разница между временем и датой в Ruby



в чем разница между DateTime и Time классы в Ruby и какие факторы заставят меня выбрать один или другой?

582   7  

7 ответов:

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

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

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

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

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

[Edit July 2018]

все нижеприведенное по-прежнему верно в Ruby 2.5.1. Из документация:

DateTime не учитывает никаких високосных секунд, не отслеживает никаких правил летнего времени.

то, что не было отмечено в этой теме раньше, является одним из немногих преимуществ DateTime: он в курсе календарных реформ, тогда как Time нет:

[...] класс времени Ruby реализует пролептический Григорианский календарь и не имеет понятия о календарной реформе [...].

справочная документация завершается рекомендацией использовать Time когда речь идет исключительно о близких прошлых, текущих или будущих датах / временах и использовать только DateTime когда, например, День рождения Шекспира нужно точно преобразовать: (курсив добавлен)

Итак, когда вы должны использовать DateTime в Ruby и когда вы должны использовать время? Почти наверняка вы захотите использовать время, так как ваше приложение, вероятно, имеет дело с текущими датами и временем. однако, если вам нужно иметь дело с датами и временем в историческом контексте вы хотите использовать DateTime [...]. Если вам также придется иметь дело с часовыми поясами, то удачи - просто имейте в виду, что вы, вероятно, будете иметь дело с местными солнечными временами, так как только в 19 веке введение железных дорог потребовало необходимости стандартного времени и в конечном итоге часовой пояс.

[/Edit Июль 2018]

по состоянию на ruby 2.0, большая часть информации в других ответах устарела.

в частности, Time теперь практически не связан. Это может быть больше или меньше, чем даже 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 s используются (против Bignums (значения вне

устарел! Увидеть ниже...

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

>> 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: два класса/библиотеки были созданы по-разному разными людьми в разное время. Это одно из печальных последствий общинного характера эволюции Ruby по сравнению с тщательно спланированной разработкой чего-то вроде Java. Разработчики хотят новую функциональность, но не хотят наступать на существующие API, поэтому они просто создают новый класс - для конечный пользователь нет никаких очевидных причин для их существования.

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

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

Я в конечном итоге с помощью времени повсюду.

чтобы быть безопасным, я, как правило, разрешаю передавать аргументы 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

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

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

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

кажется, что в некоторых случаях поведение людей сильно отличается:

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"

Comments

    Ничего не найдено.