Quels sont les formats de «date non ambiguë standard» pour la conversion chaîne à date dans R?

94

Veuillez considérer ce qui suit

$ R --vanilla

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

Mais cette date est clairement dans un format standard non ambigu. Pourquoi le message d'erreur?

Pire encore, une date ambiguë est apparemment acceptée sans avertissement ni erreur puis lue incorrectement!

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

J'ai recherché et trouvé 28 autres questions dans la balise [R] contenant ce message d'erreur. Le tout avec des solutions et des contournements impliquant la spécification du format, iiuc. Cette question est différente en ce que je demande où sont les formats standard non ambigus définis de toute façon, et peuvent-ils être modifiés? Est-ce que tout le monde reçoit ces messages ou est-ce juste moi? Peut-être est-ce lié aux paramètres régionaux?

En d'autres termes, y a-t-il une meilleure solution que de devoir spécifier le format?

29 questions contenant "[R] format standard non ambigu"

> 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
la source
13
à en juger par la définition de la fonction de as.Date.characterl'entrée n'est testé que pour ces deux formats: "%Y-%m-%d"et "%Y/%m/%d". S'il peut correspondre à l'un d'entre eux, il semble être considéré comme "sans ambiguïté".
plannapus
7
@CarlWitthoft "Ai-je même lu" semble impliquer que la réponse est aveuglément évidente ?as.Date. Où cela aide-t-il à cela?
Matt Dowle
2
On peut soutenir que «24 janvier 1949» et «24 janvier 1949» seraient sans ambiguïté, mais ils sont certainement anglo-centriques. Pourtant, il existe également des valeurs pour 'month.abb' qui sont également anglo-centriques, donc un cas pourrait être fait pour que ces valeurs soient mises en correspondance dans les cas où: strptime(xx, f <- "%d $B %Y", tz = "GMT")ou des strptime(xx, f <- "%B $d %Y", tz = "GMT")valeurs renvoyées. (Je ne veux pas dire que month.abbc'est utilisé pour la correspondance avec% B puisque la documentation indique que la correspondance est spécifique à la locale.)
IRTFM
6
@CarlWitthoft Certains d'entre nous trébuchent de temps en temps. Merci pour le coup de pied pendant que je suis à terre. Dans cette question, j'ai bien compris plusieurs choses: j'ai inclus sessionInfo (), j'ai cherché, je vous ai dit ce que j'ai cherché et j'ai inclus un lien, je l'ai gardé aussi concis que possible. J'ai manqué une ligne dans? As.Date et vous me donnez le traitement TFM. Nous ne pouvons pas tous être aussi parfaits que vous tout le temps.
Matt Dowle
1
@MatthewDowle désolé si je suis descendu dur. Je pense que la flamme a commencé quand vous avez semblé confondre «sans ambiguïté pour un humain raisonnablement bien éduqué» avec «sans ambiguïté pour un pauvre morceau de code impuissant». :-(
Carl Witthoft

Réponses:

66

Il s'agit d'un comportement documenté. De ?as.Date:

format: une chaîne de caractères. S'il n'est pas spécifié, il essaiera '"% Y-% m-% d"' puis '"% Y /% m /% d"' sur le premier élément non-'NA ', et donnera une erreur si aucun des deux ne fonctionne.

as.Date("01 Jan 2000")génère une erreur car le format n'est pas l'un des deux répertoriés ci-dessus. as.Date("01/01/2000")renvoie une réponse incorrecte car la date n'est pas dans l'un des deux formats répertoriés ci-dessus.

Je prends «standard sans ambiguïté» pour signifier «ISO-8601» (même si ce as.Daten'est pas si strict, car «% m /% d /% Y» n'est pas ISO-8601).

Si vous recevez cette erreur, la solution consiste à spécifier le format de votre date (ou datetimes), en utilisant les formats décrits dans ?strptime. Assurez-vous de faire particulièrement attention si vos données contiennent des noms de jour / mois et / ou des abréviations, car la conversion dépendra de vos paramètres régionaux (voir les exemples dans ?strptimeet lire ?LC_TIME).

Joshua Ulrich
la source
6
@BenBolker Et pourquoi pas "character string is not either %Y-%m-%d or %Y/%m/%d"?
Matt Dowle
9
Le comportement est certainement documenté dans ?as.Date(+1). Cependant, le message d'erreur "format standard non ambigu" est ironiquement ambigu, ce dont témoignent les 23 questions précédentes. Un message d'erreur plus direct comme "format non reconnu, voir la documentation" peut améliorer l'expérience utilisateur. De plus, je ne crois pas que "01/01/2000" soit ISO-8601 ("2000-01-01" est ISO-8601), ce qui ajoute à l'ambiguïté.
jthetzel
@jthetzel: vous avez raison, "01/01/2000" n'est pas ISO-8601. Je voulais dire que je pense personnellement à ISO-8601 comme étant le format standard sans ambiguïté. Et je conviens que as.Datene pas se plaindre de "01/01/2000" est incompatible avec le message d'erreur.
Joshua Ulrich
31

En d'autres termes, y a-t-il une meilleure solution que de devoir spécifier le format?

Oui, il est maintenant (c. - à la fin de 2016), grâce à anytime::anydatedu moment paquet.

Voir ci-dessous quelques exemples ci-dessus:

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

Comme vous l'avez dit, ceux-ci sont en fait sans ambiguïté et devraient tout simplement fonctionner. Et via anydate()ils le font. Sans format.

Dirk Eddelbuettel
la source
2
Seulement venu ici parce que nous avions une autre question de quelque chose essayant d'analyser des dates avec un format incomplet . Pour les plus complets, nous avons maintenant quelque chose. J'en suis très satisfait - c'était une question lancinante. Et il va sans dire qu'il anytime()est également utile pour POSIXct.
Dirk Eddelbuettel
Je viens d'utiliser le package anytime et cela a fonctionné à merveille, à l'exception de quelques NA. Après avoir exécuté trimws () sur le vecteur de date, tout était parfait.
lawyeR
Je l'utilise aussi une tonne métrique!
Dirk Eddelbuettel
Ça a l'air si simple! J'ai utilisé anydate () sur une colonne avec des valeurs de chaîne de mm-jj (pas de aa). Toutes les valeurs <chr> de la colonne ont été converties avec succès en <date>. Malheureusement, il a fixé l'année à «1400» au lieu de «2020». ¯_ (ツ) _ / ¯
owlstone
Enfin, pas tout à fait. Comme je l'ai répondu à quelques autres questions sur ce site, ce mm-ddn'est pas une date (ni mm-aa ou mm-aaaa). Vous ne pouvez pas analyser ce qu'il n'y a pas.
Dirk Eddelbuettel
26

En complément de la réponse @JoshuaUlrich, voici la définition de la fonction 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>

Donc, fondamentalement, si les deux strptime(x, format="%Y-%m-%d")et strptime(x, format="%Y/%m/%d")jette un, NAil est considéré comme ambigu et sinon sans ambiguïté.

plannapus
la source
6

La conversion de la date sans spécifier le format actuel peut vous apporter cette erreur facilement.

Voici un exemple:

sdate <- "2015.10.10"

Convertir sans spécifier le format:

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

Convertir avec le format spécifié:

date <- as.Date(sdate4, format = "%Y.%m.%d") # ==> Error Free Date Conversion.
HassanSh__3571619
la source
2

Cela fonctionne parfaitement pour moi, peu importe comment la date a été codée précédemment.

library(lubridate)
data$created_date1 <- mdy_hm(data$created_at)
data$created_date1 <- as.Date(data$created_date1)
Viviana Wu
la source