为何as.POSIXct与as.POSIXlt处理Sys.Date()返回值差8小时?
拆解R中POSIXct/POSIXlt与时区的那些坑
这个问题其实是R里时区处理的经典陷阱,我来给你一步步理清楚:
为什么as.POSIXct和as.POSIXlt处理Sys.Date()会返回不同值?
核心原因在于Date类型转POSIX类型时的时区解析逻辑差异:
as.POSIXlt(Sys.Date()-1):会把前一天的日期,直接解析成你系统本地时区的午夜。比如你系统时区是纽约,那它就对应纽约时间2018-01-12 00:00:00,底层存储的是这个时间对应的UTC时间戳。as.POSIXct(Sys.Date()-1):默认会把前一天的日期,先当成UTC时区的午夜,再转换为你本地时区的时间显示。比如UTC的2018-01-12 00:00:00,转换到纽约时区就是2018-01-11 19:00:00 EST,底层存储的是UTC午夜的时间戳。
简单说,这两个函数生成的对象,底层的时间戳完全不一样,后续操作自然会出现差异。
为什么用lubridate的force_tz后仍有8小时差异?
这里你踩了force_tz()的一个常见误区:它不是用来转换时区的,而是用来纠正时区标记的!
force_tz()的作用是:保留底层的时间戳不变,只是把这个时间戳的时区标签换成你指定的时区。举个例子:
- 你用
as.POSIXct(Sys.Date()-1)得到的是UTC午夜的时间戳,假设这个时间戳在你本地时区(比如UTC+8)显示为2018-01-12 08:00:00。 - 用
force_tz(..., tz='America/New_York')后,这个时间戳被直接标记为纽约时区的时间,也就是2018-01-12 08:00:00 EST——但这个时间对应的UTC其实是2018-01-12 13:00:00,和你想要的纽约午夜完全不是一回事。
如果要把时间从一个时区转换到另一个时区,你应该用lubridate::with_tz(),它会调整时间戳来匹配目标时区的实际时间。
正确获取纽约时区前一天最后一分钟的写法
推荐用lubridate的直观语法,直接指定时区生成日期,避免时区混淆:
library(lubridate) # 方式1:生成前一天的纽约日期,加一天减一秒 ymd(Sys.Date()-1, tz = "America/New_York") + days(1) - seconds(1) # 方式2:分步构建时间 nyc_prev_day <- ymd(Sys.Date()-1, tz = "America/New_York") nyc_last_minute <- nyc_prev_day + hours(23) + minutes(59) + seconds(59)
这样就能准确得到2018-01-12 23:59:59 EST的结果啦。
内容的提问来源于stack exchange,提问作者iskandarblue
相关产品推荐
相关产品推荐

