Strptime с часовым поясом
У меня есть строка, которую я анализирую с помощью DateTime.strptime
. Часовой пояс даты в строке - это CET, но Ruby создает объект UTC DateTime, который, конечно, имеет смещение в 2 часа.
В настоящее время я работаю над проблемой с DateTime.strptime().change(:offset => "+0020")
, но я уверен, что это не так, как это должно было работать.
Может кто-нибудь просветить меня по правильному пути для этого?
Ответы
Ответ 1
Я не могу удалить принятый ответ
Как отметил @LeeJarvis в разделе комментариев ниже, Chronic.parse
не принимает параметр :time_class
. Таким образом, этот ответ глючит, и, хотя он выглядит так, как будто он работает, он не делает (если Chronic не разрешает передавать параметр :time_class
в ближайшее время.)
Хронический камень действительно мощный.
Я использую его следующим образом:
Chronic.parse("next 5:00 pm",
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc
В моем примере выше User.first.time_zone
есть "Тихоокеанское время (США и Канада)".
Chronic поддерживает множество форматов, поэтому проверьте его на
https://github.com/mojombo/chronic
Обязательно передайте параметр :time_class
и конвертируйте в UTC (в документации Chronic устанавливает :time_class
перед вызовом анализа). Я избегаю этого подхода, потому что это может привести к тому, что другие части приложения не будут работать)
Документация TimeZone находится на
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html
Ответ 2
Я использую его следующим образом:
ruby-1.9.2-head :001 > require 'date'
=> true
ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
=> "%m-%d-%Y %H:%M:%S %Z"
ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
=> #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)>
ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
=> #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)>
ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
=> #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)>
Это то, что вы имеете в виду?
Ответ 3
Это работает в Rails 5:
Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")
Возвращает время в указанном часовом поясе.
Ответ 4
Я был "strptiming" этой строки:
19/05/2014 8:13:26 a.m.
Локальная метка времени, которая в моем случае - Оклендская ЗЗ, без отметки времени в строке, как видно.
Насколько я могу сказать, Time.strptime
использует серверную часовую зону в качестве базы.
В моей ситуации и общей хорошей практике мои серверы работают в часовом поясе UTC, поэтому каждый синтаксический анализ строки заканчивается созданием объекта времени, время до +0000 (UTC):
2014-05-19 08:13:26 +0000
Тогда преобразование в in_time_zone(Time.zone)
дало:
Mon, 19 May 2014 20:13:26 NZST +12:00
Как видно, это 12 часов (смещение по UTC) позже фактического времени, которое я хотел.
Я попытался использовать трюк +' Auckland', '...%Z'
, как указано выше, без каких-либо изменений.
Затем я использовал трюк + '+1200', '...%Z'
, как указано выше, который работал правильно.
Однако я был обеспокоен летним временем, тогда синтаксический анализ будет отсутствовать на час, так что это то, что я закончил:
Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)
Результат:
Mon, 19 May 2014 08:13:26 NZST +12:00
Это не особенно элегантный, но он работает.
Ответ 5
По крайней мере, из Rails 4.2 (возможно, раньше не тестировалось), пока вы используете Time#strptime
вместо DateTime.strptime
, текущий часовой пояс автоматически применяется:
> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000
> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800
Ответ 6
Вы можете преобразовать дату в часовой пояс с помощью to_time_in_current_zone
. Например:
Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
Ответ 7
Я боролся с этой же проблемой, пытаясь проанализировать строку даты из формы и сохранить ее независимо от времени сервера. Процесс, который я последовал, как таковой.
Я уверяю, что часы RoR и Ruby установлены на UTC. Это облегчает работу сервера в UTC.
Я сохраняю локали пользователей, используя формат ActiveSupport: TimeZone, например US/Eastern
У меня есть функция интерпретации даты, которая может содержать строку даты, которая не содержит в себе временную зону или смещение
# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
Time.use_zone tz do
parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
offset = parsed_dt.in_time_zone(tz).utc_offset
parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
end
end
Это, конечно, не похоже на идеальное решение, но оно работает.
Шаги для обеспечения правильного часового пояса:
- Разберите строку даты в соответствии с нашим форматом
- Извлеките текущее смещение utc, основанное на времени в этом часовом поясе (мы должны это сделать, если дата, которую вы разыгрываете, находится в dst, в то время как ваше местное время не является dst для восточного времени, это гарантирует, что dst является локальным на разобранное время)
- Преобразуйте время в наш целевой локаль и дайте время сдвинуться с добавленным правильным смещением.