How do you convert dates/times from one time zone to another in R?

Package lubridate holds two functions to convert timezones. According to the help pages:


force_tz returns a date-time that has the same clock time as x in the new time zone.

force_tz(time, tzone = "America/Los_Angeles")


with_tz changes the time zone in which an instant is displayed. The clock time displayed for the instant changes, but the moment of time described remains the same.

with_tz(time, tzone = "America/Los_Angeles")

Use attr() (base R) or lubridate::with_tz() (tidyverse) to view the same moment of time in a different time zone.

The internal value of a POSIXct object is always in UTC (number of seconds since the beginning of 1970; see ?DateTimeClasses, but the displayed time when printed is determined by the tzone attribute. So change the tzone attribute (via attr() or lubridate::with_tz()) to display/print the same moment of time in a different time zone.

For example:

pb.txt <- "2009-06-03 19:30"  
pb.date <- as.POSIXct(pb.txt, tz="Europe/London") 

Note tzone attribute determines time zone used when displayed/printed:

attributes(pb.date)$tzone
[1] "Europe/London"

pb.date
[1] "2009-06-03 19:30:00 BST"

Note that internal value is seconds since origin in UTC, regardless of tzone attribute:

as.numeric(pb.date)
[1] 1244053800

In base R, the tzone attribute can be set/changed using attr():

attr(pb.date, "tzone") <- "America/Los_Angeles"

pb.date  
[1] "2009-06-03 11:30:00 PDT"  

Equivalently, use lubridate::with_tz() (which also uses attr):

pb.date <- lubridate::with_tz(pb.date, "America/Los_Angeles")

Note that display time is now local clock time in PDT:

pb.date  
[1] "2009-06-03 11:30:00 PDT"

but internal value has not changed:

as.numeric(pb.date)
[1] 1244053800

so tzone does not affect any operations, only the displayed value when printed.


First, convert the London time to a POSIXct object:

pb.txt <- "2009-06-03 19:30"
pb.date <- as.POSIXct(pb.txt, tz="Europe/London")

Then use format to print the date in another time zone:

> format(pb.date, tz="America/Los_Angeles",usetz=TRUE)
[1] "2009-06-03 11:30:00 PDT"

There are some tricks to finding the right time zone identifier to use. More details in this post at the Revolutions blog: Converting time zones in R: tips, tricks and pitfalls


If you'd like to do this in one line, recall that any POSIXct object in R is really just a number (seconds UTC since epoch beginning), and that the "timezone" is just an attribute that determines how that number is printed.

Therefore, we can use the .POSIXct helper function as follows:

x = as.POSIXct("2009-06-03 19:30", tz = "Europe/London")
.POSIXct(as.integer(x), tz = 'America/Los_Angeles')
# [1] "2009-06-03 11:30:00 PDT"

as.integer strips the class and attributes of x, and .POSIXct is shorthand for constructing a POSIXct object; if your object has milliseconds and you'd like to keep track of them, you can use as.numeric(x).