В документации есть раздел , объясняющий, когда использовать какой.
х-юри
Ответы:
177
Более новые версии Ruby (2.0+) на самом деле не имеют существенных различий между двумя классами. Некоторые библиотеки будут использовать одну или другую по историческим причинам, но новый код не обязательно должен быть связан с этим. Вероятно, лучше выбрать один для согласованности, поэтому постарайтесь сочетать с тем, что ожидают ваши библиотеки. Например, ActiveRecord предпочитает DateTime.
В версиях, предшествующих Ruby 1.9, и во многих системах время представляется в виде 32-разрядного знакового значения, описывающего количество секунд с 1 января 1970 года по Гринвичу, тонкой обертки вокруг стандартного time_tзначения POSIX и ограниченного:
Time.at(0x7FFFFFFF)# => Mon Jan 18 22:14:07 -0500 2038Time.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 предоставлял лучшие варианты для манипулирования им по календарю, но многие из этих методов были перенесены и на Time, по крайней мере, в среде Rails.
Если вы работаете с датами, я бы сказал, использовать DateTime. Время удобно для представления таких вещей, как текущее время дня или точки в ближайшем будущем, такие как 10.minutes.from_now. Эти два имеют много общего, хотя, как отмечалось, DateTime может представлять гораздо более широкий диапазон значений.
tadman
3
Я полагаю, что это потому, что Ruby переключается на Bignum произвольной длины с 32-битного Fixnum, когда происходит переполнение. Числа вне этого диапазона могут не поддерживаться внешними приложениями. Да, в 2038 году мы в основном облажались, пока все не смогли договориться о правильном 64-битном формате времени. Юрий все еще отсутствует.
tadman
28
Этот ответ предшествует 1.9.2. Игнорируйте все, что говорится об ограничениях времени Posix, и сделайте свой выбор на основе API-интерфейсов Time и DateTime.
Бен Надь
8
Этот ответ устарел, верно? Теперь рекомендуется использовать ActiveSupport :: WithTimeZone от Time или Rail. Вам больше не нужно использовать DateTime. Это для обратной совместимости.
DateTime не учитывает никаких дополнительных секунд, не отслеживает правила летнего времени.
То, что не было отмечено в этой теме ранее, является одним из немногих преимуществ DateTime: он осведомлен о календарных реформах, а Timeне:
[…] Класс Time в Ruby реализует пролептический григорианский календарь и не имеет понятия о реформе календаря […].
Справочная документация заканчивается рекомендацией использовать, Timeкогда речь идет исключительно о ближайших, текущих или будущих датах / временах, и использовать только DateTimeтогда, когда, например, день рождения Шекспира необходимо точно преобразовать: (выделение добавлено)
Итак, когда вы должны использовать DateTime в Ruby и когда вы должны использовать Time? Почти наверняка вам захочется использовать Time, поскольку ваше приложение, вероятно, имеет дело с текущими датами и временем. Однако, если вам нужно иметь дело с датами и временем в историческом контексте, вы захотите использовать DateTime […]. Если вам также приходится иметь дело с часовыми поясами, тогда удачи - просто имейте в виду, что вы, вероятно, будете иметь дело с местным солнечным временем, так как только в 19 веке введение железных дорог потребовало стандартного времени и в конечном итоге часовые пояса.
[/ Изменить июль 2018 года]
Начиная с 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-1907:44:38 UTC
irb(main):003:0>Time.at(2**128).utc # outside of Integer range=>10783118943836478994022445751222-08-0608:03:51 UTC
irb(main):004:0>Time.at(-2**128).utc # outside of Integer range=>-10783118943836478994022445747283-05-2815:55:44 UTC
Единственным последствием использования больших значений должна быть производительность, которая лучше при использовании Integers (по сравнению Bignumс s (значения вне Integerдиапазона) или Rationals (когда отслеживаются наносекунды)):
Начиная с Ruby 1.9.2, реализация Time использует 63-разрядное целое число со знаком, Bignum или Rational. Целое число - это число наносекунд, начиная с эпохи, которое может представлять 1823-11-12 до 2116-02-20. Когда используется Bignum или Rational (до 1823, после 2116, в течение наносекунды), время работает медленнее, чем при использовании целого числа. ( http://www.ruby-doc.org/core-2.1.0/Time.html )
Другими словами, насколько я понимаю, DateTimeболее не охватывает более широкий диапазон потенциальных значений, чемTime .
Кроме того, DateTimeвероятно, следует отметить два ранее не упомянутых ограничения :
Для работы с приведенным выше примером TimeОС должна поддерживать високосные секунды, а информация о часовом поясе должна быть установлена правильно, например, через TZ=right/UTC irb(во многих системах Unix).
Во-вторых, DateTimeимеет очень ограниченное понимание часовых поясов и, в частности, не имеет понятия о переходе на летнее время . Он в значительной степени обрабатывает часовые пояса как простые смещения UTC + X:
Это может вызвать проблемы, когда времена вводятся как DST, а затем преобразуются в часовой пояс не-DST, не отслеживая правильные смещения вне DateTimeсебя (многие операционные системы могут фактически позаботиться об этом за вас).
В целом, я бы сказал, что в настоящее время Timeэто лучший выбор для большинства приложений.
Также обратите внимание на важное различие при добавлении: когда вы добавляете число к объекту Time, оно считается в секундах, а когда вы добавляете число в DateTime, оно считается в днях.
Это все еще верно в Ruby 2.5.1. ruby-doc.org/stdlib-2.5.1/libdoc/date/rdoc/DateTime.html : «DateTime не учитывает никаких дополнительных секунд, не отслеживает правила летнего времени». Тем не менее, обратите внимание, что DateTime имеет преимущества, когда вам нужно иметь дело с датами / временем до григорианского календаря. Это не упоминалось здесь ранее, но задокументировано в справочной документации: «[…] Класс Time в Ruby реализует пролептический григорианский календарь и не имеет понятия о реформе календаря […]». Я отредактирую свой ответ, чтобы предоставить более подробную информацию.
Нильс Гансер
Timeтакже не имеет понятия о високосных секундах, поэтому он не отличается от DateTime. Я не знаю, где вы запускали свои примеры, но я пробовал Time.new(2012,6,30,23,59,60,0)в разных версиях Ruby, от 2.0 до 2.7, и всегда получал 2012-07-01 00:00:00 +0000.
Микау
@michau TimeПоддерживает ли високосные секунды или нет, зависит от вашей ОС и конфигурации часового пояса. Например: TZ=right/UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'=> 2012-06-30 23:59:60 +0000тогда как TZ=UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'=> 2012-07-01 00:00:00 +0000.
Нильс Гансер
@NielsGanser Отлично, спасибо! Я предложил изменить, чтобы прояснить этот момент.
Микау
44
Я думаю, что ответ на вопрос «в чем разница» является одним из неудачных общих ответов на этот вопрос в стандартных библиотеках Ruby: два класса / библиотеки были созданы по-разному разными людьми в разное время. Это одно из печальных последствий общественной природы эволюции Ruby по сравнению с тщательно спланированной разработкой чего-то вроде Java. Разработчики хотят новую функциональность, но не хотят наступать на существующие API, поэтому они просто создают новый класс - для конечного пользователя нет очевидных причин для существования этих двух.
Это верно для библиотек программного обеспечения в целом: часто причина того, что какой-то код или API-интерфейс таков, что оказывается исторической, а не логической.
Соблазн - начать с DateTime, потому что он кажется более общим. Дата ... и Время, верно? Неправильно. Время также делает даты лучше, и фактически может анализировать часовые пояса, где DateTime не может. Также это работает лучше.
Я закончил тем, что использовал Время везде.
Однако, чтобы быть в безопасности, я склонен разрешать передачу аргументов 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"defself.format_date_time(date_time)if(date_time.respond_to?(:rfc822))thenreturn format_time(date_time)else
time =Time.parse(date_time.to_s)return format_time(time)endend# Note must use a Time, not a String, nor a DateTime, nor Date.# see format_date_time for the more general versiondefself.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 charsreturn"#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"end
Кроме того, Time.new и DateTime.new работают с часовым поясом по-разному. Я в GMT + 7, поэтому Time.new(2011, 11, 1, 10, 30)выдает, 2011-11-01 10:30:00 +0700пока DateTime.new(2011, 11, 1, 10, 30)выдает Tue, 01 Nov 2011 10:30:00 +0000.
Phương Nguyễn
21
И, как мы все знаем, тщательно спланированная разработка Java привела к созданию исключительно простых логических API.
pje
@ PhươngNguyễn: Не могли бы вы добавить это в качестве ответа, чтобы я мог проголосовать за него? Именно поэтому я решил выбрать Time вместо DateTime.
Чувственный
@Senseful Извините, я не получил ваше сообщение до сих пор. Люди уже высказывают мои комментарии, поэтому я думаю, что это круто.
Phương Nguyễn
@ PhươngNguyễn Привет, есть идеи, как / почему эта разница во временных зонах? откуда берется смещение?
Joel_Blum
10
Я обнаружил, что такие вещи, как разбор и вычисление начала / конца дня в разных часовых поясах, проще сделать с 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,10Oct201223: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-1023: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,10Oct201223:59:59 EEST +03:00
Таким образом, в этом случае определенно проще использовать DateTime.
Используя это в производстве сейчас, есть ли недостатки в технике?
Алекс Мур-Ниеми
1
DateTime не учитывает переход на летнее время. Таким образом, экономя время, оно не будет работать правильно. DateTime.parse('2014-03-30 01:00:00 +0100').end_of_dayпроизводит Sun, 30 Mar 2014 23:59:59 +0100, но Time.zone = 'CET'; Time.zone.parse('2014-03-30 01:00:00').end_of_dayпроизводит Sun, 30 Mar 2014 23:59:59 CEST +02:00(CET = + 01: 00, CEST = + 02: 00 - обратите внимание, что смещение изменилось). Но для этого вам нужно больше информации о часовом поясе пользователя (не только о смещении, но и о том, используется ли экономия времени).
Петр Бубак Шедивы
1
Это может быть констатирую очевидное, но Time.zone.parseэто очень полезно при анализе раз с разными зонами - это заставляет вас думать о том, в какой зоне вы должны использовать. Иногда Time.find_zone работает даже лучше.
Пруссван
1
@ Petr''Bubák''Sedivý DateTimeпроанализировал смещение, которое вы ему дали, +0100. Вы не указали Timeсмещение, но часовой пояс («CET» не описывает смещение, это название часового пояса). Часовые пояса могут иметь разные смещения в течение года, но смещение - это смещение, и оно всегда одинаково.
Меки
4
Рассмотрим, как они обрабатывают часовые пояса по-разному с помощью пользовательских экземпляров:
Это интересное наблюдение, но нужно объяснить, почему это происходит. Date(неудивительно) анализирует только даты, и когда a Dateконвертируется в Time, он всегда использует полночь в местном часовом поясе в качестве времени. Разница между Timeи TimeDateсвязана с тем, что Timeне понимает BST, что удивительно, учитывая, что часовые пояса обычно обрабатываются более корректно Time(например, в отношении летнего времени). Таким образом, в этом случае, только DateTimeанализирует всю строку правильно.
Обратите внимание, что в Руководстве по стилю Ruby довольно четко изложена позиция по этому вопросу:
Нет даты и времени
Не используйте DateTime, если вам не нужно учитывать историческую реформу календаря - и если вы это делаете, явно укажите аргумент start, чтобы четко указать свои намерения.
# bad - uses DateTime for current timeDateTime.now
# good - uses Time for current timeTime.now
# bad - uses DateTime for modern dateDateTime.iso8601('2016-06-29')# good - uses Date for modern dateDate.iso8601('2016-06-29')# good - uses DateTime with start argument for historical dateDateTime.iso8601('1751-04-23',Date::ENGLAND)
Ответы:
Более новые версии Ruby (2.0+) на самом деле не имеют существенных различий между двумя классами. Некоторые библиотеки будут использовать одну или другую по историческим причинам, но новый код не обязательно должен быть связан с этим. Вероятно, лучше выбрать один для согласованности, поэтому постарайтесь сочетать с тем, что ожидают ваши библиотеки. Например, ActiveRecord предпочитает DateTime.
В версиях, предшествующих Ruby 1.9, и во многих системах время представляется в виде 32-разрядного знакового значения, описывающего количество секунд с 1 января 1970 года по Гринвичу, тонкой обертки вокруг стандартного
time_t
значения POSIX и ограниченного:Более новые версии Ruby могут обрабатывать большие значения без ошибок.
DateTime - это основанный на календаре подход, в котором год, месяц, день, час, минута и секунда хранятся отдельно. Это конструкция Ruby on Rails, которая служит оболочкой для полей DATETIME стандарта SQL. Они содержат произвольные даты и могут представлять практически любой момент времени, поскольку диапазон выражений обычно очень велик.
Так что обнадеживает, что DateTime может обрабатывать сообщения в блоге от Аристотеля.
При выборе одного различия несколько субъективны. Исторически DateTime предоставлял лучшие варианты для манипулирования им по календарю, но многие из этих методов были перенесены и на Time, по крайней мере, в среде Rails.
источник
[Изменить июль 2018 года]
Все перечисленное ниже относится и к Ruby 2.5.1. Из справочной документации :
То, что не было отмечено в этой теме ранее, является одним из немногих преимуществ
DateTime
: он осведомлен о календарных реформах, аTime
не:Справочная документация заканчивается рекомендацией использовать,
Time
когда речь идет исключительно о ближайших, текущих или будущих датах / временах, и использовать толькоDateTime
тогда, когда, например, день рождения Шекспира необходимо точно преобразовать: (выделение добавлено)[/ Изменить июль 2018 года]
Начиная с ruby 2.0, большая часть информации в других ответах устарела.
В частности,
Time
сейчас практически не связан. Это может быть больше или меньше 63 бит от Epoch:Единственным последствием использования больших значений должна быть производительность, которая лучше при использовании
Integer
s (по сравнениюBignum
с s (значения внеInteger
диапазона) илиRational
s (когда отслеживаются наносекунды)):Другими словами, насколько я понимаю,
DateTime
более не охватывает более широкий диапазон потенциальных значений, чемTime
.Кроме того,
DateTime
вероятно, следует отметить два ранее не упомянутых ограничения :Во-первых,
DateTime
не имеет понятия о високосных секундах:Для работы с приведенным выше примером
Time
ОС должна поддерживать високосные секунды, а информация о часовом поясе должна быть установлена правильно, например, черезTZ=right/UTC irb
(во многих системах Unix).Во-вторых,
DateTime
имеет очень ограниченное понимание часовых поясов и, в частности, не имеет понятия о переходе на летнее время . Он в значительной степени обрабатывает часовые пояса как простые смещения UTC + X:Это может вызвать проблемы, когда времена вводятся как DST, а затем преобразуются в часовой пояс не-DST, не отслеживая правильные смещения вне
DateTime
себя (многие операционные системы могут фактически позаботиться об этом за вас).В целом, я бы сказал, что в настоящее время
Time
это лучший выбор для большинства приложений.Также обратите внимание на важное различие при добавлении: когда вы добавляете число к объекту Time, оно считается в секундах, а когда вы добавляете число в DateTime, оно считается в днях.
источник
Time
также не имеет понятия о високосных секундах, поэтому он не отличается отDateTime
. Я не знаю, где вы запускали свои примеры, но я пробовалTime.new(2012,6,30,23,59,60,0)
в разных версиях Ruby, от 2.0 до 2.7, и всегда получал2012-07-01 00:00:00 +0000
.Time
Поддерживает ли високосные секунды или нет, зависит от вашей ОС и конфигурации часового пояса. Например:TZ=right/UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'
=>2012-06-30 23:59:60 +0000
тогда какTZ=UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'
=>2012-07-01 00:00:00 +0000
.Я думаю, что ответ на вопрос «в чем разница» является одним из неудачных общих ответов на этот вопрос в стандартных библиотеках Ruby: два класса / библиотеки были созданы по-разному разными людьми в разное время. Это одно из печальных последствий общественной природы эволюции Ruby по сравнению с тщательно спланированной разработкой чего-то вроде Java. Разработчики хотят новую функциональность, но не хотят наступать на существующие API, поэтому они просто создают новый класс - для конечного пользователя нет очевидных причин для существования этих двух.
Это верно для библиотек программного обеспечения в целом: часто причина того, что какой-то код или API-интерфейс таков, что оказывается исторической, а не логической.
Соблазн - начать с DateTime, потому что он кажется более общим. Дата ... и Время, верно? Неправильно. Время также делает даты лучше, и фактически может анализировать часовые пояса, где DateTime не может. Также это работает лучше.
Я закончил тем, что использовал Время везде.
Однако, чтобы быть в безопасности, я склонен разрешать передачу аргументов DateTime в мои Timey API и любые преобразования. Также, если я знаю, что у обоих есть метод, который меня интересует, я тоже принимаю, как этот метод, который я написал для преобразования времени в XML (для файлов XMLTV).
источник
Time.new(2011, 11, 1, 10, 30)
выдает,2011-11-01 10:30:00 +0700
покаDateTime.new(2011, 11, 1, 10, 30)
выдаетTue, 01 Nov 2011 10:30:00 +0000
.Я обнаружил, что такие вещи, как разбор и вычисление начала / конца дня в разных часовых поясах, проще сделать с DateTime, если вы используете расширения ActiveSupport .
В моем случае мне нужно было вычислить конец дня в часовом поясе пользователя (произвольно) на основе местного времени пользователя, которое я получил в виде строки, например, «2012-10-10 10:10 +0300»
С DateTime это так же просто, как
Теперь давайте попробуем то же самое со временем:
На самом деле, Time должен знать часовой пояс перед синтаксическим анализом (также обратите внимание, что это
Time.zone.parse
не такTime.parse
):Таким образом, в этом случае определенно проще использовать DateTime.
источник
DateTime.parse('2014-03-30 01:00:00 +0100').end_of_day
производитSun, 30 Mar 2014 23:59:59 +0100
, ноTime.zone = 'CET'; Time.zone.parse('2014-03-30 01:00:00').end_of_day
производитSun, 30 Mar 2014 23:59:59 CEST +02:00
(CET = + 01: 00, CEST = + 02: 00 - обратите внимание, что смещение изменилось). Но для этого вам нужно больше информации о часовом поясе пользователя (не только о смещении, но и о том, используется ли экономия времени).Time.zone.parse
это очень полезно при анализе раз с разными зонами - это заставляет вас думать о том, в какой зоне вы должны использовать. Иногда Time.find_zone работает даже лучше.DateTime
проанализировал смещение, которое вы ему дали, +0100. Вы не указалиTime
смещение, но часовой пояс («CET» не описывает смещение, это название часового пояса). Часовые пояса могут иметь разные смещения в течение года, но смещение - это смещение, и оно всегда одинаково.Рассмотрим, как они обрабатывают часовые пояса по-разному с помощью пользовательских экземпляров:
Это может быть сложно при создании временных диапазонов и т. Д.
источник
Кажется, что в некоторых случаях поведение очень отличается:
источник
Date
(неудивительно) анализирует только даты, и когда aDate
конвертируется вTime
, он всегда использует полночь в местном часовом поясе в качестве времени. Разница междуTime
иTimeDate
связана с тем, чтоTime
не понимает BST, что удивительно, учитывая, что часовые пояса обычно обрабатываются более корректноTime
(например, в отношении летнего времени). Таким образом, в этом случае, толькоDateTime
анализирует всю строку правильно.В дополнение к ответу Нильса Гансера вы могли бы рассмотреть этот аргумент:
Обратите внимание, что в Руководстве по стилю Ruby довольно четко изложена позиция по этому вопросу:
источник