I have one data frame with a lot of locations (around 30.000), and I need to convert the time of each location for the local time. I tried some ideas like this one, and this one. But they did not work for me.
I have data like this:
dt = data.table(date = c("2018-01-16 22:02:37",
"2018-01-16 22:54:00",
"2018-01-16 23:08:38"),
lat = c(-54.5010,
-54.5246,
-54.5285),
long = c(-25.0433,
-25.0929,
-25.0832))
And I expected this output:
date lat long
2018-01-16 20:02:37 -54.5010 -25.0433
2018-01-16 20:54:00 -54.5246 -25.0929
2018-01-16 21:08:38 -54.5285 -25.0832
One try:
library(sf)
dt = data.table(date = c("2018-01-16 22:02:37",
"2018-01-16 22:54:00",
"2018-01-16 23:08:38"),
lat = c(-54.5010,
-54.5246,
-54.5285),
long = c(-25.0433,
-25.0929,
-25.0832))
sdf = st_as_sf(dt, coords = c("long", "lat"), crs = 4326)
## import timezones (after extraction) and intersect with spatial points
tzs = st_read("timezones.geojson/combined.json", quiet = TRUE) #HERE DONT WORK
sdf = st_join(sdf, tzs)
## convert timestamps to local time
sdf$timeL = as.POSIXlt(sdf$time1, tz = as.character(sdf$tzid))
sdf$timeL
Cannot open data source timezones.geojson/combined.json
Error in CPL_read_ogr(dsn, layer, query, as.character(options), quiet, :
Open failed.
Then I tried:
library(lutz)
library(sf)
library(purrr)
library(dplyr)
download.file("https://github.com/evansiroky/timezone-boundary-builder/releases/download/2019a/timezones-with-oceans.geojson.zip",
destfile = "tz.zip")
unzip("tz.zip", exdir = "data-raw/dist/")
tz_full <- read_sf("data-raw/dist/combined-with-oceans.json")
But this didn't work either.
Cannot open data source ~/Dropbox/Érika Project/mestrado_R/bhv_loc_R/tables/data-raw/dist/combined-with-oceans.json
Error in CPL_read_ogr(dsn, layer, query, as.character(options), quiet, :
Open failed.
I got it just like this:
library(lutz)
v <- tz_lookup_coords(lat = dt$lat, lon = dt$lon, method = "accurate")
v1<-as.data.frame(v)
The output:
[1] "America/Bahia" "Etc/GMT+3" "Etc/GMT+3" "Etc/GMT+3" "Etc/GMT+3" "Etc/GMT+3"
But with this output I dont know how can I convert the timezones.
I thought in do something like this:
v1$tzone <- NA
v1[v1$v == "America/Bahia", "tzone"] <- "+3"
v1[v1$v == "America/Sao_Paulo", "tzone"] <- "+3"
v1[v1$v == "Etc/GMT+2", "tzone"] <- "+2"
v1[v1$v == "Etc/GMT+3", "tzone"] <- "+3"
if (v1$tzone == "+3" ) {
v1$timeBR <- NA
v1$timeBR <- strptime(v1$time, format = "%Y-%m-%d %H:%M:%S")
v1$timeBR <- v1$timeBR -3*3600 #creating a column corresponding to local Brazilian time (UTC -3)
v1$hourBR <- as.POSIXlt(v1$timeBR)$hour
v1 <- v1[!is.na(v1$timeBR),]
}
#But the function not works (I dont know do functions), would gonna be better one function with the two condition +3 and +2
EDIT
With the suggestion:
> library(data.table)
data.table 1.12.8 using 2 threads (see ?getDTthreads). Latest news: r-datatable.com
Warning message:
package ‘data.table’ was built under R version 3.5.2
> library(lutz)
Warning message:
package ‘lutz’ was built under R version 3.5.2
> library(purrr)
Attaching package: ‘purrr’
The following object is masked from ‘package:data.table’:
transpose
> library(lubridate)
Attaching package: ‘lubridate’
The following objects are masked from ‘package:data.table’:
hour, isoweek, mday, minute, month, quarter, second, wday, week, yday, year
The following object is masked from ‘package:base’:
date
#t it is the original data
> head(t$time)
[1] 2017-10-16 17:01:00 2017-10-16 18:35:22 2017-10-16 20:38:54 2017-10-16 21:27:27 2017-10-16 21:43:20
[6] 2017-10-16 23:24:46
27092 Levels: 2016-10-24 15:42:00 2016-10-24 21:03:28 2016-10-24 22:04:35 2016-10-24 23:13:40 ... 2020-01-10 11:34:21
> class(t$time)
[1] "factor"
> date2<-t$time
> class(date2)
[1] "factor"
> date2<- as.character(t$time)
> class(date2)
[1] "character"
> head(date2)
[1] "2017-10-16 17:01:00" "2017-10-16 18:35:22" "2017-10-16 20:38:54" "2017-10-16 21:27:27" "2017-10-16 21:43:20"
[6] "2017-10-16 23:24:46"
> t[, date2 := as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")][,
+ timezone := tz_lookup_coords(lat = lat, lon = long, method = "accurate")][,
+ new_time := map2(.x = date2, .y = timezone,
+ .f = function(x, y) {with_tz(time = x, tzone = y)})][]
Error in `:=`(date2, as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")) :
Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").
EDIT2
I found what was going wrong, my original data wasn't in data.table and data.frame format! Then, now I have this list inside the data. Im trying to convert in one new column
EDIT 3
NOW WORKED! THANKS TO ALL FOR COMMENTS AND HELP
t[, date2 := as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")]
[,timezone := tz_lookup_coords(lat = lat, lon = lon, method = "accurate")]
[,new_time := map2(.x = date2, .y = timezone,
.f = function(x, y) {with_tz(time = x, tzone = y)})][]
newtime<-do.call(rbind, lapply(t$new_time, as.data.frame))
t$newtime<-paste(newtime$`X[[i]]`)
head(t$newtime)
[1] "2016-10-24 12:42:00" "2016-10-24 18:03:28" "2016-10-24 19:04:35" "2016-10-24 20:13:40" "2016-10-24 21:13:00"
[6] "2016-10-25 02:17:05"
Someone know how to do this? Thanks
read_sf
and notst_read
as per the previous answer. Does that make a difference? – Zinkst_read
, dint work too.. – Narra