Modifying timezone of a POSIXct object without changing the display

北慕城南 提交于 2019-12-20 10:39:32

问题


I have a POSIXct object and would like to change it's tz attribute WITHOUT R to interpret it (interpret it would mean to change how the datetime is displayed on the screen).

Some background: I am using the fasttime package from S.Urbanek, which take strings and cast it to POSIXct very quickly. Problem is that the string should represent a datetime in "GMT" and it's not the case of my data.

I end up with a POSIXct object with tz=GMT, in reality it is tz=GMT+1, if I change the timezone with

attr(datetime, "tzone") <- "Europe/Paris";
datetime  <- .POSIXct(datetime,tz="Europe/Paris"); 

then it will be "displayed" as GMT+2 (the underlying value never change).

EDIT: Here is an example

datetime=as.POSIXct("2011-01-01 12:32:23.234",tz="GMT")
attributes(datetime)
#$tzone
#[1] "GMT"
datetime
#[1] "2011-01-01 12:32:23.233 GMT"

How can I change this attribute without R to interpret it aka how can I change tzone and still have datetime displayed as "2011-01-01 12:32:23.233" ?

EDIT/SOLUTION, @GSee's solution is reasonably fast, lubridate::force_tz very slow

datetime=rep(as.POSIXct("2011-01-01 12:32:23.234",tz="GMT"),1e5)
f <- function(x,tz) return(as.POSIXct(as.numeric(x), origin="1970-01-01", tz=tz))
> system.time(datetime2 <- f(datetime,"Europe/Paris"))
   user  system elapsed 
   0.01    0.00    0.02 
> system.time(datetime3 <- force_tz(datetime,"Europe/Paris"))
   user  system elapsed 
   5.94    0.02    5.98 
identical(datetime2,datetime3)
[1] TRUE

回答1:


EDITED:

My previous solution was passing a character value to origin (i.e.origin="1970-01-01"). That only worked here because of a bug (#PR14973) that has now been fixed in R-devel.

origin was being coerced to POSIXct using the tz argument of the as.POSIXct call, and not "GMT" as it was documented to do. The behavior has been changed to match the documentation which, in this case, means that you have to specify your timezone for both the origin and the as.POSIXct call.

datetime
#[1] "2011-01-01 12:32:23.233 GMT"
as.POSIXct(as.numeric(datetime), origin=as.POSIXct("1970-01-01", tz="Europe/Paris"),
           tz="Europe/Paris")
#[1] "2011-01-01 12:32:23.233 CET"

This will also works in older versions of R.




回答2:


To change the tz attribute of a POSIXct variable it is not best practice to convert to character or numeric and then back to POSIXct. Instead you could use the force_tz function of the lubridate package

library(lubridate)

datetime2 <- force_tz(datetime, tzone = "CET")
datetime2
attributes(datetime2)



回答3:


An alternative to the lubridate package is via conversion to and back from character type:

recastTimezone.POSIXct <- function(x, tz) return(
  as.POSIXct(as.character(x), origin = as.POSIXct("1970-01-01"), tz = tz))

(Adapted from GSee's answer)

Don't know if this is efficient, but it would work for time zones with daylight savings.

Test code:

x <- as.POSIXct('2003-01-03 14:00:00', tz = 'Etc/UTC')
x
recastTimezone.POSIXct(x, tz = 'Australia/Melbourne')

Output:

[1] "2003-01-03 14:00:00 UTC"
[1] "2003-01-03 14:00:00 AEDT" # Nothing is changed apart from the time zone.

Output if I replaced as.character() by as.numeric() (as GSee had done):

[1] "2003-01-03 14:00:00 UTC"
[1] "2003-01-03 15:00:00 AEDT" # An hour is added.


来源:https://stackoverflow.com/questions/15575713/modifying-timezone-of-a-posixct-object-without-changing-the-display

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!