Reputation: 463
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
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
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
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