Strptime с часовым поясом - PullRequest
       64

Strptime с часовым поясом

20 голосов
/ 27 октября 2011

У меня есть строка, с которой я разбираю DateTime.strptime.Часовой пояс даты в строке - CET, но Ruby создает объект UTC DateTime, который, конечно, имеет смещение 2 часа.

В настоящее время я работаю над проблемой с DateTime.strptime().change(:offset => "+0020"), но я уверен, чтоэто не тот способ, которым он должен работать.

Может ли кто-нибудь просветить меня о правильном способе сделать это?

Ответы [ 8 ]

11 голосов
/ 27 октября 2011

Я использую это следующим образом:

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)> 

Это то, что вы имеете в виду?

4 голосов
/ 27 мая 2017

Это работает в Rails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

Возвращает время в указанном часовом поясе.

4 голосов
/ 29 декабря 2016

По крайней мере, в 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
1 голос
/ 09 сентября 2014

Я «напрашивался» на эту строку:

19/05/2014 8:13:26 a.m.

Местная временная метка, в моем случае это Auckland NZ без метки часового пояса в строке, как видно.

Насколько я могу судить, 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

Это не особо элегантно, но работает.

0 голосов
/ 19 июня 2018

Для pre Rails 5 будет работать следующее:

t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)
0 голосов
/ 22 мая 2016

Я боролся с этой же проблемой, пытаясь проанализировать строку даты из формы и сохранить ее независимо от времени серверов.Процесс, которому я следовал, таков.Уверяю, часовые пояса 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

Это, конечно, не идеальное решение, но оно работает.Шаги для обеспечения правильного часового пояса:

  1. Анализ строки даты в соответствии с нашим форматом
  2. Извлечение текущего смещения utc на основе времени в этом часовом поясе (мы должны сделать этоесли дата, которую вы анализируете, оказывается в dst, а ваше местное время не является dst для восточного времени, это гарантирует, что dst будет локальным по отношению к проанализированному времени)
  3. Преобразование времени в нашу целевую локаль и разрешениевремя сдвига с добавлением правильного смещения
0 голосов
/ 16 июня 2013

Вы можете конвертировать дату в часовой пояс с помощью to_time_in_current_zone. Например:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
0 голосов
/ 03 апреля 2013

Я не могу удалить принятый ответ

Как указал @LeeJarvis в разделе комментариев ниже, Chronic.parse не принимает параметр :time_class.Таким образом, этот ответ ошибочен, и, хотя он выглядит так, как он работает, он этого не делает (если только Chronic не разрешит вскоре передать опцию :time_class.)


Драгоценный камень Chronic действительно мощный.1010 * Я использую это так:

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

...