lubridate包with_tz函数在CEST与UTC时区下的异常行为问询
lubridate::with_tz() 时区异常问题解析
代码重现
library(lubridate) #> #> Attaching package: 'lubridate' #> The following objects are masked from 'package:base': #> #> date, intersect, setdiff, union # 示例时间 time = as.POSIXct("2016-08-01 10:00:00 UTC", tz = 'UTC') # 检查原始时间 tz(time) #> [1] "UTC" print(time) #> [1] "2016-08-01 10:00:00 UTC" # 异常行为 with_tz(time, tz = 'CEST') #> [1] "2016-08-01 10:00:00 CEST" with_tz(time, tz = 'UTC') #> [1] "2016-08-01 10:00:00 UTC" with_tz(time, tz = 'America/New_York') #> [1] "2016-08-01 06:00:00 EDT"
为什么指定CEST时时间不变?
这不是with_tz()的bug,核心原因是时区缩写不被R识别:
CEST是「中欧夏令时」的缩写,属于非标准时区标识符。R和lubridate依赖IANA时区数据库,只认可类似Europe/Berlin、America/New_York这类规范的时区名称。- 当传入未被识别的时区字符串时,
with_tz()会自动 fallback 到UTC时区。此时输出虽然显示CEST,但实际时区属性仍是UTC,所以时间和原UTC时间完全一致。
用标准时区标识符测试就能得到预期结果:
with_tz(time, tz = 'Europe/Berlin') #> [1] "2016-08-01 12:00:00 CEST"
同一时刻在中欧夏令时(比UTC早2小时)显示为12:00,符合with_tz()「同一时间点,不同时区显示」的设计逻辑。
关于force_tz()的行为
force_tz()和with_tz()的逻辑完全不同:
with_tz():保留时间点不变,转换为目标时区的显示格式force_tz():保留时间数值不变,强制将其绑定到目标时区
你得到的force_tz(time, tz='CEST')结果"2016-08-01 08:00:00 CEST"是正确的:原时间的数值是UTC的10:00,强制赋予CEST时区属性后,这个数值对应的实际UTC时间是8:00(因为CEST比UTC早2小时),所以显示为CEST的8:00,完全符合文档描述。
总结
- 始终使用IANA标准时区标识符(而非时区缩写),避免因识别失败导致的异常行为。
with_tz()的行为是设计预期,并非bug;force_tz()的结果也符合其「强制绑定时区属性」的逻辑,二者不要混淆。
内容的提问来源于stack exchange,提问作者chm
相关产品推荐
相关产品推荐

