R语言suncalc包日期/时区计算错误问题求助
解决suncalc包getSunlightTimes函数日期偏移问题
问题描述
在为动物追踪数据添加黎明/黄昏/夜晚/白昼变量时,使用suncalc包的getSunlightTimes函数出现日期偏差。所有时区设置为UTC,系统时区为Pacific/Auckland。例如输入日期为2021-02-05时,得到的日出时间为2021-02-04 17:42:24,日落时间为2021-02-05 07:28:19,地点位于新西兰附近(lon = 174.9776,lat = -36.20939),时段合理但日期偏移一天。
示例数据框
datetime <- c("2021-02-05 11:00:00", "2021-02-05 13:00:00", "2021-02-05 15:00:00") lat <- c("-36.20939", "-36.20952", "-36.20979") lon <- c("174.9776", "174.9772", "174.9764") date <- c("2021-02-05", "2021-02-05", "2021-02-05") df <- cbind.data.frame(datetime, lat, lon, date)
当前代码
#Using the SunCalc package get times for sunrise, sunset, night, and nightENd df$datetime <- strptime(df$datetime, format = "%d/%m/%y %H:%M", tz = "UTC") df$datetime <- as.POSIXct(df$datetime) df$date <- as.Date(df$datetime, tz = "UTC") sun_all <- getSunlightTimes(data = df, tz = "UTC", keep = c("sunrise", "sunset", "night", "nightEnd")) #Append to main data frame df$sunrise <- sun_all$sunrise df$sunset<- sun_all$sunset df$night <- sun_all$night df$nightEnd<- sun_all$nightEnd #Create new column labelling each data point as the Time of Day (ToD) df$period <- rep(" ", length.out = nrow(df)) # Assign labels based on time ranges df$period[df$datetime > df$sunrise & df$datetime < df$sunset] <- "day" df$period[df$datetime > df$sunset & df$datetime < df$night] <- "dusk" df$period[df$datetime > df$nightEnd & df$datetime < df$sunrise] <- "dawn" df$period[df$period == " "] <- "night"
问题原因
- 日期解析格式错误:当前代码用
%d/%m/%y解析datetime列,但输入的日期格式是YYYY-MM-DD HH:MM:SS,格式不匹配导致解析错误,后续日期计算全部出错。 - 时区不匹配导致跨天偏移:新西兰(Pacific/Auckland时区)夏季比UTC早13小时,当地日期2021-02-05对应的UTC时间范围是2021-02-04 11:00到2021-02-05 11:00。用UTC时区计算当地日照时间,结果的UTC日期会与当地日期跨天,造成日期偏移的视觉错觉。
解决方案
修正步骤
- 正确解析datetime列:使用匹配的格式字符串
%Y-%m-%d %H:%M:%S解析日期时间,设置对应时区。 - 使用当地时区计算日照时间:将
getSunlightTimes的tz参数设置为Pacific/Auckland,确保计算出的日照时间与当地日期对齐。 - 优化时段判断逻辑:用更清晰的条件判断语句替代重复赋值。
修正后的代码
library(suncalc) library(dplyr) # 示例数据框 datetime <- c("2021-02-05 11:00:00", "2021-02-05 13:00:00", "2021-02-05 15:00:00") lat <- c("-36.20939", "-36.20952", "-36.20979") lon <- c("174.9776", "174.9772", "174.9764") date <- c("2021-02-05", "2021-02-05", "2021-02-05") df <- cbind.data.frame(datetime, lat, lon, date) # 1. 正确解析datetime,设置为Pacific/Auckland时区 df$datetime <- as.POSIXct(df$datetime, format = "%Y-%m-%d %H:%M:%S", tz = "Pacific/Auckland") df$date <- as.Date(df$datetime, tz = "Pacific/Auckland") # 2. 用当地时区计算日照时间 sun_all <- getSunlightTimes( data = df, tz = "Pacific/Auckland", keep = c("sunrise", "sunset", "night", "nightEnd") ) # 合并数据 df <- cbind(df, sun_all) # 3. 优化时段判断逻辑 df$period <- case_when( df$datetime > df$sunrise & df$datetime < df$sunset ~ "day", df$datetime > df$sunset & df$datetime < df$night ~ "dusk", df$datetime > df$nightEnd & df$datetime < df$sunrise ~ "dawn", TRUE ~ "night" ) # 查看结果 print(df)
关键说明
- 使用
Pacific/Auckland时区计算日照时间,得到的日出日落时间会与当地日期对齐,比如2021-02-05的日出时间显示为当地时间2021-02-05 06:42左右,避免跨天偏移。 dplyr::case_when让时段判断逻辑更简洁清晰,减少代码冗余。
内容的提问来源于stack exchange,提问作者squid
相关产品推荐
相关产品推荐

