如何获取日期对应的天文季节起始日?lubridate::floor_date使用问题
问题解答
为什么floor_date(x, "season")返回的是6月1日?
lubridate::floor_date()的season参数是基于北半球气象季节划分的,每个季节对应固定的月份区间:
- 冬季:12-2月,起始日为当年12月1日
- 春季:3-5月,起始日为当年3月1日
- 夏季:6-8月,起始日为当年6月1日
- 秋季:9-11月,起始日为当年9月1日
它完全不考虑天文节气(夏至、秋分等)的具体日期,所以你得到2008-06-01是该函数的正常行为,但不符合你要的天文季节需求。
获取天文季节起始日的方法
天文季节的起始日由二至二分(春分、夏至、秋分、冬至)的具体日期决定,这些日期每年会有1-2天的浮动,因此需要根据年份计算。
方法1:用suncalc包计算精确节气日期
这个方法能得到准确的天文节气日期:
# 先安装并加载包 install.packages("suncalc") library(suncalc) library(lubridate) # 定义函数 get_astronomical_season_start <- function(date) { target_year <- year(date) # 计算当年的二至二分日期(坐标不影响节气计算,选任意北半球位置即可) solstice_data <- getSunlightTimes( date = as.Date(paste(target_year, c(3,6,9,12), 21, sep = "-")), lat = 40, lon = -100, keep = "solarNoon" ) # 提取准确的节气日期 spring_start <- solstice_data$date[which.min(solstice_data$solarNoon[1:2])] # 春分 summer_start <- solstice_data$date[which.max(solstice_data$solarNoon[1:2])] # 夏至 autumn_start <- solstice_data$date[which.min(solstice_data$solarNoon[3:4])] # 秋分 winter_start <- solstice_data$date[which.max(solstice_data$solarNoon[3:4])] # 冬至 # 判断输入日期所属季节,返回起始日 target_date <- as.Date(date) if (target_date >= spring_start && target_date < summer_start) { return(spring_start) } else if (target_date >= summer_start && target_date < autumn_start) { return(summer_start) } else if (target_date >= autumn_start && target_date < winter_start) { return(autumn_start) } else { return(winter_start) } } # 测试你的示例 x <- ymd_hms("2008-08-03 12:01:59.23") get_astronomical_season_start(x) # 输出:"2008-06-21"
方法2:使用近似固定日期(无需额外包)
如果你不需要绝对精确的节气日期,可以使用每年的近似值(比如夏至固定为6月21日):
library(lubridate) get_approx_season_start <- function(date) { target_year <- year(date) target_date <- as.Date(date) # 定义近似节气日期 spring_start <- as.Date(paste(target_year, "03", "20", sep = "-")) summer_start <- as.Date(paste(target_year, "06", "21", sep = "-")) autumn_start <- as.Date(paste(target_year, "09", "22", sep = "-")) winter_start <- as.Date(paste(target_year, "12", "21", sep = "-")) if (target_date >= spring_start && target_date < summer_start) { spring_start } else if (target_date >= summer_start && target_date < autumn_start) { summer_start } else if (target_date >= autumn_start && target_date < winter_start) { autumn_start } else { winter_start } } # 测试 get_approx_season_start(x) # 输出:"2008-06-21"
内容的提问来源于stack exchange,提问作者adl
相关产品推荐
相关产品推荐

