60

can anyone tell me why R give such outcome below:

> as.POSIXct("2013-01-01 08:00")
[1] "2013-01-01 08:00:00 HKT"
> as.Date(as.POSIXct("2013-01-01 08:00"))
[1] "2013-01-01"
> as.POSIXct("2013-01-01 07:00")
[1] "2013-01-01 07:00:00 HKT"
> as.Date(as.POSIXct("2013-01-01 07:00"))
[1] "2012-12-31"

Shouldn't it be 2013-01-01 after converting POSIXct to Date for 2013-01-01 07:00, is there any way to change the cutoff from 08:00 to 00:00?

Update #1

I found the following can fix my problem, but in a less neat way

> as.Date(as.character(as.POSIXct("2013-01-01 07:00")))
[1] "2013-01-01"
lokheart
  • 23,743
  • 39
  • 98
  • 169
  • There is a similar question and answers here that may be of interest: https://stackoverflow.com/questions/62743019/wrong-date-when-converting-posixct-date-time-to-date-timezone-not-fixing-it/62743807#62743807 – G. Grothendieck Jul 05 '20 at 19:47

3 Answers3

51

The problem here is timezones - you can see you're in "HKT". Try:

as.Date(as.POSIXct("2013-01-01 07:00", 'GMT'))
[1] "2013-01-01"

From ?as.Date():

["POSIXct" is] converted to days by ignoring the time after midnight in the representation of the time in specified timezone, default UTC

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
alexwhan
  • 15,636
  • 5
  • 52
  • 66
35

Use the time zone parameter of as.Date:

as.Date(as.POSIXct("2013-01-01 07:00",tz="Hongkong"))
#[1] "2012-12-31"

as.Date(as.POSIXct("2013-01-01 07:00",tz="Hongkong"),tz="Hongkong")
#[1] "2013-01-01"

In fact, I recommend always using the tz parameter when using date-time converting functions. There are other nasty surprises, e.g. with daylight saving time.

Roland
  • 127,288
  • 10
  • 191
  • 288
  • 3
    Worth mentioning after hinting at the daylight saving one, that sometimes you need to put tz="" to get it to work properly. I don't really know why, I just avoid `POSIXct` at all costs. – Corvus Oct 23 '14 at 14:15
  • 3
    This is the best answer (And should get the green tick) as it is more thorough and precise regarding the tz argument applied in date (NOT `as.POSIXct`), not the green ticked answer by the OP. –  Aug 02 '17 at 17:31
4

This happens as documented and previously explained when contemporaneous UTC time is before (your third example) or after midnight on your POSIXct date. To see the math for yourself, inspect as.Date.POSIXct at the console. The math under the default tz="UTC" is clear. In the non-default case, R essentially calls as.Date.POSIXlt, and the date-travel does not occur. In fact, if you had started with the lt object you would not have had this problem:

> as.Date(as.POSIXlt("2013-01-01 07:00", tz = "Hongkong"))  
[1] "2013-01-01"

The easiest work-around is to call as.Date with tz="" to force using the less offending as.Date.POSIXlt algorithm:

> as.Date(as.POSIXct("2013-01-01 07:00"), tz = "")  
[1] "2013-01-01"
Dan Murphy
  • 51
  • 1
  • I need to correct myself. tz="" does not always work. If you never want to change the timezone of your POSIXct object, x, go straight to POSIXlt first, then to Date: as.Date(as.POSIXlt(x)) – Dan Murphy Feb 19 '19 at 22:40