Counting days of the year with leap years
Asked Answered
T

3

7

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"))
Trotter answered 1/3, 2019 at 14:13 Comment(0)
V
2

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!

Vaenfila answered 1/3, 2019 at 15:53 Comment(1)
Happy it helped!Vaenfila
B
2

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}
Bigener answered 1/3, 2019 at 14:29 Comment(0)
V
2

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!

Vaenfila answered 1/3, 2019 at 15:53 Comment(1)
Happy it helped!Vaenfila
C
0

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)

Campaign answered 1/3, 2019 at 14:33 Comment(4)
I'm getting this warning message when I run your code. "Warning message: In 1:(lubridate::month(d) - 1) : numerical expression has 29220 elements: only the first used" My starting date is 1937-10-01 and the counting is correct until it gets to 1937-11-01 and it starts back up at day #275 again.Trotter
@SamanthaSullivan Can you edit your question to include the data and exact code you're running so that I can reproduce the issue?Campaign
I added the code. I'm not sure how to add the table. It just starts out as a table with 5 headers. The 3rd header is called "datetime" where the dates are in $Y-%m-%d format and then I add a 6th column called x which is just a rename of my 4th column which is my data value that I am performing analysis on. How do I add my data?Trotter
@SamanthaSullivan It's easiest to add your data by using dput or dump and copy-and-pasting the output. For example, dump("file", ""), if your data frame is called file.Campaign

© 2022 - 2024 — McMap. All rights reserved.