Головоломка за миллисекунды при вызове strptime в R
options(digits.secs = 3);
> strptime("2007-03-30 15:00:00.007", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.007"
> strptime("2007-03-30 15:00:00.008", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.009", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.010", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.01"
> strptime("2007-03-30 15:00:00.011", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.010"
> strptime("2007-03-30 15:00:00.999", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.998"
Я запутался, почему разница в одну миллисекунду с "009", а затем с "011".
2 ответа
Это связано с R-FAQ 7.31, хотя и принимает облик, отличный от обычного.
Поведение, которое вы видите, является результатом комбинации: (а) неточного представления (большинства) десятичных значений двоичными компьютерами; и (б) документированное поведение strftime
а также strptime
, который должен усекать, а не округлять дробные части секунд, до указанного числа десятичных знаков.
От ?strptime
файл справки (ключевое слово "усечено"):
Специфическим для R является "%OSn", который для вывода дает секунды, усеченные до "0 <= n <= 6" десятичных знаков (и если после "% OS" не следует цифра, используется настройка "getOption("digits.secs") 'или, если это не установлено,' n = 3 ').
Пример, вероятно, проиллюстрирует, что происходит более эффективно, чем дальнейшее объяснение:
strftime('2011-10-11 07:49:36.3', format="%Y-%m-%d %H:%M:%OS6")
[1] "2011-10-11 07:49:36.299999"
strptime('2012-01-16 12:00:00.3', format="%Y-%m-%d %H:%M:%OS1")
[1] "2012-01-16 12:00:00.2"
В приведенном выше примере дробный ".3" должен быть наилучшим образом аппроксимирован двоичным числом, которое немного меньше, чем "0.300000000000000000" - что-то вроде "0.29999999999999999". Так как strptime
а также strftime
усечение, а не округление до указанного десятичного знака, 0.3 будет преобразовано в 0,2, если число десятичных разрядов установлено в 1. Та же логика верна для ваших примеров, из которых половина демонстрирует такое поведение, как и (в среднем) быть ожидаемым.
Я знаю, что на него "ответили", но эта проблема все еще существует для 32-битного R, существует несоответствие в реализации между 32-битной и 64-битной версиями. Проблема усечения частично верна, но это не результат функции strptime, а метода print.POSIXlt в данном конкретном случае.
Это можно продемонстрировать, переписав функцию с функцией, которая производит ожидаемое поведение. Например
print.POSIXlt = function(posix) {
print(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ",
sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec)))
}
Теперь время отображается, как и ожидалось:
> strptime("2007-03-30 15:00:00.009", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:0.009"
Для более подробной информации, я рассмотрел этот вопрос R с округлением миллисекунд