Sarah
Sarah

Reputation: 463

Counting days of the year with leap years

I am currently trying to code this in R. I would like to take a date that I have in %Y-%m-%d (ex: 2017-12-31) format and convert it to the day of the year. However, I would like it to always count 02/28 as day #59 and 03/01 as day #61. When it is not a leap year, it will just skip #60. This way, 01/01 is always #1 and 12/31 is always #366.

I have already tried using strftime() and yday(), but both of those do not skip day #60 when it is a leap year. It will just make 12/31 be day #365 or #366 depending on if it is a leap year or not.

If anyone has any insight on how I could code this in R, that would be great! Thank you so much.

file <- read.table("PATHTOMYFILE", fill = TRUE, header = TRUE)
file <- file[-c(1), ]
file$datetime <- as.Date(as.character(file$datetime))
file <- file[which(file$datetime <= as.Date("2017-09-30")), ]
file$x <- file[, 4]
file$x <- as.numeric(as.character(file$x))

# Year-day function
yearday <- function(d){
# Count previous months
yd <- ifelse(lubridate::month(d) > 1, sum(lubridate::days_in_month(1: 
(lubridate::month(d)-1))), 0)

# Add days so far in month & extra day if after February
yd <- yd + lubridate::day(d) + ifelse(lubridate::month(d)>2, 1, 0)
yd
}

file$Day <- yearday(as.Date((file$datetime), format = "%Y-%m-%d"))

Upvotes: 7

Views: 2005

Answers (3)

Andrew
Andrew

Reputation: 5138

You could use the lubridate's leap_year function. E.g.,

library(lubridate)
dates <- c(as.Date("2017-12-31"), as.Date("2016-12-31"))
y <- as.Date("2016-12-31")
z <- as.Date("2017-12-31")
leap_every_year <- function(x) {
   ifelse(yday(x) > 59 & leap_year(x) == FALSE, yday(x) + 1, yday(x))
}
leap_every_year(y)
[1] 366
leap_every_year(z)
[1] 366
leap_every_year(dates)
[1] 366 366

EDIT: saw this was very similar to @MDEWITT's solution but it uses lubridate instead. Similar ideas though. Good luck!

Upvotes: 2

Dan
Dan

Reputation: 12084

Here's a function that does the job. It sums all the months prior to the current month, adds days for the current month, and then adds the leap day if the month is after February.

# Year-day function
yearday <- function(d){
  # Count previous months
  yd <- ifelse(lubridate::month(d) > 1, sum(lubridate::days_in_month(1:(lubridate::month(d)-1))), 0)
  # Add days so far in month & extra day if after February
  yd <- yd + lubridate::day(d) + ifelse(lubridate::month(d)>2, 1, 0)
  yd
}

# Test function
yearday(as.Date("2017-12-31", format = "%Y-%m-%d"))
#> [1] 366
yearday(as.Date("2017-03-01", format = "%Y-%m-%d"))
#> [1] 61
yearday(as.Date("2017-01-01", format = "%Y-%m-%d"))
#> [1] 1

Created on 2019-03-01 by the reprex package (v0.2.1)

Upvotes: 0

MDEWITT
MDEWITT

Reputation: 2368

One option would be to use this function:

How to account for leap years?

leap_year <- function(year) {
  return(ifelse((year %%4 == 0 & year %%100 != 0) | year %%400 == 0, TRUE, FALSE))
}

Then write some code that manipulates the day number you have based on your rules (e.g. in a leap year

 if(leap_year(mydate)== TRUE & day_num>60) {
 day_num + 1} else{
  day_num}

Upvotes: 2

Related Questions