Converting Utc Time to Local Standard Time in R

Converting UTC time to local standard time in R

First, POSIXct date-times are always UCT internally. The print.POSIXt and format.POSIXt methods will appropriately make the TZ shift on output from their internal representations:

pb.date <- as.POSIXct(Sys.Date())
Sys.Date()
#[1] "2015-07-09"

So that was midnight of the current date in Greenwich:

format(pb.date, tz="America/Los_Angeles",usetz=TRUE)
#[1] "2015-07-08 17:00:00 PDT"

When it's midnight in Greenwich, it's 5PM Daylight Time in the previous day on the Left Coast of the US. You need to use the correct character values for your TZ (and your OS) both of which at the moment are unspecified.

The US Pacific timezone is 8 hours behind GMT (in winter months) so you can use a timezone that is Standard/Daylight-agnostic:

> format(pb.date,usetz=TRUE, tz="Etc/GMT+8")
[1] "2015-07-08 16:00:00 GMT+8"

(Notice the reversal of + with "behind" and - with "ahead".)

How to convert date and time from UTC to local time in R?

The default format of as.POSIXct expects an date ordered by Year-Month-Day. Therefore the date 01/04/2020 is translated into the 20th April of Year 1.

You just need to add your timeformat to as.POSIXct:

vlinder$dateandtime <- as.POSIXct(vlinder$dateandtime, tz = "UTC", format = "%d/%m/%Y %H:%M:%S")

format(vlinder$dateandtime, tz = "Europe/Brussels", usetz = TRUE)

Convert UTC datetime to local datetime with timezone

Unfortunately you cannot have different time zones within a single POSIXct vector, because the timezone is stored as a single atomic attribute that applies to the whole vector. If you try to write multiple timezones to this attribute, the S3 methods for POSIXct will stop working.

If this is something you are very keen to pursue you can write a new S3 class to handle this kind of problem. The very bare bones of such a class would look something like this:

POSIX_multi_tz <- function(UTC_times, time_zones)
{
structure(as.numeric(UTC_times),
class = c("POSIXmulti", "POSIXt"),
tz = time_zones)
}

format.POSIXmulti <- function(x, ...)
{
unlist(mapply(function(a, b) {
format(as.POSIXct(a, origin = "1970-01-01"), tz = b, usetz = TRUE)
}, a = x, b = attr(x, "tz"), SIMPLIFY = FALSE))
}

print.POSIXmulti <- function(x, ...)
{
print(format(x, ...))
}

This would allow for the following behaviour:

df$new_time <- POSIX_multi_tz(df$start_time, df$timezone)

df
#> start_time timezone new_time
#> 1 2020-07-08 00:01:15 Europe/Dublin 2020-07-08 00:01:15 IST
#> 2 2020-07-08 05:01:28 America/Los_Angeles 2020-07-07 21:01:28 PDT
#> 3 2020-07-20 20:45:33 America/New_York 2020-07-20 15:45:33 EDT
#> 4 2020-07-25 00:00:32 America/Los_Angeles 2020-07-24 16:00:32 PDT
#> 5 2020-07-09 22:00:39 Europe/London 2020-07-09 22:00:39 BST
#> 6 2020-07-17 04:30:30 America/Los_Angeles 2020-07-16 20:30:30 PDT
#> 7 2020-07-29 22:03:09 Europe/London 2020-07-29 22:03:09 BST
#> 8 2020-07-28 04:59:32 America/Los_Angeles 2020-07-27 20:59:32 PDT
#> 9 2020-07-21 00:09:54 America/Denver 2020-07-20 17:09:54 MDT
#> 10 2020-07-21 17:51:04 Europe/Dublin 2020-07-21 17:51:04 IST

Beware though - you would still have a bit of work to do to be able to use this class the way you would use POSIXct objects. You can still use arithmetic functions to add and substract seconds, but if you use the lubridate package or similar, many of the methods will not work for this class unless you define various Ops to handle adding durations, periods etc.

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

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

convert local dateTime to UTC in R

If you want to shift a datetime from your current timezone to UTC, you need to
import in your local timezone, then just shift the display timezone to "UTC". e.g.: in Australian EST I am UTC+10.

out <- as.POSIXct("12/31/2014 6:42:52 PM", format="%m/%d/%Y %H:%M:%S")
out
#"2014-12-31 06:42:52 EST"
#(Australian Eastern Standard Time)
as.numeric(out)
#[1] 1419972172

Now shift the timezone for display purposes:

attr(out, "tzone") <- "UTC" 
out
#[1] "2014-12-30 20:42:52 UTC"
# display goes 10 hours backwards as I'm UTC+10
as.numeric(out)
#[1] 1419972172

Note that this doesn't affect the underlying numeric data (seconds since 1970-01-01), it only changes what is displayed.

Converting local date-times from a large dataset with multiple time zones into UTC

The error is due to the timeZone column being a factor instead of a character vector, use stringsAsFactors = FALSE when defining the data.frame to specify timeZone as a character column. You can also avoid any loops by using vectorized functions from the lubridate package:

library(lubridate)

df <- data.frame(
"localDate" = c("2015-04-20","2016-07-17","2015-08-06"),
"localTime" = c("14:00", "14:46", "10:35"),
"timeZone" = c("Pacific/Pago_Pago", "Pacific/Saipan", "Pacific/Honolulu"),
stringsAsFactors = FALSE
)

df$eventDate <- force_tzs(ymd_hm(with(df, paste(localDate, localTime))), tzones = df$timeZone)

df
#> localDate localTime timeZone eventDate
#> 1 2015-04-20 14:00 Pacific/Pago_Pago 2015-04-21 01:00:00
#> 2 2016-07-17 14:46 Pacific/Saipan 2016-07-17 04:46:00
#> 3 2015-08-06 10:35 Pacific/Honolulu 2015-08-06 20:35:00

Edit: in case of missing values, check for each row whether it can be converted and if not return NA. Below an example solution using base R:

df <- data.frame(
"localDate" = c("2015-04-20","2016-07-17","2015-08-06", "2019-01-01", "2019-01-01"),
"localTime" = c("14:00", "14:46", "10:35", NA, "00:00"),
"timeZone" = c("Pacific/Pago_Pago", "Pacific/Saipan", "Pacific/Honolulu",
"Pacific/Honolulu", NA),
stringsAsFactors = FALSE
)

df$eventDate <- apply(df, 1, function(row) {
ifelse(any(is.na(row)), NA_character_,
format(as.POSIXct(paste(row["localDate"], row["localTime"]), "%Y-%m-%d %H:%M",
tz = row["timeZone"]), tz = "UTC", usetz = TRUE)
)
})
df
#> localDate localTime timeZone eventDate
#> 1 2015-04-20 14:00 Pacific/Pago_Pago 2015-04-21 01:00:00 UTC
#> 2 2016-07-17 14:46 Pacific/Saipan 2016-07-17 04:46:00 UTC
#> 3 2015-08-06 10:35 Pacific/Honolulu 2015-08-06 20:35:00 UTC
#> 4 2019-01-01 <NA> Pacific/Honolulu <NA>
#> 5 2019-01-01 00:00 <NA> <NA>

R Change from stardard UTC time zone to multiple local time zones

Multiple problems here:

  1. format (and other time-related functions) only takes a length-1 argument for tz;
  2. time zones recognized by R do not include the popular "CST", "PST", etc.

To fix the first, the use of Map or mapply will suffice.

The second requires a little more research, unfortunately. Zones like "PST" and such, though popular in at least the US if not other countries, are not valid time zone strings (ref: CCTZ, a C++ library for translating between time zones, says so). Neither are "GMT-7", et al, though the latter can be faked by prepending with Etc/, as in: "Etc/GMT-7". Or you can go with the alternatives of "America/New_York" or "US/Eastern".

df$time_zone <- c("US/Eastern", "US/Pacific", "US/Central", "US/Eastern")
df
# day time_zone
# 1 2018-12-06 15:40:29 US/Eastern
# 2 2018-12-06 15:25:28 US/Pacific
# 3 2018-12-06 15:25:28 US/Central
# 4 2018-12-06 14:09:09 US/Eastern
mapply(format, df$day, tz = "GMT")
# [1] "2018-12-06 15:40:29" "2018-12-06 15:25:28" "2018-12-06 15:25:28"
# [4] "2018-12-06 14:09:09"
mapply(format, df$day, tz = df$time_zone)
# [1] "2018-12-06 10:40:29" "2018-12-06 07:25:28" "2018-12-06 09:25:28"
# [4] "2018-12-06 09:09:09"

All of the immediately-recognizable formats for R's time zones are found in a 594-element vector:

str(OlsonNames())
# chr [1:592] "Africa/Abidjan" "Africa/Accra" "Africa/Addis_Ababa" ...
# - attr(*, "Version")= chr "2018e"
set.seed(2)
sample(OlsonNames(), size=8)
# [1] "America/El_Salvador" "Etc/GMT+8" "Atlantic/Madeira"
# [4] "America/Creston" "Pacific/Port_Moresby" "Pacific/Ponape"
# [7] "America/Atka" "GB-Eire"
grep("US/", OlsonNames(), value = TRUE)
# [1] "US/Alaska" "US/Aleutian" "US/Arizona"
# [4] "US/Central" "US/East-Indiana" "US/Eastern"
# [7] "US/Hawaii" "US/Indiana-Starke" "US/Michigan"
# [10] "US/Mountain" "US/Pacific" "US/Pacific-New"
# [13] "US/Samoa"

In this example, you'll see one of the alternatives you can use: "Etc/GMT+8". Notice that + is to the west of the prime meridian, so

mapply(format, df$day, tz = "US/Eastern")
# [1] "2018-12-06 10:40:29" "2018-12-06 10:25:28" "2018-12-06 10:25:28"
# [4] "2018-12-06 09:09:09"
mapply(format, df$day, tz = "Etc/GMT+5")
# [1] "2018-12-06 10:40:29" "2018-12-06 10:25:28" "2018-12-06 10:25:28"
# [4] "2018-12-06 09:09:09"

Caveat emptor: using "US/Eastern" should take into account daylight savings where appropriate; "Etc/GMT+5" does not, I believe.



Related Topics



Leave a reply



Submit