strptime, как.POSIXct и как.Дата возвращает неожиданный NA

#r

#r #macos #datetime #strptime #r-faq

Вопрос:

Когда я пытаюсь проанализировать временную метку в следующем формате: «Чт, 8 ноября, 15:41: 45 2012», возвращается только NA .

Я использую Mac OS X, R 2.15.2 и Rstudio 0.97.237. Язык моей операционной системы — голландский: я предполагаю, что это как-то связано с этим.

Когда я пытаюсь strptime , NA возвращается:

 var <- "Thu Nov 8 15:41:45 2012"
strptime(var, "%a %b %d %H:%M:%S %Y")
# [1] NA
  

Ни то, ни другое не as.POSIXct работает:

 as.POSIXct(var, "%a %b %d %H:%M:%S %Y")
# [1] NA
  

Я также пробовал as.Date с приведенной выше строкой, но без %H:%M:%S компонентов:

 as.Date("Thu Nov 8 2012", "%a %b %d %Y")
# [1] NA
  

Есть идеи, что я мог делать неправильно?

Ответ №1:

Я думаю, что это именно так, как вы догадались, strptime не удается проанализировать вашу строку даты и времени из-за ваших локализаций. Ваша строка содержит как сокращенный день недели ( %a ), так и сокращенное название месяца ( %b ). Эти временные спецификации описаны в ?strptime :

Подробные сведения

%a : Сокращенное название дня недели в текущей локали на этой платформе

%b : Сокращенное название месяца в текущей локали на этой платформе.

«Обратите внимание, что сокращенные имена зависят от платформы (хотя стандарты указывают, что в C локали они должны быть первыми тремя буквами английского имени с заглавной буквы:»

«Знание аббревиатур важно, если вы хотите использовать %a , %b или %h как часть формата ввода: смотрите примеры, как проверить».

Смотрите также

[…] locales для запроса или установки локали.

Проблема locales также актуальна для as.POSIXct , as.POSIXlt и as.Date .

От ?as.POSIXct :

Подробные сведения

Если format указано, помните, что некоторые спецификации формата зависят от локали, и вам может потребоваться соответствующим образом задать LC_TIME категорию через Sys.setlocale . Это чаще всего влияет на использование %b , %B (названия месяцев) и %p (AM / PM).

От ?as.Date :

Подробные сведения

Преобразования в символьные строки и из символьных строк, зависящие от локали, используются там, где это уместно и доступно. Это влияет на названия дней и месяцев.


Таким образом, если названия дней недели и месяцев в строке отличаются от названий в текущей локали, strptime , as.POSIXct и as.Date не удается правильно проанализировать строку и NA возвращается.

Однако вы можете решить эту проблему, изменив locales :

 # First save your current locale
loc <- Sys.getlocale("LC_TIME")

# Set correct locale for the strings to be parsed
# (in this particular case: English)
# so that weekdays (e.g "Thu") and abbreviated month (e.g "Nov") are recognized
Sys.setlocale("LC_TIME", "en_GB.UTF-8")
# or
Sys.setlocale("LC_TIME", "C") 

#Then proceed as you intended
x <- "Thu Nov 8 15:41:45 2012" 
strptime(x, "%a %b %d %H:%M:%S %Y")
# [1] "2012-11-08 15:41:45"

# Then set back to your old locale
Sys.setlocale("LC_TIME", loc) 
  

С моим личным языком я могу воспроизвести вашу ошибку:

 Sys.setlocale("LC_TIME", loc)
# [1] "fr_FR.UTF-8"

strptime(var,"%a %b %d %H:%M:%S %Y")
# [1] NA
  

Ответ №2:

Я просто возился с той же проблемой и обнаружил, что это решение намного чище, потому что нет необходимости изменять какие-либо системные настройки вручную, потому что в lubridate пакете есть функция-оболочка, выполняющая эту работу, и все, что вам нужно сделать, это установить аргумент locale :

 date <- c("23. juni 2014", "1. november 2014", "8. marts 2014", "16. juni 2014", "12. december 2014", "13. august 2014")
df$date <- dmy(df$Date, locale = "Danish")
[1] "2014-06-23" "2014-11-01" "2014-03-08" "2014-06-16" "2014-12-12" "2014-08-13"
  

Комментарии:

1. Что касается » нет необходимости изменять какие-либо системные настройки «, пожалуйста, обратите внимание, что locale аргумент в lubridate функциях — это просто удобная оболочка шагов, описанных в ответе выше: (1) сохранить текущую локаль, (2) изменить локаль, (3) вернуться к исходной локали. Проверьте код здесь : orig_locale <- Sys.getlocale("LC_TIME"); Sys.setlocale("LC_TIME", locale); on.exit(Sys.setlocale("LC_TIME", orig_locale))

2. или locale = "da_DK"