聚合函数和时区

Aggregate function and timezone

我有两段代码理论上做同样的事情:

Mn_min_max_D <- with(Mn, aggregate(Depth ~ as.Date(Date_time), FUN =  function(x) c(Min = min(x), Max = max(x))))
Mn_min_max_D <- do.call(data.frame, Mn_min_max_D)
names(Mn_min_max_D)[names(Mn_min_max_D) == "as.Date.Date_time."] <- "Date"

min_max_D <- with(Mn, aggregate(Depth ~ as.Date(Date), FUN =  function(x) c(Min = min(x), Max = max(x))))
min_max_D <- do.call(data.frame, min_max_D)
names(Mn_min_max_D)[names(min_max_D) == "as.Date.Date_time."] <- "Date"

但是输出值不同。在检查最大深度时,我发现由于某种原因,第一段代码忽略了时区。 例如,最大深度发生在“2013-10-26 22:33:00”,但经过时区校正后,这实际上是“2013-10-27 07:33:00”。

$Date 值来自此代码:

Mn$Date_time <- as.POSIXct(Mn$Date_time, format="%Y-%m-%d %H:%M:%S", tz = "Asia/Tokyo")
    Mn$Date <- format(as.POSIXct(Mn$Date_time, format="%YYYY/%m/%d %H:%M:%S"), format = "%Y/%m/%d")
    Mn$Date <- as.Date(Mn$Date, "%Y/%m/%d")

似乎删除时间的过程可以修复日期。我需要了解问题的根源,以确保我以后不会犯错。

我想我可能需要用 tz 进行 %>% 变异,但目前不明白怎么做。或者可能使用 dplyr 聚合而不是如下所示,但我已经尝试过并且结果是相同的。

test <- Mn %>% group_by(as.Date(Date_time))%>% dplyr::summarise(min = min(Depth), max = max(Depth))

示例数据:

Date_time Depth
2013-10-14 12:30:00 64.45
2013-10-14 12:30:05 65.95
2013-10-14 12:30:10 65.95
2013-10-14 12:30:15 66.45
2013-10-14 12:30:20 67.95
2013-10-14 12:30:25 66.95

在目前的格式中,数据不包含时区,因此使用默认时区。如果您知道这些时间戳的时区,最好对其进行明确控制。

dta <- with(
    asNamespace("readr"),
    read_table(
        file = "
Date_time Depth
2013-10-14-12:30:00 64.45
2013-10-14-12:30:05 65.95
2013-10-14-12:30:10 65.95
2013-10-14-12:30:15 66.45
2013-10-14-12:30:20 67.95
2013-10-14-12:30:25 66.95",
col_types = cols(
    Date_time = col_datetime(format = "%Y-%m-%d-%H:%M:%S"),
    Depth = col_double()
)
    )
)

library("lubridate")
library("tidyverse")
dta %>%
    mutate(DT_tz = force_tz(Date_time, tzone = "GMT"),
           DT_tz_NYC = with_tz(Date_time, tzone = "America/New_York"))

说明

考虑以下因素:

  • tz(now()) returns 一个空字符串
  • Sys.timezone() returns 本地时区,"Europe/London" 在我的例子中
  • tz(as.Date(now())) returns "UTC"

不指定时区 R 取决于您的本地设置

as.POSIXlt(Sys.time(), "America/New_York")
# "2022-03-18 12:43:10 EDT"
as.POSIXlt(Sys.time())
# "2022-03-18 16:43:16 GMT"

这可能有点繁琐。

tz(as.POSIXlt(Sys.time()))
# [1] "Europe/London"
tz(as.Date(as.POSIXlt(Sys.time())))
# "UTC"

特别值得一提的是,使用 as.Date 会去除时区信息。

tz(as.Date(as.POSIXlt(Sys.time())))
"UTC"
tz(as.Date(as.POSIXlt(Sys.time()), tz = "Africa/Abidjan"))
"UTC"

解决方案

如果处理时间戳,始终建议确保在该数据中重新编码时区信息,或者作为替代方案,在脚本中明确说明不太可靠的选项。就个人而言,我认为时区组件是时间戳的组成部分,应该与数据一起驻留。当本地化时间戳不同时,从时间戳中剥离时区信息会导致混淆。显着差异可能会导致不同的日期(考虑 2 小时时区差异和接近午夜发生的事件等)。