Головоломка за миллисекунды при вызове strptime в R - PullRequest
6 голосов
/ 17 января 2012
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 ]

9 голосов
/ 17 января 2012

Это относится к R-FAQ 7.31 , хотя и принимает облик, отличный от обычного.

Поведение, которое вы видите, является результатом комбинации: (a) неточного представления (большинства) десятичных значений двоичными компьютерами; и (b) задокументированное поведение strftime и strptime, которое заключается в том, чтобы усекать, а не округлять дробных долей секунд до указанного числа десятичных знаков.

Из справочного файла ?strptime (ключевое слово «усечено»):

Специфическим для R является «% OSn», который для вывода дает секунды усекается до ‘0 <= n <= 6’ десятичных знаков (а если if% OS ’не сопровождаемый цифрой, он использует настройку ‘GetOption (" digits.secs ")’ или, если это не установлено, ‘n = 3’). </p>

Пример, вероятно, проиллюстрирует, что происходит более эффективно, чем дальнейшее объяснение:

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. Та же логика верна для ваших примеров, из которых половина демонстрирует это поведение, как и следовало ожидать (в среднем).

3 голосов
/ 16 октября 2015

Я знаю, что на него "ответили", но эта проблема все еще существует для 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 с округлением в миллисекундах

...