7

I have a data set with the following information: latitude, longitude, EST time. For example, for one observation

lat = 13
long = -2
time1 = as.POSIXlt("2014-02-12 17:00:00", tz = "EST")

I want to create a new variable timeL that is the local time. Any suggestions of how to do this with R?

Thanks!

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
Ignacio
  • 7,646
  • 16
  • 60
  • 113

2 Answers2

14
lat = 13
long = -2
time1 <- as.POSIXct("2014-02-12 17:00:00", tz = "EST")
# https://developers.google.com/maps/documentation/timezone/
apiurl <- sprintf("https://maps.googleapis.com/maps/api/timezone/%s?location=%s,%s&timestamp=%d&sensor=%s", 
                  "xml", 
                  lat, 
                  long, 
                  as.numeric(time1), 
                  "false")
library(XML)
tz <- xmlParse(readLines(apiurl))[["string(//time_zone_id)"]]
as.POSIXct(format(time1, tz=tz))
# [1] "2014-02-12 22:00:00 CET"

or, as suggested by @SymbolixAU, use their googleway package:

res <- googleway::google_timezone(c(lat, long), time1, key = NULL)
as.POSIXct(format(time1, tz=res$timeZoneId))
# [1] "2014-02-12 22:00:00 CET"
lukeA
  • 53,097
  • 5
  • 97
  • 100
  • 2
    there's also the API wrapper `google_timezone()` in my `googleway` pacakge that avoids having to parse the XML yourself. – SymbolixAU Sep 10 '17 at 23:08
  • With lat = 114 I get tz = "", why? – Claudia Dec 11 '18 at 13:11
  • @Claudia What tz would you expect? – lukeA Dec 24 '18 at 11:48
  • Hi, I tried your solution, but for some reason the output is GMT, even though my coordinates are Lat - 3, Lon 160. I have tried both solutions: `time1 <- as.POSIXct("2015-10-30 03:50:00", tz = "UTC")` `res <- googleway::google_timezone(c(-3, 162), time1, key = NULL)` `as.POSIXct(format(time1, tz=res$timeZoneId))` – Paperwing Dec 12 '19 at 17:12
4

An alternate approach is to intersect the target point coordinates with a shapefile of global time zones and subsequently convert the EST timestamps to the local time at each spatial point. For example, boundaries of the world's time zones are available from Timezone Boundary Builder (direct download).

library(sf)

## example data
dat = data.frame(lon = -2
                 , lat = 13
                 , time1 = as.POSIXlt("2014-02-12 17:00:00", tz = "EST"))

## convert to 'sf' object
sdf = st_as_sf(dat, coords = c("lon", "lat"), crs = 4326)

## import timezones (after extraction) and intersect with spatial points
tzs = st_read("timezones.geojson/combined.json", quiet = TRUE)
sdf = st_join(sdf, tzs)

## convert timestamps to local time
sdf$timeL = as.POSIXlt(sdf$time1, tz = as.character(sdf$tzid))
sdf$timeL
# [1] "2014-02-12 22:00:00 GMT"

Note that the corresponding time zone Africa/Ouagadougou is GMT.

fdetsch
  • 5,239
  • 3
  • 30
  • 58
  • Instead of doing a full `st_intersection` you could also use `st_join` (just replace in the code) to joint the timezone attributes to the point. For this example this may not relevant, but `st_join` is usually much faster for larger data sets and for point-in-polygon queries produces identical results. – TimSalabim Apr 24 '18 at 08:25
  • Agreed, thanks for pointing this out. See also [Vectorize `st_intersection`](https://github.com/r-spatial/sf/issues/575) issue on GitHub. – fdetsch Apr 24 '18 at 10:09