Странное поведение POSIX для двух близких строк времени с указанием формата и без него

Я не совсем понимаю поведение преобразования строк данных и времени в объекты POSIX. Например, у меня есть вектор из двух строк, представляющих дату и время. Преобразование без указания формата игнорирует часть времени и устанавливает часовой пояс на IST:

as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'))
[1] "2017-03-24 IST" "2017-03-24 IST"

Но когда я указываю формат, он устанавливает другой часовой пояс и не работает для строки, где часы равны «2», но не в том случае, если время является вторым последним.

as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), format="%Y-%m-%d %H:%M:%OS")
[1] NA "2017-03-24 03:00:00 IDT"

Три вопроса:

  1. Почему часовой пояс отличается между двумя строками
  2. Почему, когда формат не указан, он игнорирует часть времени.
  3. Почему не удается преобразовать первую строку, когда указан формат?

person user890739    schedule 10.01.2019    source источник
comment
Преобразование даты/времени достаточно умно, чтобы распознать переход на летнее время. На этом сайте есть много других вопросов, касающихся этой самой проблемы.   -  person Dave2e    schedule 10.01.2019
comment
А такого часа 2:59:59 в тот день не было? Но это зависит, конечно, от часового пояса. Что, если я не знаю, в каком часовом поясе это было записано, и меня это не волнует. Все, что мне нужно, это постоянство.   -  person user890739    schedule 10.01.2019
comment
Чтобы обеспечить согласованность, укажите часовой пояс с параметром tz в файле as.POSIXct(x, tz = " ", format...). Использование стандартного времени IST должно работать.   -  person Dave2e    schedule 10.01.2019
comment
Моя консоль работает не так, как ваша, видимо. Без указания tz= я не получаю NA. При включении tz="IST" получаю предупреждения, так как "IST" нет в списке (OlsonNames(), длинный век известных зон), хотя могу воспроизвести с tz="Israel" (который в OlsonNames()). Часовые пояса чрезвычайно проблематичны при переходе на летнее время.   -  person r2evans    schedule 10.01.2019


Ответы (1)


  1. Почему часовой пояс отличается между двумя строками

Как сказано в комментариях, он отличается из-за перехода на летнее время. Поскольку вы не включаете зону в вызов as.POSIXct, вы подвержены многим проблемам. Когда это возможно, указывайте часовой пояс явно. Это нешуточный момент: если вы знаете его (и он не является частью строки), никогда не предполагайте, что он будет выведен правильно. По моему опыту, это будет достаточно неправильно, чтобы действительно раздражать и очень трудно обнаружить, найти и исправить.


  1. Почему, когда формат не указан, он игнорирует часть времени

Это не так, хотя может показаться, что это так. Это всего лишь симптом того, как он распечатывается, а не сохраняется. (Это распространено во многих функциях R, например, как он показывает pi только с несколькими десятичными знаками, в то время как он, безусловно, хранит гораздо больше. Без этой модели «представление против фактической точности» консоль R была бы излишне заполнена десятичными знаками. и так постоянно)

Если я обновлю ваш код, чтобы явно включить зону:

as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz="Israel")
# [1] "2017-03-24 IST" "2017-03-24 IST"
as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz="Israel") + 1
# [1] "2017-03-24 00:00:01 IST" "2017-03-24 00:00:01 IST"

Во втором случае я добавил к времени одну секунду, и вы видите, что время теперь есть. Вы можете посмотреть на внутренности, чтобы увидеть это по-другому:

dput(as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz="Israel"))
# structure(c(1490306400, 1490306400), class = c("POSIXct", "POSIXt"
# ), tzone = "Israel")
dput(as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz="Israel")+1)
# structure(c(1490306401, 1490306401), tzone = "Israel", class = c("POSIXct", 
# "POSIXt"))

Время хранится в виде чисел с плавающей запятой и специального класса. Между ними (без прибавления 1 секунды и с добавлением 1 секунды) вы можете видеть, что числа просто отличаются друг от друга.

Третий способ подтверждения — взять posix-объекты «отсутствующего времени» и явно напечатать что-то (это уже не POSIXct, а просто для демонстрации):

a <- as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz="Israel")
a
# [1] "2017-03-24 IST" "2017-03-24 IST"
format(a, format="the time is %Y-%m-%d %H:%M:%S")
# [1] "the time is 2017-03-24 00:00:00" "the time is 2017-03-24 00:00:00"

  1. Почему не удается преобразовать первую строку, когда указан формат?

Как прокомментировал @Dave2e, согласно преобразованиям летнего времени, этого времени «никогда не было».

Согласно https://www.timeanddate.com/time/change/israel/jerusalem?year=2017:

24 марта 2017 г. – переход на летнее время

Когда местное стандартное время приближалось к пятнице, 24 марта 2017 г., 2:00:00, часы были переведены на 1 час вперед до пятницы, 24 марта 2017 г., 3:00:00 по местному летнему времени.

Я интерпретирую это так, что часы переместились с 01:59:59 на 03:00:00, поэтому 02:**:** никогда не было. R говорит вам с помощью NA, что этого времени не должно было произойти. Конечно, есть способы (взломы), с помощью которых можно вывести, что дело обстоит именно так: найти все значения NA, затем попытаться повторно преобразовать, используя плюс-минус час; если новое значение не NA, то вы нашли еще один случай, когда R считает, что время невозможно. Если это все еще NA, то в строке должно быть что-то еще (дополнительные символы, другой порядок и т. д.).

По моему опыту, я никогда не находил эту логику неправильной (хотя я не уверен, что она безупречна), даже если она кажется раздражающей. Когда я думал, что это может быть неправильно, я всегда находил что-то еще, что объясняло, почему я думаю, что у меня есть точное время:

  • сбор данных сохранил неверную ТЗ
  • при сборе данных не удалось сохранить TZ, и я сделал неправильный вывод
  • некоторое преобразование в конвейере неправильно преобразовало время и / или зону (ы)
  • скорее всего что-то еще я не искоренил
person r2evans    schedule 10.01.2019
comment
Спасибо за подробный ответ. Я почти готов принять это. Но в вашем первом примере: `as.POSIXct(c('2017-03-24 02:59:59', '2017-03-24 03:00:00'), tz=Israel) + 1, it demonstrates the opposite from what you claims. As the output of the two times is 2017-03-24 00:00:01 IST. I would expect the first one to output 2017-03-24 03:00:00 IST`. Но из того, что вы описали, он потерял время от ввода. - person user890739; 10.01.2019
comment
Возможно, мы говорим о двух вещах. Я интерпретировал потерю времени, так как было показано только %y-%m-%d. Если вы говорите, что он сдвинулся с 3 часов ночи на полночь, то проблема не в моем коде, а в понимании назначения часового пояса. В вашем первом примере, как вы думаете, в каком часовом поясе должен находиться '2017-03-24 03:00:00'? - person r2evans; 11.01.2019
comment
Я понимаю, почему 3 часа ночи печатаются как полночь. но почему секунда до полуночи плюс секунда дает полночь плюс секунда вместо ровной полуночи? as.POSIXct('2017-03-24 02:59:59', tz="Israel") + 1 выводит "2017-03-24 00:00:01 IST", а as.POSIXct('2017-03-24 02:59:59', tz="US/pacific") + 1 выводит "2017-03-24 03:00:00 PDT" (обратите внимание на второе отличие). - person user890739; 13.01.2019
comment
Я понимаю вашу точку зрения ... это интересно, я пропустил это и никогда не замечал. И, конечно же, он специфичен для этого часового пояса (ну, из всех 592 часовых поясов в OlsonNames() только "Asia/Jerusalem" "Asia/Tel_Aviv" "Israel" показывают это явление...). Итак, на это у меня нет ответа/оправдания. - person r2evans; 13.01.2019