Каковы стандартные форматы «однозначной даты» для преобразования строки в дату в R?

94

Пожалуйста, примите во внимание следующее

$ R --vanilla

> as.Date("01 Jan 2000")
Error in charToDate(x) :
    character string is not in a standard unambiguous format

Но эта дата явно имеет стандартный однозначный формат. Почему появляется сообщение об ошибке?

Хуже того, двусмысленная дата, по-видимому, принимается без предупреждения или ошибки, а затем читается неправильно!

> as.Date("01/01/2000")
[1] "0001-01-20"

Я просмотрел и нашел 28 других вопросов в теге [R], содержащем это сообщение об ошибке. Все с решениями и обходными путями, включая указание формата, iiuc. Этот вопрос отличается тем, что я спрашиваю, где в любом случае определены стандартные однозначные форматы и можно ли их изменить? Все получают эти сообщения или это только я? Возможно, это связано с локалью?

Другими словами, есть ли лучшее решение, чем необходимость указывать формат?

29 вопросов, содержащих «стандартный однозначный формат [R]»

> sessionInfo()
R version 2.15.2 (2012-10-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252
[2] LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base
Мэтт Доул
источник
13
судя по определению функции as.Date.characterвход проверяется только для этих двух форматов: "%Y-%m-%d"и "%Y/%m/%d". Если он может совпадать с одним из них, это будет считаться «однозначным».
plannapus
7
@CarlWitthoft «Я вообще читал», кажется, подразумевает, что ответ ослепляюще очевиден ?as.Date. Где это помогает?
Мэтт Доул
2
Возможно, «24 января 1949 года» и «24 января 1949 года» будут однозначными, но они определенно англоцентричны. Тем не менее, есть также значения для 'month.abb', которые также являются англоцентрическими, поэтому можно сделать случай, чтобы эти значения совпадали в тех случаях, когда: strptime(xx, f <- "%d $B %Y", tz = "GMT")или strptime(xx, f <- "%B $d %Y", tz = "GMT")возвращаемые значения. (Я не имею в виду, что month.abbэто используется для сопоставления с% B, поскольку в документации говорится, что сопоставление зависит от локали.)
IRTFM
6
@CarlWitthoft Некоторые из нас то и дело спотыкаются. Спасибо за удар, пока я внизу. В этом вопросе я правильно понял несколько вещей: я включил sessionInfo (), я искал, сказал вам, что я искал, и включил ссылку, я сохранил ее как можно более лаконично. Я пропустил одну строчку в? As.Date, а вы меня лечите TFM. Мы не можем все время быть такими же идеальными, как вы.
Мэтт Доул
1
@MatthewDowle, прости, если я сильно упал. Я думаю, что вспыльчивость началась, когда вы, казалось, путали «однозначное для достаточно хорошо образованного человека» с «однозначное для бедного беспомощного фрагмента кода». :-(
Карл Уиттофт

Ответы:

66

Это задокументированное поведение. Откуда ?as.Date:

формат: строка символов. Если не указано иное, он попробует '"% Y-% m-% d"', затем '"% Y /% m /% d"' для первого элемента, отличного от'NA ', и выдаст ошибку, если ни один из них не работает.

as.Date("01 Jan 2000")выдает ошибку, потому что формат не один из двух перечисленных выше. as.Date("01/01/2000")дает неверный ответ, потому что дата не в одном из двух форматов, перечисленных выше.

Я считаю, что «стандартный однозначный» означает «ISO-8601» (хотя as.Dateэто и не так строго, поскольку «% m /% d /% Y» не является ISO-8601).

Если вы получаете эту ошибку, решение состоит в том, чтобы указать формат вашей даты (или даты и времени), используя форматы, описанные в ?strptime. Будьте особенно внимательны, если ваши данные содержат названия дней / месяцев и / или сокращения, так как преобразование будет зависеть от вашего языкового стандарта (см. Примеры в ?strptimeи прочтите ?LC_TIME).

Джошуа Ульрих
источник
6
@BenBolker Как насчет "character string is not either %Y-%m-%d or %Y/%m/%d"?
Мэтт Доул
9
Такое поведение определенно задокументировано в ?as.Date(+1). Однако сообщение об ошибке «стандартный однозначный формат» по иронии судьбы неоднозначно, о чем свидетельствуют 23 предыдущих вопроса. Более прямое сообщение об ошибке, например «формат не распознан, см. Документацию», может улучшить взаимодействие с пользователем. Кроме того, я не верю, что «01.01.2000» - это ISO-8601 («2000-01-01» - это ISO-8601), что добавляет двусмысленности.
jthetzel 07
@jthetzel: вы правы, «01.01.2000» - это не ISO-8601. Я имел в виду, что лично я считаю ISO-8601 стандартным однозначным форматом. И я согласен с тем, что as.Dateотсутствие жалоб на «01.01.2000» несовместимо с сообщением об ошибке.
Джошуа Ульрих,
31

Другими словами, есть ли лучшее решение, чем необходимость указывать формат?

Да, есть сейчас (то есть в конце 2016 года) благодаря пакету anytime::anydateот anytime .

См. Следующие примеры сверху:

R> anydate(c("01 Jan 2000", "01/01/2000", "2015/10/10"))
[1] "2000-01-01" "2000-01-01" "2015-10-10"
R> 

Как вы сказали, они на самом деле однозначны и должны работать. И anydate()они это делают. Без формата.

Дирк Эддельбюттель
источник
2
Пришли сюда только потому, что у нас возник еще один вопрос о том, что что-то пытается разобрать даты с неполным форматом. Для полных у нас теперь есть кое-что. Меня это вполне устраивает - это был назойливый вопрос. И, разумеется, anytime()одинаково полезен для POSIXct.
Дирк Эдделбюттель
Просто использовал пакет Anytime, и он отлично работал, за исключением нескольких НА. После того, как я запустил trimws () для вектора даты, все стало идеально.
lawyeR 07
Я тоже использую метрическую тонну!
Дирк Эддельбюттель
Выглядит так просто! Я использовал anydate () для столбца со строковыми значениями mm-dd (без yy). Все значения <chr> в столбце были успешно преобразованы в <дата>. К сожалению, он установил год «1400» вместо «2020». ¯_ (ツ) _ / ¯
owlstone
Не совсем так. Как я ответил на несколько других вопросов на этом сайте, mm-ddэто не дата (ни мм-гг, ни мм-гггг). Вы не можете разобрать то, чего там нет.
Дирк Эддельбюттель
26

В дополнение к ответу @JoshuaUlrich вот определение функции as.Date.character:

as.Date.character
function (x, format = "", ...) 
{
    charToDate <- function(x) {
        xx <- x[1L]
        if (is.na(xx)) {
            j <- 1L
            while (is.na(xx) && (j <- j + 1L) <= length(x)) xx <- x[j]
            if (is.na(xx)) 
                f <- "%Y-%m-%d"
        }
        if (is.na(xx) || !is.na(strptime(xx, f <- "%Y-%m-%d", 
            tz = "GMT")) || !is.na(strptime(xx, f <- "%Y/%m/%d", 
            tz = "GMT"))) 
            return(strptime(x, f))
        stop("character string is not in a standard unambiguous format")
    }
    res <- if (missing(format)) 
        charToDate(x)
    else strptime(x, format, tz = "GMT")
    as.Date(res)
}
<bytecode: 0x265b0ec>
<environment: namespace:base>

Так что в основном, если оба strptime(x, format="%Y-%m-%d")и strptime(x, format="%Y/%m/%d")бросают, NAэто считается неоднозначным, а если и не однозначным.

планнап
источник
6

Преобразование даты без указания текущего формата может легко вызвать эту ошибку.

Вот пример:

sdate <- "2015.10.10"

Преобразовать без указания формата:

date <- as.Date(sdate4) # ==> This will generate the same error"""Error in charToDate(x): character string is not in a standard unambiguous format""".

Преобразование в указанный формат:

date <- as.Date(sdate4, format = "%Y.%m.%d") # ==> Error Free Date Conversion.
ХасанШ__3571619
источник
2

Это отлично работает для меня, независимо от того, как дата была закодирована ранее.

library(lubridate)
data$created_date1 <- mdy_hm(data$created_at)
data$created_date1 <- as.Date(data$created_date1)
Вивиана Ву
источник