R - форматирование дат в кадре данных - сочетание десятичных и символьных значений

У меня есть столбец даты в кадре данных. Я прочитал этот df в R, используя openxlsx. Столбец "видится" как вектор символов, когда я использую typeof(df$date).

Столбец содержит информацию о дате в нескольких форматах, и я хочу получить ее в одном формате.

#Example
date <- c("43469.494444444441", "12/31/2019 1:41 PM", "12/01/2019  16:00:00")

#What I want -updated
fixed <- c("2019-04-01", "2019-12-31", "2019-12-01")

Я пробовал много обходных путей, включая openxlsx::ConvertToDate, lubridate::parse_date_time, lubridate::date_decimal

openxlsx::ConvertToDateпока работает лучше всего, но он будет принимать только 1 формат и принуждать NA для других

обновить

Я понял, что на самом деле у меня была неправильная одна из указанных выше дат вывода. Значение 43469,494444444441 должно быть преобразовано в 2019-04-01.


person AudileF    schedule 02.01.2020    source источник


Ответы (2)


Вы можете использовать вспомогательную функцию для нормализации дат, которая может быть немного быстрее, чем lubridate.

В MS Excel есть странные источники, которые зависят от Платформа. Поэтому, если данные импортируются с разных платформ, вы можете работать с фиктивными переменными.

normDate <- Vectorize(function(x) {
if (!is.na(suppressWarnings(as.numeric(x))))  # Win excel
  as.Date(as.numeric(x), origin="1899-12-30")
else if (grepl("A|P", x))
  as.Date(x, format="%m/%d/%Y %I:%M %p")
else
  as.Date(x, format="%m/%d/%Y %R")
})

Для дополнительных форматов даты просто добавьте еще один else if. Спецификации формата можно найти с помощью ?strptime.

Тогда просто используйте as.Date() с обычным происхождением.

res <- as.Date(normDate(date), origin="1970-01-01")
# 43469.494444444441   12/31/2019 1:41 PM 12/01/2019  16:00:00 
#       "2019-01-04"         "2019-12-31"         "2019-12-01"
class(res)
# [1] "Date"

Изменить. Чтобы получить определенный выходной формат, используйте format, например.

format(res, "%Y-%d-%m")
# 43469.494444444441   12/31/2019 1:41 PM 12/01/2019  16:00:00 
#       "2019-04-01"         "2019-31-12"         "2019-01-12" 

format(res, "%Y/%d/%m")
# 43469.494444444441   12/31/2019 1:41 PM 12/01/2019  16:00:00 
#       "2019/04/01"         "2019/31/12"         "2019/01/12" 

Для поиска кодов введите ?strptime.

person jay.sf    schedule 02.01.2020
comment
Кажется, это работает лучше всего. Только в моем фактическом df некоторые даты имеют неправильный день и месяц, например. 10 апреля 2019 года сообщается как 2019-10-04 вместо 2019-04-10. - person AudileF; 03.01.2020
comment
as.Date("10Apr19", format="%d%b%y") выполняет эту работу? Вы можете найти другие строки формата, набрав ?strptime. - person jay.sf; 06.01.2020
comment
Спасибо jay.sf, дата 10Apr19 присутствует в моем df как 43469.494444444441. Я хочу, чтобы R представлял как 2019-04-10, но когда я использую приведенный выше код, он сообщает об этом как 2019-10-04. - person AudileF; 13.01.2020
comment
Спасибо jay.sf, но если вы посмотрите выше, другие даты теперь неверны. Я думаю, что данные слишком беспорядочны, чтобы с ними работать. Тем не менее, большое спасибо за помощь :) - person AudileF; 15.01.2020
comment
@AudileF Будет ли лучше, если вы обернете format() внутри формулы, то есть format(as.Date(as.numeric(x), origin="1899-12-30"), "%Y-%d-%m")? - person jay.sf; 15.01.2020

Вот один из способов сделать это в два этапа. Измените даты Excel отдельно, а все остальные даты по-другому. Если у вас есть еще форматы дат, которые можно добавить в parse_date_time.

temp <- lubridate::parse_date_time(date, c('mdY IMp', 'mdY HMS'))
temp[is.na(temp)] <- as.Date(as.numeric(date[is.na(temp)]), origin = "1899-12-30")

temp
#[1] "2019-01-04 11:51:59 UTC" "2019-12-31 13:41:00 UTC" "2019-12-01 16:00:00 UTC"
as.Date(temp)
#[1] "2019-01-04" "2019-12-31" "2019-12-01"
person Ronak Shah    schedule 02.01.2020
comment
Спасибо, мне нравится это решение. У меня работало, когда я использовал read_excel - person Jd Baba; 24.03.2020