Jakie są „standardowe jednoznaczne formaty daty” dla konwersji ciągów na datę w języku R?

94

Proszę wziąć pod uwagę następujące kwestie

$ R --vanilla

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

Ale ta data jest najwyraźniej w standardowym, jednoznacznym formacie. Dlaczego komunikat o błędzie?

Co gorsza, niejednoznaczna data jest najwyraźniej akceptowana bez ostrzeżenia lub błędu, a następnie odczytywana nieprawidłowo!

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

Przeszukałem i znalazłem 28 innych pytań w tagu [R] zawierającym ten komunikat o błędzie. Wszystko z rozwiązaniami i obejściami obejmującymi określenie formatu, iiuc. To pytanie jest inne, ponieważ pytam, gdzie i tak zdefiniowano standardowe, jednoznaczne formaty i czy można je zmienić? Czy wszyscy dostają te wiadomości, czy to tylko ja? Być może jest to związane z lokalizacją?

Innymi słowy, czy istnieje lepsze rozwiązanie niż konieczność określenia formatu?

29 pytań zawierających „[R] standardowy, jednoznaczny format”

> 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
Matt Dowle
źródło
13
sądząc po definicji funkcji as.Date.characterwejścia, jest testowany tylko dla tych dwóch formatów: "%Y-%m-%d"i "%Y/%m/%d". Jeśli pasuje do jednego z nich, wydaje się, że jest to „jednoznaczne”.
plannapus
7
@CarlWitthoft „Czy nawet czytałem” wydaje się sugerować, że odpowiedź jest oślepiająco oczywista ?as.Date. Gdzie to pomaga?
Matt Dowle,
2
Prawdopodobnie „24 stycznia 1949 r.” I „24 stycznia 1949 r.” Byłyby jednoznaczne, ale z pewnością są one anglo-centryczne. Jednak istnieją również wartości dla „month.abb”, które również są anglo-centryczne, więc można by uzasadnić dopasowanie tych wartości w przypadkach, gdy: strptime(xx, f <- "%d $B %Y", tz = "GMT")lub strptime(xx, f <- "%B $d %Y", tz = "GMT")zwrócone wartości. (Nie sugeruję, że month.abbjest używany do dopasowania do% B, ponieważ dokumentacja mówi, że dopasowanie jest specyficzne dla ustawień regionalnych.)
IRTFM
6
@CarlWitthoft Niektórzy z nas potykają się od czasu do czasu. Dzięki za kopnięcie, kiedy jestem na dole. W tym pytaniu kilka rzeczy się zgadza: dołączyłem sessionInfo (), szukałem, powiedziałem ci, czego szukałem i dołączyłem link, trzymałem go tak dokładnie, jak to tylko możliwe. Przegapiłem jedną linię w? As Date i daj mi leczenie TFM. Nie możemy przez cały czas być tak doskonali jak Ty.
Matt Dowle,
1
@MatthewDowle przepraszam, jeśli ciężko upadłem. Myślę, że płomienność zaczęła się, gdy wydawało się, że pomyliłeś „jednoznaczne dla dość dobrze wykształconego człowieka” z „jednoznacznym dla biednego, bezradnego kodu”. :-(
Carl Witthoft,

Odpowiedzi:

66

To jest udokumentowane zachowanie. Od ?as.Date:

format: ciąg znaków. Jeśli nie zostanie określony, spróbuje '"% Y-% m-% d"', a następnie '"% Y /% m /% d"' na pierwszym elemencie innym niż 'NA' i wyświetli błąd, jeśli żaden z nich nie zadziała.

as.Date("01 Jan 2000")zwraca błąd, ponieważ format nie jest jednym z dwóch wymienionych powyżej. as.Date("01/01/2000")zwraca nieprawidłową odpowiedź, ponieważ data nie jest w jednym z dwóch formatów wymienionych powyżej.

Przyjmuję „standard jednoznaczny” jako „ISO-8601” (chociaż as.Datenie jest to aż tak ścisłe, ponieważ „% m /% d /% Y” nie jest ISO-8601).

Jeśli pojawi się ten błąd, rozwiązaniem jest określenie formatu daty (lub godzin) przy użyciu formatów opisanych w ?strptime. Zachowaj szczególną ostrożność, jeśli Twoje dane zawierają nazwy dni / miesięcy i / lub skróty, ponieważ konwersja będzie zależała od ustawień regionalnych (zobacz przykłady wi ?strptimeprzeczytaj ?LC_TIME).

Joshua Ulrich
źródło
6
@BenBolker A może "character string is not either %Y-%m-%d or %Y/%m/%d"?
Matt Dowle,
9
Zachowanie jest z pewnością udokumentowane w ?as.Date(+1). Jednak komunikat o błędzie „standardowy, jednoznaczny format” jest ironicznie niejednoznaczny, o czym świadczą 23 poprzednie pytania. Bardziej bezpośredni komunikat o błędzie, np. „Format nierozpoznany, zobacz dokumentację”, może poprawić komfort użytkowania. Nie uważam też, że „01/01/2000” to ISO-8601 („2000-01-01” to ISO-8601), co zwiększa niejednoznaczność.
jthetzel,
@jthetzel: masz rację, „01/01/2000” to nie ISO-8601. Chodziło mi o to, że osobiście uważam ISO-8601 za standardowy, jednoznaczny format. I zgadzam się, że as.Datenie narzekanie na „01/01/2000” jest niezgodne z komunikatem o błędzie.
Joshua Ulrich
31

Innymi słowy, czy istnieje lepsze rozwiązanie niż konieczność określenia formatu?

Tak, jest teraz (tj. Pod koniec 2016 r.), Dzięki anytime::anydatez pakietu Anytime .

Poniżej znajdziesz kilka przykładów z góry:

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

Jak powiedziałeś, są one w rzeczywistości jednoznaczne i powinny po prostu działać. I przez anydate()nich robią. Bez formatu.

Dirk Eddelbuettel
źródło
2
Przyszedłem tutaj tylko dlatego, że mieliśmy kolejne pytanie dotyczące czegoś, co próbowało przeanalizować daty z niekompletnym formatem. Jeśli chodzi o kompletne, teraz coś mamy. Jestem z tego całkiem zadowolony - to było dokuczliwe pytanie. I nie trzeba dodawać, że anytime()jest równie przydatny dla POSIXct.
Dirk Eddelbuettel
Po prostu skorzystałem z pakietu w dowolnym momencie i działało cudownie, z wyjątkiem kilku NA. Po uruchomieniu trimws () na wektorze daty wszystko było idealne.
prawnik
Używam go też tony metrycznej!
Dirk Eddelbuettel,
Wygląda tak prosto! Użyłem anydate () w kolumnie z wartościami ciągów mm-dd (bez rr). Wszystkie wartości <chr> w kolumnie zostały pomyślnie przekonwertowane na <date>. Niestety ustawił rok na „1400” zamiast „2020”. ¯_ (ツ) _ / ¯
owlstone
Cóż, niezupełnie. Jak odpowiedziałem w kilku innych pytaniach na tej stronie, mm-ddnie jest datą (ani mm-rr, ani mm-rrrr). Nie możesz przeanalizować tego, czego tam nie ma.
Dirk Eddelbuettel
26

Jako uzupełnienie odpowiedzi @JoshuaUlrich, oto definicja funkcji 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>

Zasadniczo więc, jeśli oba strptime(x, format="%Y-%m-%d")i strptime(x, format="%Y/%m/%d")rzuca NA, jest uważane za niejednoznaczne, a jeśli nie jednoznaczne.

plannapus
źródło
6

Konwersja daty bez określenia bieżącego formatu może łatwo przynieść ten błąd.

Oto przykład:

sdate <- "2015.10.10"

Konwertuj bez określania formatu:

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

Konwertuj w określonym formacie:

date <- as.Date(sdate4, format = "%Y.%m.%d") # ==> Error Free Date Conversion.
HassanSh__3571619
źródło
2

U mnie działa to idealnie, bez względu na to, jak wcześniej zakodowano datę.

library(lubridate)
data$created_date1 <- mdy_hm(data$created_at)
data$created_date1 <- as.Date(data$created_date1)
Viviana Wu
źródło