Search code examples
rzooposixct

write.zoo() changed behavior since R 4.3.0: as.character.POSIXct() changed?


Sunday seemed to be a good day to update R from version 4.2.3 to 4.3.2 (on Win 10) to start with something up-to-date into a new week.

I was using the zoo package for some time series writing to basic text files for saving data. This worked for years, but after the above upgrade I encountered a change in the output where suddenly midnight times are left out:

Code to test (using zoo version 1.8.12):

library(zoo)
write.zoo(
  zoo(
    c(46, 47),
    c(as.POSIXct("2023-11-26 00:00:00"), as.POSIXct("2023-11-26 01:00:00"))
  )
)

With R prior to 4.3.0 the result looks like:

"2023-11-26 00:00:00" 46
"2023-11-26 01:00:00" 47

But starting with 4.3.0 it changed to:

"2023-11-26" 46
"2023-11-26 01:00:00" 47

As documentation of zoo says that write.zoo() is a convenience function for write.table() I tried to substitute with this getting proper results (with midnight timestamps) again:

write.table(
  zoo(
    c(46, 47),
    c(as.POSIXct("2023-11-26 00:00:00"), as.POSIXct("2023-11-26 01:00:00"))
  )
)

outputs

"2023-11-26 00:00:00" 46
"2023-11-26 01:00:00" 47

under any mentioned version of R.

So it seems like the write.zoo function has been broken by R >= 4.3.0, but the story continues...

As one can see in zoo sources this function is rather simple and produces a data.frame from the zoo object by copying the index while using as.character().

Testing again this very simple call on POSIXct objects

R <4.3.0:

> as.character(c(as.POSIXct("2023-11-26 00:00:00"), as.POSIXct("2023-11-26 01:00:00")))
[1] "2023-11-26 00:00:00" "2023-11-26 01:00:00"

R >=4.3.0:

> as.character(c(as.POSIXct("2023-11-26 00:00:00"), as.POSIXct("2023-11-26 01:00:00")))
[1] "2023-11-26"          "2023-11-26 01:00:00"

tells me, that this might be the reason for failure of write.zoo()

Now I'm puzzled because that is very basic R-functionality which was not mentioned to be changing in the R News. The output also looks awkward - why should there be two different formats be produced?

There is another question on R write.table remove 0:00:00 from Timestamps which uses write.table() directly on data.frame (so no zoo here) and yields the same results also in my case:

> write.table(data.frame(Index = c(as.POSIXct("2023-11-26 00:00:00"), as.POSIXct("2023-11-26 01:00:00")), Value = c(46, 47)), row.names = FALSE)
"Index" "Value"
2023-11-26 46
2023-11-26 01:00:00 47

So obviously my "workaround" by using write.table() on zoo objects only works because those objects are different internally. Unfortunately is beyond my understanding of R as well as if the as.character() behavior is intended and useful.

Any further explanation from the community on this?


Solution

  • Thanks for reporting this problem. As others have already pointed out in the comments, the issue was triggered by a change in behavior of as.character() for POSIXt object.

    I have just committed an update to write.zoo() on R-Forge which now uses format(index(x)) rather than the old as.character(index(x)) (which never was an ideal choice to begin with).

    The update can be installed from R-Forge via

    install.packages("zoo", repos="https://R-Forge.R-project.org")