从纬度和经度 R 转换为本地时区

Éri*_*lho 6 timezone r localtime latitude-longitude lubridate

我有一个包含很多位置(大约 30.000 个)的数据框,我需要将每个位置的时间转换为当地时间。\n我尝试了一些想法,例如这个这个。但他们不适合我。

\n\n

我有这样的数据:

\n\n
dt = data.table(date = c("2018-01-16 22:02:37",\n                         "2018-01-16 22:54:00", \n                         "2018-01-16 23:08:38"),\n                lat = c(-54.5010,\n                        -54.5246,\n                        -54.5285),\n                long = c(-25.0433, \n                         -25.0929,\n                         -25.0832))\n
Run Code Online (Sandbox Code Playgroud)\n\n

我期望这个输出:

\n\n
date                      lat           long\n2018-01-16 20:02:37       -54.5010      -25.0433\n2018-01-16 20:54:00       -54.5246      -25.0929\n2018-01-16 21:08:38       -54.5285      -25.0832\n
Run Code Online (Sandbox Code Playgroud)\n\n

一试:

\n\n
library(sf)\ndt = data.table(date = c("2018-01-16 22:02:37",\n                         "2018-01-16 22:54:00", \n                         "2018-01-16 23:08:38"),\n                lat = c(-54.5010,\n                        -54.5246,\n                        -54.5285),\n                long = c(-25.0433, \n                         -25.0929,\n                         -25.0832))\n\nsdf = st_as_sf(dt, coords = c("long", "lat"), crs = 4326)\n\n## import timezones (after extraction) and intersect with spatial points\ntzs = st_read("timezones.geojson/combined.json", quiet = TRUE) #HERE DONT WORK\nsdf = st_join(sdf, tzs)\n\n## convert timestamps to local time\nsdf$timeL = as.POSIXlt(sdf$time1, tz = as.character(sdf$tzid))\nsdf$timeL\n
Run Code Online (Sandbox Code Playgroud)\n\n
Cannot open data source timezones.geojson/combined.json\n\nError in CPL_read_ogr(dsn, layer, query, as.character(options), quiet,  :\n  Open failed.\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我尝试:

\n\n
library(lutz)\nlibrary(sf)\nlibrary(purrr)\nlibrary(dplyr)\n\ndownload.file("https://github.com/evansiroky/timezone-boundary-builder/releases/download/2019a/timezones-with-oceans.geojson.zip",\n              destfile = "tz.zip")\nunzip("tz.zip", exdir = "data-raw/dist/")\ntz_full <- read_sf("data-raw/dist/combined-with-oceans.json")\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这也不起作用。

\n\n
Cannot open data source ~/Dropbox/\xc3\x89rika Project/mestrado_R/bhv_loc_R/tables/data-raw/dist/combined-with-oceans.json\nError in CPL_read_ogr(dsn, layer, query, as.character(options), quiet,  : \n  Open failed.\n
Run Code Online (Sandbox Code Playgroud)\n\n

我得到的就像这样:

\n\n
library(lutz)\n\nv <- tz_lookup_coords(lat = dt$lat, lon = dt$lon, method = "accurate")\nv1<-as.data.frame(v)\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
[1] "America/Bahia" "Etc/GMT+3"     "Etc/GMT+3"     "Etc/GMT+3"     "Etc/GMT+3"     "Etc/GMT+3"   \n
Run Code Online (Sandbox Code Playgroud)\n\n

但有了这个输出,我不知道如何转换时区。

\n\n

我想做这样的事情:

\n\n
v1$tzone <- NA\nv1[v1$v == "America/Bahia", "tzone"] <- "+3" \nv1[v1$v == "America/Sao_Paulo", "tzone"] <- "+3" \nv1[v1$v == "Etc/GMT+2", "tzone"] <- "+2" \nv1[v1$v == "Etc/GMT+3", "tzone"] <- "+3" \n\n  if (v1$tzone == "+3" ) {\n  v1$timeBR <- NA\n  v1$timeBR <- strptime(v1$time, format = "%Y-%m-%d %H:%M:%S")\n  v1$timeBR <- v1$timeBR -3*3600 #creating a column corresponding to local Brazilian time (UTC -3)\n  v1$hourBR <- as.POSIXlt(v1$timeBR)$hour\n  v1 <- v1[!is.na(v1$timeBR),]\n  }\n\n#But the function not works (I dont know do functions), would gonna be better one function with the two condition +3 and +2 \n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑

\n\n

随着建议:

\n\n
> library(data.table)\ndata.table 1.12.8 using 2 threads (see ?getDTthreads).  Latest news: r-datatable.com\nWarning message:\npackage \xe2\x80\x98data.table\xe2\x80\x99 was built under R version 3.5.2 \n> library(lutz)\nWarning message:\npackage \xe2\x80\x98lutz\xe2\x80\x99 was built under R version 3.5.2 \n> library(purrr)\n\nAttaching package: \xe2\x80\x98purrr\xe2\x80\x99\n\nThe following object is masked from \xe2\x80\x98package:data.table\xe2\x80\x99:\n\n    transpose\n\n> library(lubridate)\n\nAttaching package: \xe2\x80\x98lubridate\xe2\x80\x99\n\nThe following objects are masked from \xe2\x80\x98package:data.table\xe2\x80\x99:\n\n    hour, isoweek, mday, minute, month, quarter, second, wday, week, yday, year\n\nThe following object is masked from \xe2\x80\x98package:base\xe2\x80\x99:\n\n    date\n\n#t it is the original data\n> head(t$time)\n[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\n[6] 2017-10-16 23:24:46\n27092 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\n> class(t$time)\n[1] "factor"\n> date2<-t$time\n> class(date2)\n[1] "factor"\n> date2<- as.character(t$time)\n> class(date2)\n[1] "character"\n> head(date2)\n[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"\n[6] "2017-10-16 23:24:46"\n> t[, date2 := as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")][,\n+                                                                          timezone := tz_lookup_coords(lat = lat, lon = long, method = "accurate")][,\n+                                                                                                                                                    new_time := map2(.x = date2, .y = timezone, \n+                                                                                                                                                                     .f = function(x, y) {with_tz(time = x, tzone = y)})][]\nError in `:=`(date2, as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")) : \n  Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑2

\n\n

我发现出了什么问题,我的原始数据不是 data.table 和 data.frame 格式!\n然后,现在我在数据中有这个列表。我正在尝试在一个新列中进行转换

\n\n

编辑3

\n\n

现在工作了!感谢大家的评论和帮助

\n\n
t[, date2 := as.POSIXct(date2, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")]\n[,timezone := tz_lookup_coords(lat = lat, lon = lon, method = "accurate")]\n[,new_time := map2(.x = date2, .y = timezone,\n.f = function(x, y) {with_tz(time = x, tzone = y)})][]\n\nnewtime<-do.call(rbind, lapply(t$new_time, as.data.frame))\nt$newtime<-paste(newtime$`X[[i]]`)\n\nhead(t$newtime)\n[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"\n[6] "2016-10-25 02:17:05"\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

有人知道怎么做吗?\n谢谢

\n

jaz*_*rro 4

我想这就是你想要的。我首先创建了一个日期对象。然后,我按照tz_lookup_coords()您的尝试搜索了时区。然后,我使用with_tz(),它获取不同时区的日期时间。请注意,这new_time是一个如所示的列表str(dt)

\n\n
library(data.table)\nlibrary(lutz)\nlibrary(purrr)\nlibrary(lubridate)\n\ndt[, date := as.POSIXct(date, format = "%Y-%m-%d %H:%M:%S", tz = "GMT")][,\n    timezone := tz_lookup_coords(lat = lat, lon = long, method = "accurate")][,\n      new_time := map2(.x = date, .y = timezone, \n                       .f = function(x, y) {with_tz(time = x, tzone = y)})][]\n\n#                  date      lat     long  timezone            new_time\n#1: 2018-01-16 22:02:37 -54.5010 -25.0433 Etc/GMT+2 2018-01-16 20:02:37\n#2: 2018-01-16 22:54:00 -54.5246 -25.0929 Etc/GMT+2 2018-01-16 20:54:00\n#3: 2018-01-16 23:08:38 -54.5285 -25.0832 Etc/GMT+2 2018-01-16 21:08:38\n\n#str(dt)\n#Classes \xe2\x80\x98data.table\xe2\x80\x99 and \'data.frame\': 3 obs. of  5 variables:\n# $ date    : POSIXct, format: "2018-01-16 22:02:37" "2018-01-16 22:54:00" "2018-01-16 23:08:38"\n# $ lat     : num  -54.5 -54.5 -54.5\n# $ long    : num  -25 -25.1 -25.1\n# $ timezone: chr  "Etc/GMT+2" "Etc/GMT+2" "Etc/GMT+2"\n# $ new_time:List of 3\n#  ..$ : POSIXct, format: "2018-01-16 20:02:37"\n#  ..$ : POSIXct, format: "2018-01-16 20:54:00"\n#  ..$ : POSIXct, format: "2018-01-16 21:08:38"\n
Run Code Online (Sandbox Code Playgroud)\n\n

更多帮助

\n\n

如果您有数据框,您也可以使用 tidyverse 方法。我dt这里用的是你的。我将其转换为 data.frame 对象。您需要的最后一个薄层是unnest()。然后,您将有时间写专栏。

\n\n
setDF(dt) %>% \nmutate(date = as.POSIXct(date, format = "%Y-%m-%d %H:%M:%S", tz = "GMT"),\n       timezone = tz_lookup_coords(lat = lat, lon = long, method = "accurate"),\n       new_time = map2(.x = date, .y = timezone, \n                       .f = function(x, y) {with_tz(time = x, tzone = y)})) %>% \nunnest(new_time) \n\n   date                  lat  long timezone  new_time           \n  <dttm>              <dbl> <dbl> <chr>     <dttm>             \n1 2018-01-16 22:02:37 -54.5 -25.0 Etc/GMT+2 2018-01-16 20:02:37\n2 2018-01-16 22:54:00 -54.5 -25.1 Etc/GMT+2 2018-01-16 20:54:00\n3 2018-01-16 23:08:38 -54.5 -25.1 Etc/GMT+2 2018-01-16 21:08:38\n\n> str(foo)\nClasses \xe2\x80\x98tbl_df\xe2\x80\x99, \xe2\x80\x98tbl\xe2\x80\x99 and \'data.frame\':   3 obs. of  5 variables:\n $ date    : POSIXct, format: "2018-01-16 22:02:37" "2018-01-16 22:54:00" "2018-01-16 23:08:38"\n $ lat     : num  -54.5 -54.5 -54.5\n $ long    : num  -25 -25.1 -25.1\n $ timezone: chr  "Etc/GMT+2" "Etc/GMT+2" "Etc/GMT+2"\n $ new_time: POSIXct, format: "2018-01-16 20:02:37" "2018-01-16 20:54:00" "2018-01-16 21:08:38"\n
Run Code Online (Sandbox Code Playgroud)\n

  • @ÉrikaSoaresCoelho 我为你添加了 tydyverse 方法。关键是使用`unnest()`。我希望这对你来说已经足够了。 (2认同)