如何在给定年份获得去年的同一工作日?

How to Get the Same Weekday Last Year Given any Given Year?

我想得到去年任何一年的同一天。我怎样才能在 R 中最好地做到这一点。例如,给定星期日 2010/01/03,我想获得前一年同一周的星期日。

# "Sunday"
weekdays(as.Date("2010/01/03", format="%Y/%m/%d"))

# "Saturday"
weekdays(as.Date("2009/01/03", format="%Y/%m/%d"))

查看 lubridate 包中的 ?years。这将创建一个正确跨越闰年的期间对象。

> library(lubridate)
> # set the reference date
> d1 = as.Date("2017/01/03", format="%Y/%m/%d")
> 
> # verify across years and leap years
> d1 - years(1)
[1] "2016-01-03"
> d1 - years(2)
[1] "2015-01-03"
> d1 - years(3)
[1] "2014-01-03"
> d1 - years(4)
[1] "2013-01-03"
> d1 - years(5)
[1] "2012-01-03"
> 
> weekdays(d1 - years(1))
[1] "Sunday"
> weekdays(d1 - years(2))
[1] "Saturday"
> 
> # feb 29 on year period in yields NA
> ymd("2016/02/29") - years(1)
[1] NA
> 
> # feb 29 in a non-leap year fails to convert
> ymd("2015/02/29") - years(1)
[1] NA
Warning message:
All formats failed to parse. No formats found. 
> 
> # feb 29, leap year with 4 year period works.
> ymd("2016/02/29") - years(4)
[1] "2012-02-29"
> 

要查找一年前的同一工作日,只需从给定日期减去 52 周或 364 天:

d <- as.Date("2010-01-03")
weekdays(d)
#[1] "Sunday"
d - 52L * 7L
#[1] "2009-01-04"
weekdays(d - 52L * 7L)
#[1] "Sunday"

请注意,日历年有 365 天(或闰年为 366 天),比 52 周多一两天。因此,一年前同一工作日的 日历日期 向前移动了一两天。 (或者,它解释了为什么除夕总是在不同的工作日。)

使用 lubridate 下面的公式可以得到上一年同一周对应的工作日:

as.Date(dDate - 364 - ifelse(weekdays( dDate - 363) == weekdays( dDate ), 1, 0))

其中 dDate 是某个日期,即 dDate <- as.Date("2016-02-29")ifelse 表示闰年。

这是一个简单的算法。从感兴趣的日期减去 365 天。使用下面的 Tableau 代码将这一天调整为一周中最接近的匹配日(轻松将 table 翻译成其他语言)。这等同于下面 table 中的规则(1 = 星期一,7 = 星期日)。基本上你将 day - 365 调整为在同一周的正确日期,如果它移动 <= 3 天,否则你使用 previous/next 周的匹配工作日。它将选择导致天数差异最小的那个。

[day prior year raw] = [day] - 365
[matching day prior year] = 
if abs(datepart('weekday',[day]) - datepart('weekday',[day prior year raw]))<= 3
then [day prior year raw]+datepart('weekday',[day]) - datepart('weekday',[day prior year raw])
else [day prior year raw]+(if  datepart('weekday',[day]) > datepart('weekday',[day prior year raw])
        then -7+(datepart('weekday',[day]) - datepart('weekday',[day prior year raw]))
        else 7+(datepart('weekday',[day]) - datepart('weekday',[day prior year raw])) end
      )
end)