Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Suggestion] ISO leap year (long years) #1129

Open
ceisenhauer opened this issue Aug 3, 2023 · 2 comments
Open

[Feature Suggestion] ISO leap year (long years) #1129

ceisenhauer opened this issue Aug 3, 2023 · 2 comments

Comments

@ceisenhauer
Copy link

I'm not sure if this use case is too specific (or if there is already a solution elsewhere!) but it's something I found myself needing rather often so I figured I would share.

In my job I use lubridate a lot to work with dates in general and ISO weeks/years in particular. I frequently need to know if a particular year is an ISO "leap year", i.e. a year with 53 ISO weeks instead of 52. While ISO leap years and standard leap years sometimes happen to match up, this is often not the case and leap_year() thus can't be used on its own to check if a week has 53 weeks.

So, I wrote a function, iso_leap_year() to compliments leap_year():

iso_leap_year <- function(date) {
  if (is.numeric(date)) {
    year <- date
  } else {
    year <- lubridate::year(date)
  }

  january_first <- lubridate::wday(paste0(year, "-01-01"))

  (january_first == 5) | (january_first == 4 & lubridate::leap_year(year))
}

As we can see, sometimes ISO and standard leap years line up:

# standard leap year AND ISO long year
year <- 2020
lubridate::leap_year(year)
#> [1] TRUE
iso_leap_year(year)
#> [1] TRUE

But often, they do not:

# standard leap year but NOT ISO long year
year <- 2012
lubridate::leap_year(year)
#> [1] TRUE
iso_leap_year(year)
#> [1] FALSE

# ISO long year but NOT standard leap year
year <- 2015
lubridate::leap_year(year)
#> [1] FALSE
iso_leap_year(year)
#> [1] TRUE

NB. ISO years with 53 weeks are technically called long years not "leap years". I found iso_leap_year() a more intuitive name, but it could equally be iso_long_year().

Created on 2023-08-03 with reprex v2.0.2

@vspinu
Copy link
Member

vspinu commented Sep 22, 2023

I wold happily approve a PR for this. I think it's a nice addition to the package. But docs, tests and news entry should be added. Also please use ISOdate to construct the date instead of parsing the string.

Regarding the actual computation of the leap year, the peculiarity of the standard should be documented. The above rule would not predict correctly some of the years, like 2004. The rule suggested here seem to be doing the job:

A slight modification of the above rule, apparently first suggested by Sven Pran (Norway) and Lars Nordentoft (Denmark), successfully predicts the long ISO calendar years without any error:
    An ISO calendar year is long if and only if the corresponding Gregorian year begins on a Thursday when it is a common year or begins either on a Wednesday or a Thursday when it is a leap year.
A variant of the above rule was proposed in 1997 by Amos Shapir (Israel):
   An ISO calendar year is long if and only if the corresponding Gregorian year either begins or ends (or both) on a Thursday.

@ceisenhauer
Copy link
Author

Great! I will add the requested changes and additional docs this week and then submit a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants