【问题标题】:Unable to modify timezone when creating date from datetime从日期时间创建日期时无法修改时区
【发布时间】:2025-11-29 16:55:02
【问题描述】:

我今天在尝试从日期时间列创建日期列并且无法保留正确的时区时遇到了一个有趣的问题。问题是,在下面的示例中,为什么似乎无法修改“日期”列的时区?

这是一个可重现的例子:

library(lubridate)

# create a short datetime sequence
df <- data.frame(datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))

# check the timezone -- it is UTC
tz(df$datetime)

# convert to PST
df$datetime <- force_tz(df$datetime, "US/Pacific")

# confirm -- OK
tz(df$datetime) # [1] "US/Pacific"

# now create a date column based on the datetime column
df$date <- as.Date(df$datetime)

# might think it would be PST, but it's UTC
tz(df$date)

# attempt to change it manually to PST
df$date <- force_tz(df$date, tz="US/Pacific")

# doesn't work
tz(df$date) # [1] "UTC"

# seems we're stuck -- the date column reflects UTC and changes to January 2nd at 4PM on 1/1
# in the datetime column
df[15:20,]

输出在技术上是正确的(即 8 小时偏移量),但在两列中有两个不同的时区似乎非常令人困惑。

              datetime       date
15 2020-01-01 14:00:00 2020-01-01
16 2020-01-01 15:00:00 2020-01-01
17 2020-01-01 16:00:00 2020-01-02
18 2020-01-01 17:00:00 2020-01-02
19 2020-01-01 18:00:00 2020-01-02
20 2020-01-01 19:00:00 2020-01-02

【问题讨论】:

  • 可能检查您的 R/lubridate 版本,因为 force_tz 对我有用(lubridate 1.7.9,R 4.0.2)。
  • 感谢@heds1,对 1.7.9 的更新似乎确实修复了“日期”列的标称时区,但随后输出与上面示例中的输出相同,其中日期仍然提前到 1 月 2 日下午 4 点在日期时间列中。这也是你得到的吗?

标签: r datetime timezone lubridate


【解决方案1】:

真恶心。我无法解释为什么 tz 参数在您尝试过时不起作用。这是我会做的。经过一点实验,我发现替换

df$date <- as.Date(df$datetime)

df$date <- with_tz(date(df$datetime), tz="US/Pacific")

给出想要的结果:

tz(df$date)
[1] "US/Pacific"

[df$date &lt;- with_tz(as.Date(df$datetime), tz="US/Pacific") 也可以。]

@heds1:force_tz 对我来说失败了,对于 OP 来说。选中sessionInfo() 输出:

R version 3.6.3 (2020-02-29)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.6
lubridate_1.7.4 

更新

没有人在他们的 cmets 中足够清楚地确定确切正在运行什么代码来生成每组结果。但我想我可能有混淆的根源:它是df$date &lt;- force_tz(df$date, tz="US/Pacific")

force_tzonline doc:“force_tz 返回与输入时间具有相同时钟时间但在新时区的日期时间”,而with_tzsame sentence 读取"with_tz 返回一个日期时间,因为它会出现在不同的时区"。

区别很微妙但很重要:force_tz 只是替换时区字段的值,不影响时钟时间,而with_tz 将时钟时间映射到同一时刻新时区中的相应时钟时间.

为了清楚起见,稍微修改了 OP 的代码:

# create a short datetime sequence
df <- data.frame(utc_datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))
# check the timezone -- it is UTC
tz(df$utc_datetime)
[1] "UTC"
# convert to PST
df$pst_datetime <- with_tz(df$utc_datetime, tz="US/Pacific")
# confirm -- OK
tz(df$pst_datetime) # [1] "US/Pacific"
[1] "US/Pacific"
# Convert UTC datetime to Date
df$utc_date <- with_tz(date(df$utc_datetime))
tz(df$utc_date)
[1] "UTC"
# Convert PST datetime to Date
df$pst_date <- with_tz(date(df$pst_datetime), tz="US/Pacific")
tz(df$pst_date)
[1] "US/Pacific"
# List to show behaviour around midnight for both UTC and PST
df[22:35,]
          utc_datetime        pst_datetime   utc_date   pst_date
22 2020-01-01 21:00:00 2020-01-01 13:00:00 2020-01-01 2020-01-01
23 2020-01-01 22:00:00 2020-01-01 14:00:00 2020-01-01 2020-01-01
24 2020-01-01 23:00:00 2020-01-01 15:00:00 2020-01-01 2020-01-01
25 2020-01-02 00:00:00 2020-01-01 16:00:00 2020-01-02 2020-01-01
26 2020-01-02 01:00:00 2020-01-01 17:00:00 2020-01-02 2020-01-01
27 2020-01-02 02:00:00 2020-01-01 18:00:00 2020-01-02 2020-01-01
28 2020-01-02 03:00:00 2020-01-01 19:00:00 2020-01-02 2020-01-01
29 2020-01-02 04:00:00 2020-01-01 20:00:00 2020-01-02 2020-01-01
30 2020-01-02 05:00:00 2020-01-01 21:00:00 2020-01-02 2020-01-01
31 2020-01-02 06:00:00 2020-01-01 22:00:00 2020-01-02 2020-01-01
32 2020-01-02 07:00:00 2020-01-01 23:00:00 2020-01-02 2020-01-01
33 2020-01-02 08:00:00 2020-01-02 00:00:00 2020-01-02 2020-01-02
34 2020-01-02 09:00:00 2020-01-02 01:00:00 2020-01-02 2020-01-02
35 2020-01-02 10:00:00 2020-01-02 02:00:00 2020-01-02 2020-01-02

【讨论】:

  • 谢谢@Limey。更新到 lubridate 1.7.9 并使用您对 'df$date
  • R 版本 3.6.2 (2019-12-12) 平台:x86_64-apple-darwin15.6.0 (64-bit) 运行于:macOS Mojave 10.14.6
  • 我会接受这个答案,因为它确实确定了影响最终产品的机制并提供了功能性解决方法。但是,我仍然相信“lubridate”如何处理具有不同时区的这些列存在一些“错误”。如果你回头看看我最初的 reprex,你会发现我对“force_tz”的使用与我的目标是一致的。实际上,初始时间序列是我从文件中读取的,并且已经在 PST 中。因此我使用了“force_tz”。可以使用正确的时区创建新列,但现在它们要休息 7-8 小时。
【解决方案2】:

经过更多的实验,我不相信有办法先将“日期时间”列转换为 PST,然后创建一个具有正确时区并给出正确时区的日期列(基于 PST 中的日期时间)逐行计算结果。相反,如果我首先在 UTC 中创建两列,然后将两者都转换为 PST,它似乎可以工作。当然,如果您查看最终结果(即使日期列的时区似乎是正确的),为什么以前的方法似乎失败了,我仍然感到困惑。


library(lubridate)

# create a short datetime sequence
df <- data.frame(datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))

# check the timezone on datetime -- it is UTC
tz(df$datetime)

# now create a date column based on the datetime column in UTC
df$date <- as.Date(df$datetime)

# check date timezone -- also UTC
tz(df$date)

# now manually change both
df$datetime <- force_tz(df$datetime, tz="US/Pacific")
df$date <- force_tz(df$date, tz="US/Pacific")

# check -- both correctly register 'US/Pacific'
tz(df$datetime)
tz(df$date)

# now the two columns seem to match up
df[1:30,]

这是结果 - 请注意日期与日期时间相符。

              datetime       date
1  2020-01-01 00:00:00 2020-01-01
2  2020-01-01 01:00:00 2020-01-01
3  2020-01-01 02:00:00 2020-01-01
4  2020-01-01 03:00:00 2020-01-01
5  2020-01-01 04:00:00 2020-01-01
6  2020-01-01 05:00:00 2020-01-01
7  2020-01-01 06:00:00 2020-01-01
8  2020-01-01 07:00:00 2020-01-01
9  2020-01-01 08:00:00 2020-01-01
10 2020-01-01 09:00:00 2020-01-01
11 2020-01-01 10:00:00 2020-01-01
12 2020-01-01 11:00:00 2020-01-01
13 2020-01-01 12:00:00 2020-01-01
14 2020-01-01 13:00:00 2020-01-01
15 2020-01-01 14:00:00 2020-01-01
16 2020-01-01 15:00:00 2020-01-01
17 2020-01-01 16:00:00 2020-01-01
18 2020-01-01 17:00:00 2020-01-01
19 2020-01-01 18:00:00 2020-01-01
20 2020-01-01 19:00:00 2020-01-01
21 2020-01-01 20:00:00 2020-01-01
22 2020-01-01 21:00:00 2020-01-01
23 2020-01-01 22:00:00 2020-01-01
24 2020-01-01 23:00:00 2020-01-01
25 2020-01-02 00:00:00 2020-01-02
26 2020-01-02 01:00:00 2020-01-02
27 2020-01-02 02:00:00 2020-01-02
28 2020-01-02 03:00:00 2020-01-02
29 2020-01-02 04:00:00 2020-01-02
30 2020-01-02 05:00:00 2020-01-02

这是会话信息:

R version 3.6.2 (2019-12-12)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.6

【讨论】: