将UTC日期时间转换为带有时区的本地日期时间

问题描述

我有一个包含start_timetimezone列的数据框(如下所示的示例)。 start_time以UTC记录。我想创建一个名为start_time_local的新列,其中包含该记录在本地时区内的开始时间。

我尝试了很多示例,包括format()force_tz()with_tz()等,但是我见过的大多数示例都展示了如何将所有时间戳转换为相同时区,而不是每个时间戳分别为其相应的时区

+---------------------+---------------------+
|     start_time      |      timezone       |
+---------------------+---------------------+
| 2020-07-07 16:01:15 | Europe/dublin       |
| 2020-07-07 21:01:28 | America/Los_Angeles |
| 2020-07-20 12:45:33 | America/New_York    |
| 2020-07-24 16:00:32 | America/Los_Angeles |
| 2020-07-09 14:00:39 | Europe/London       |
| 2020-07-16 20:30:30 | America/Los_Angeles |
| 2020-07-29 14:03:09 | Europe/London       |
| 2020-07-27 20:59:32 | America/Los_Angeles |
| 2020-07-20 16:09:54 | America/Denver      |
| 2020-07-21 09:51:04 | Europe/dublin       |
+---------------------+---------------------+
# example data
df <- structure(list(start_time = structure(c(1594162875,1594180888,1595274333,1595631632,1594328439,1594956630,1596056589,1595908772,1595286594,1595350264),class = c("POSIXct","POSIXt"),tzone = ""),timezone = c("Europe/dublin","America/Los_Angeles","America/New_York","Europe/London","America/Denver","Europe/dublin")),row.names = c(NA,-10L),class = "data.frame")

解决方法

不幸的是,在单个POSIXct向量中不能有不同的时区,因为时区是作为应用于整个向量的单个原子属性存储的。如果您尝试对此属性写入多个时区,则POSIXct的S3方法将停止工作。

如果您热衷于此,可以编写一个新的S3类来处理此类问题。这样一类的裸露骨头看起来像这样:

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,...))
}

这将允许以下行为:

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

尽管要注意-您仍然需要做一些工作才能以使用POSIXct对象的方式使用此类。您仍然可以使用算术函数来添加和减去秒,但是如果您使用lubridate包或类似的包,则除非定义了各种Ops来处理添加持续时间,否则许多方法都不适用于此类。时间段等。