Why does as.character() return an integer on a list of dates?

The issue ultimately has to do with the behavior of the function as.vector().

When you apply as.character() to a list, it sees an object of class "list" (not one of class "Date"). Since there is no as.character() method for lists, the default method as.character.default gets dispatched. Its does the following:

as.character.default
# function (x, ...) 
# .Internal(as.vector(x, "character"))
# <bytecode: 0x0000000006793e88>
# <environment: namespace:base>

As you can see, it first prepares the data object by coercing it to a vector. Running as.vector() directly on a list of Date objects shows, in turn, that it is what is producing the coercion to integer and then to character.

as.vector(list(Sys.Date()), "character")
# [1] "17567"

As Carl points out, the explanation above, even if accurate, is not really satisfying. A more complete answer requires looking at what happens under the hood, in the C code executed by the call to .Internal(as.vector(x, "character")). All of the relevant C code is in the source file coerce.c.

First up is do_asvector() which calls ascommon() which calls coerceVector() which calls coerceVectorList() and then, finally, coerceToString(). coerceToString() examines the "typeof" the element it is processing, and in our case, seeing that it is a "REAL" switches to this code block:

case REALSXP:
PrintDefaults();
savedigits = R_print.digits; R_print.digits = DBL_DIG;/* MAX precision */
for (i = 0; i < n; i++) {
//  if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
    SET_STRING_ELT(ans, i, StringFromReal(REAL(v)[i], &warn));
}
R_print.digits = savedigits;
break;

And why does it use the block for objects of with a typeof REALSXP? Because that's the storage mode of R Date objects (as can be seen by doing mode(Sys.Date()) or typeof(Sys.Date())).


The take-home is this: In the chain of events described above, the elements of the list are not somehow caught and treated as a "Date" objects while in the realm of R function calls and method dispatch. Instead, they get passed along as a "list" (aka VECSXP) to a series of C functions. And at that point, it's kind of too late, as the C functions that process that list know nothing about the "Date" class of its elements. In particular, the function that ultimately does the conversion to character, coerceToCharacter() only sees the elements' storage mode, which is REAL/numeric/double, and processes them as if that was all that they were.


You can achieve what you want with the functionformat as in

format(Sys.Date(), "%a %b %d")

Sys.Date gives a Date object and there are many ways to convert that to a string, so a special function is due. format will give you a character representation of your Date.

BTW: If you just hit Sys.Date() on the console, this will invoke print.Date which internally uses format as well, as you can see by typing print.Date without brackets () at the console.

Tags:

String

Date

R