R中PDT转PST时区切换异常及lubridate时区分配问题
处理PDT(太平洋夏令时)转PST(太平洋标准时间)的日期时间时,发现R的基础函数as.POSIXct并未在预期的2:00:00切换时区,而是在1:36:14完成切换——2021-11-07 01:36:14之后的所有时间都被标记为PST时区。代码示例如下:
x <- c( "2021-11-07 1:00:00", "2021-11-07 1:00:01", "2021-11-07 1:35:00", "2021-11-07 1:36:00", "2021-11-07 1:36:10", "2021-11-07 1:36:14", "2021-11-07 1:36:15", "2021-11-07 1:36:30", "2021-11-07 1:36:59", "2021-11-07 1:45:00", "2021-11-07 1:59:59", "2021-11-07 2:00:00", "2021-11-07 2:30:00" ) x_pst <- as.POSIXct(x, tz = "PST8PDT") x_pst # 输出片段: # [5] "2021-11-07 01:36:10 PDT" "2021-11-07 01:36:14 PDT" # [7] "2021-11-07 01:36:15 PST" "2021-11-07 01:36:30 PST"
此外,使用lubridate包处理相同数据时,所有时间(包括切换前的)都被标记为PST时区,代码示例如下:
x_pst <- lubridate::as_datetime(x, tz = "PST8PDT") x_pst # 输出: # [1] "2021-11-07 01:00:00 PST" "2021-11-07 01:00:01 PST" # [3] "2021-11-07 01:35:00 PST" "2021-11-07 01:36:00 PST" # [5] "2021-11-07 01:36:10 PST" "2021-11-07 01:36:14 PST" # [7] "2021-11-07 01:36:15 PST" "2021-11-07 01:36:30 PST" # [9] "2021-11-07 01:36:59 PST" "2021-11-07 01:45:00 PST" # [11] "2021-11-07 01:59:59 PST" "2021-11-07 02:00:00 PST" # [13] "2021-11-07 02:30:00 PST" x_pst <- lubridate::ymd_hms(x, tz = "PST8PDT") x_pst # 输出与上述一致
疑问:
- 为何时区切换发生在1:36:14这个特定时间点,而非预期的2:00:00?
- lubridate为何会将切换前的所有日期时间都分配为PST时区?
会话信息
> sessionInfo() R version 4.3.1 (2023-06-16) Platform: aarch64-apple-darwin20 (64-bit) Running under: macOS Sonoma 14.0 Matrix products: default BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0 locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 time zone: US/Pacific tzcode source: internal attached base packages: [1] stats graphics grDevices utils datasets [6] methods base loaded via a namespace (and not attached): [1] compiler_4.3.1 generics_0.1.3 tools_4.3.1 [4] lubridate_1.9.3 timechange_0.2.0
1. 时区在1:36:14切换的原因
核心问题是输入的时间字符串未指定时区,as.POSIXct会先将字符串解析为系统本地时区(你的环境是US/Pacific)的时间,再转换为PST8PDT时区。
2021年11月7日的夏令时切换实际发生在UTC时间10:00:00,对应PDT的1:00:00、PST的2:00:00。此时1:00-2:00的墙钟时间属于重叠区间:同一个本地时间会对应两个UTC时间(PDT和PST各一个)。R底层依赖系统tz数据库解析时,会将"2021-11-07 1:36:14"这个歧义时间映射到切换后的PST时区,导致显示的切换点偏移。
如果给输入字符串加上明确的时区标识(比如"2021-11-07 1:00:00 PDT"),就能得到预期的2:00:00切换结果。
2. lubridate全显示PST的原因
lubridate的as_datetime和ymd_hms处理无时区时间字符串时,解析策略与基础R不同:它直接将输入视为目标时区(PST8PDT)的墙钟时间,且在夏令时重叠区间,默认选择较晚的时区偏移(即PST,比PDT慢1小时)来避免歧义。
因此,所有处于1:00-2:00重叠区间的时间,都会被lubridate解析为切换后的PST时区,最终所有结果都显示为PST。
内容的提问来源于stack exchange,提问作者Colton Stephens

