Why is the class type in mapply(as.POSIXct , myCSV) not recognised as POSIX type?
I have a list of dates in character/string format and I need to read them as POSIXct
dates.
> x <- as.POSIXct("95-11-22" , format="%y-%m-%d") #should equal myParsedDates[1]
> typeof(x)
[1] "double"
> class(x)
[1] "POSIXct" "POSIXt" #Member of POSIXct class
> myDates <- c("95-11-22", "95-11-23", "95-12-25")
> myParsedDates <- mapply(function(x){as.POSIXct(x, format="%y-%m-%d")} , myDates)
> typeof(myParsedDates[1])
[1] "double"
> class(myParsedDates[1])
[1] "numeric" #Not a member of POSIXct
> x #The class information is retained
[1] "1995-11-22 AWST"
> myParsedDates[1] #The class information is lost
95-11-22
816969600
Why, when mapply
is called on the list, does the POSIXct
class information get lost? How can it be retained?
This is in essence a more complicated version of the (known, documented, still sad) mis-feature of S3 class attributes dropping when concatenating vectors.
I am using as.Date()
here (and a string that parses without format), but it is the same with as.POSIXct()
.
First, what works:
> as.Date("2022-01-16")
[1] "2022-01-16"
> as.Date("2022-01-16")
[1] "2022-01-16"
>
Second, what doesn't _because sapply
constructs a vector:
> sapply(c("2022-01-16", "2022-01-17"), as.Date)
2022-01-16 2022-01-17
19008 19009
> class(sapply(c("2022-01-16", "2022-01-17"), as.Date))
[1] "numeric"
>
The actual names comes back because sapply
is kind to use them as label, but the result is not longer a Date
object. For completeness, same with as.POSIXct
:
> as.POSIXct("2022-01-16")
[1] "2022-01-16 CST"
> class(as.POSIXct("2022-01-16"))
[1] "POSIXct" "POSIXt"
> class(sapply(c("2022-01-16", "2022-01-17"), as.POSIXct))
[1] "numeric"
>
It works via lapply
and do.call()
:
> do.call(c, lapply(c("2022-01-16", "2022-01-17"), as.Date))
[1] "2022-01-16" "2022-01-17"
> class(do.call(c, lapply(c("2022-01-16", "2022-01-17"), as.Date)))
[1] "Date"
>
It also works if you make the objects part of a data.frame
and stack the data.frame
rows, and/or if you inject them into pre-allocated vectors, or ... if one simply calls vectorised:
> as.Date(c("2022-01-16", "2022-01-17"))
[1] "2022-01-16" "2022-01-17"
> class(as.Date(c("2022-01-16", "2022-01-17")))
[1] "Date"
>
which is of course not always possible.