Onset dates converted to NA in Ebola surveillance exercise

Issue:

I am working with onset dates. I need to convert the onset_date variable from character format to the Date class so that it can be used to create an epidemic curve. After using ymd(), the column class changes to Date, but all the values become NA. I also receive the warning: “All formats failed to parse. No formats found.”

Steps taken to find an answer:

I reviewed the Epi R Handbook information about R projects and working with dates. I also checked the class and range of the cleaned date variable to identify where the problem occurred. The original values are written with slashes, but I am unsure why ymd() cannot interpret them or which date conversion function should be used.

Example R code:

pacman::p_load(
 rio,
 here,
 janitor,
 tidyverse,
 reprex,
 datapasta
)

# Create a minimal synthetic version
surv_raw <- data.frame(
 stringsAsFactors = FALSE,
 case_id = c(
   "694928",
    "86340d",
    "92d002",
    "544bd1",
    "6056ba"
  ),
  sex = c("m", "f", "f", "f", "f"),
  onset_date = c(
    "11/9/2014",
    "10/30/2014",
    "8/16/2014",
    "8/29/2014",
    "10/20/2014"
  )
)

# Trying to convert the column to class Date
surv_clean <- surv_raw %>%
  clean_names() %>%
  mutate(onset_date = ymd(onset_date))
#> Warning: There was 1 warning in `mutate()`.
#> ℹ In argument: `onset_date = ymd(onset_date)`.
#> Caused by warning:
#> ! All formats failed to parse. No formats found.

# Checking the cleaned date column class and range
class(surv_clean$onset_date)
#> [1] "Date"

range(surv_clean$onset_date)
#> [1] NA NA

Why are the original onset dates being converted to NA, even though the column class changes to Date? How should I modify the date conversion command so that these month/day/year values are interpreted correctly?

Thank you in advance for your help.

The issue is the order of the date components, not the / separator.

lubridate::ymd() expects dates in year-month-day order. Your values are in month-day-year order:

"11/9/2014"
"10/30/2014"
"8/16/2014"

So you should use mdy() instead:

library(lubridate)
library(dplyr)

surv_clean <- surv_raw %>%
  clean_names() %>%
  mutate(onset_date = mdy(onset_date))

Now:

class(surv_clean$onset_date)
#> [1] "Date"

range(surv_clean$onset_date)
#> [1] "2014-08-16" "2014-11-09"

The important point is that the lubridate function name tells R the order in which the date components appear:

ymd("2014/11/09")  # year-month-day
mdy("11/09/2014")  # month-day-year
dmy("09/11/2014")  # day-month-year

Best,

Luis