К сожалению, это не представляется возможным, по крайней мере, не получая гораздо более умный.
Чтобы понять, почему вы должны делать различие между часового пояса в и UTC смещение:
Рассмотрите возможность отображения из зоны в смещение: вы также должны знать время, о котором идет речь, а также зону, чтобы решить, применять ли стандартное или дневное смещение.
Идти другим способом намного сложнее. Еще раз просто смещения недостаточно, потому что мы не знаем, относится ли это смещение к стандартному или дневному свету. Но на этот раз у нас проблема с курицей/яйцом: даже если у нас есть время, нам нужно знать зону, чтобы увидеть, было ли это время стандартным или дневным. Но у нас нет зоны.
Вот обработанный пример из ваших, вы используете Fri, 30 Mar 2001 19:00:00
, который бывает стандартное время (EST), поэтому при первом проходе она хорошо выглядит:
> time_from_client = "2001-03-30T19:00:00-05:00"
=> "2001-03-30T19:00:00-05:00"
> time_from_client.to_datetime
=> Fri, 30 Mar 2001 19:00:00 -0500
> timezone_offset = time_from_client.to_datetime.offset.numerator
=> -5
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-05:00) America/New_York
Мы America/New_York
.
Но посмотрим, что произойдет, если мы переходим на летнее время, скажем, 30 Jun 2001 19:00:00
. Компонент смещения вашего time_from_client
теперь будет -04:00
, что является смещением дневного света для Нью-Йорка (EDT).
> time_from_client = "2001-03-30T19:00:00-4:00"
=> "2001-06-30T19:00:00-05:00"
> time_from_client.to_datetime
=> Fri, 30 Jun 2001 19:00:00 -0400
Отказ от ответственности: Следующий шаг фактически не работает, потому что numerator
будет округлить 4/24
к 1/6
, и вы получите неправильный timezone_offset
из 1
. Таким образом, я изменил вашу реализацию и использовал utc_offset
.
> timezone_offset = time_from_client.to_datetime.utc_offset
=> -14400
> tz = ActiveSupport::TimeZone[timezone_offset]
=> (GMT-04:00) Atlantic Time (Canada)
Проблема теперь можно видеть, вместо того, чтобы America/New_York
мы получаем Atlantic Time (Canada)
. Последний является одним из названия зон для стандартного смещения -04:00
, потому что implementation of ActiveSupport::TimeZone[]
может найти только по стандарту utc_offset
и не знает дневного света.
Если вы будете следовать этому до его завершения вы в конечном итоге с помощью следующего нелогичного parse
:
> tz.parse "2001-06-30T19:00:00-04:00"
=> Sat, 30 Jun 2001 20:00:00 ADT -03:00
Что я предполагаю, что здесь происходит TimeWithZone
видит это июнь, и поэтому приспосабливается к Атлантике Переход смещения, -03:00
.
Стоит отметить, что даже если вы могли бы объяснить для дневного света, и получаем стандартное смещение перейти к ActiveSupport::TimeZone[]
, вы бы до сих пор не имеют правильную зону, так как смещение в зону отображения ISN» t один к одному.
Как показано здесь:
ActiveSupport::TimeZone.all.select { |z| z.utc_offset == -14400 }
=> [(GMT-04:00) Atlantic Time (Canada), (GMT-04:00) Georgetown, (GMT-04:00) La Paz, (GMT-04:00) Santiago]
Это моя причина думать, что это не возможно, если вы не случится иметь информацию о местоположении в оригинальной ISO 8601 строки.
Кстати, если вы преследуете такой подход, я рекомендую библиотеку Node.js tzwhere, которая может использовать геометрию зон, чтобы сделать поиск местоположения в зоне.
К сожалению, это не ответ. Часовой пояс, в котором я хочу, чтобы экземпляр TimeWithZone находился в IS, уже содержится в строке iso8601, которую я получаю от клиента. Ваше решение будет работать, когда клиент передает часовой пояс в качестве других параметров. Обратите внимание, что при первом анализе вы уже потеряли информацию о часовом поясе. –