Sunday date in mydates is 2018-05-06. I would like 1 day added so that 2018-05-06 becomes 2018-05-07 (Monday). That is, if a date falls on a Sunday add one day.
library(dplyr)
library(lubridate)
mydates <- as.Date(c('2018-05-01','2018-05-02','2018-05-05','2018-05-06'))
# find which are weekend dates
x = as.character(wday(mydates,TRUE))
if(x == 'Sun') { mydates + 1 }
# the Sunday date in mydates is 2018-05-06. I would like 1 day added so
that 2018-05-06 becomes 2018-05-07
Here's my error: Warning message:
In if (x == "Sun") { :
the condition has length > 1 and only the first element will be used
Try ifelse. Then convert to class Date.
as.Date(ifelse(x == 'Sun', mydates + 1, mydates), origin = '1970-01-01')
#[1] "2018-05-01" "2018-05-02" "2018-05-05" "2018-05-07"
X is a vector so you can use anif_else statement to increment the Sundays as follows:
library(dplyr)
library(lubridate)
new_dates <- if_else(x == 'Sun', mydates + days(1), mydates)
First, identify which of your dates are Sundays. Then, selectively add 1
library(lubridate)
mydates <- as.Date(c('2018-05-01','2018-05-02','2018-05-05','2018-05-06'))
i <- which(as.character(wday(mydates,TRUE))=="Sun")
mydates[i] <- mydates[i]+1
this outputs
"2018-05-01" "2018-05-02" "2018-05-05" "2018-05-07"
which, I believe, is the desired result.
Related
I am reading in an excel file in R and calculating the date 6 months prior to the date. If the date is falls on Weekend, need to change the date to the following weekday.
for example: if date is 2020-2-7, the six months prior is 2019-08-11. Which is Sunday.
How do I change the date to 2019-08-12?
I tried the following code:
date <- as.date.character("2020-2-7")
nxtd <- date-180
if(weekdays(nxtd)=="Saturday"){nxtd <- date-182} else if(weekdays(nxtd)=="Sunday"){nxtd <- date-181}
else{nxtd <- date-180}
this code gives an error/warning " the condition has length > 1 and only the first element will be used"
How do I resolve it?
library(lubridate)
d1 = as.Date("2020-2-9")
d2 = d1 - 180
if(weekdays(d2) %in% c("Saturday", "Sunday")){
floor_date(d2 - 3, "week") + 8
} else {
d2
}
If I have a given date, how do I find the first and last days of the next month?
For example,
today <- as.Date("2009-04-04")
I want to find
# first date in next month
"2009-05-01"
# last date in next month
"2009-05-31"
You can do this with base R:
today <- as.Date("2009-04-04")
first <- function(x) {
x <- as.POSIXlt(x)
x$mon[] <- x$mon + 1
x$mday[] <- 1
x$isdst[] <- -1L
as.Date(x)
}
first(today)
#[1] "2009-05-01"
first(first(today)) - 1
#[1] "2009-05-31"
lubridate has some useful tools for this purpose.
library(lubridate)
today <- ymd("2009-04-12")
# First day of next month
first <- ceiling_date(today, unit = "month")
# Last day of next month
last <- ceiling_date(first, unit= "month") -1
first
#"2009-05-01"
last
#"2009-05-31"
Here are some solutions. We use today from the question to test. In both cases the input may be a Date class vector.
1) Base R Define function fom to give the first of the month of its Date
argument. Using that we can get the date of the first and last of the next month as follows. We use the facts that 31 and 62 days after the first of the month is necessarily a date in the next month and month after the next month.
fom <- function(x) as.Date(cut(x, "month"))
fom(fom(today) + 31)
## [1] "2009-05-01"
fom(fom(today) + 62) - 1
## [1] "2009-05-31"
2) yearmon yearmon class objects internally represent a year and month as the year plus 0 for January, 1/12 for Febrary, 2/12 for March and so on. Using as.Date.yearmon the frac argument specifies the fraction of the way through the month to output. The default is frac = 0 and results in the first of the month being output and frac = 1 means the end of the month.
library(zoo)
as.Date(as.yearmon(today) + 1/12)
## [1] "2009-05-01"
as.Date(as.yearmon(today) + 1/12, frac = 1)
## [1] "2009-05-31"
I have a data frame in R with the week of the year that I would like to convert to a date. I know I have to pick a year and a day of the week so I am fixing those values at 2014 and 1. Converting this to a date seems simple:
as.Date(paste(2014,df$Week,1,sep=""),"%Y%U%u")
But this code only works if week is greater than 9. Week 1 - 9 returns NA. If I change the week to 01,02,03... it still returns NA.
Anyone see what I am missing?
as.Date is calling the 1 to 9 as NA as it is expects two digits for the week number and can't properly parse it.
To fix it, add in some - to split things up:
as.Date(paste(2014, df$Week, 1, sep="-"), "%Y-%U-%u")
An alternative solution is to use date arithmetic from the lubridate package:
lubridate::ymd( "2014-01-01" ) + lubridate::weeks( df$Week - 1 )
The -1 is necessary because 2014-01-01 is already week 1. In other words, we want:
df$Week == 1 to map to 2014-01-01 (which is ymd("2014-01-01") + weeks(1-1))
df$Week == 2 to map to 2014-01-08 (which is ymd("2014-01-01") + weeks(2-1))
and so on.
Another option with lubridate
lubridate::parse_date_time(paste(2014, df$Week, 1, sep="/"),'Y/W/w')
W - week number, w - weekday number, 0-6 (Sun-Sat)
Another alternative is to make sure that week numbers have two digits, which can be done using stringr::str_pad(), which will add a pad="0" to make sure there are width=2 digits:
year <- 2015
week <- 1
as.Date(paste(year, week, "1", sep=""), "%Y%U%u")
#> [1] NA
as.Date(paste(year, stringr::str_pad(week,width=2, pad="0"), "1", sep=""), "%Y%U%u")
#> [1] "2015-01-05"
as.Date(paste(year, week, "1", sep="-"), "%Y-%U-%u")
#> [1] "2015-01-05"
Created on 2021-04-19 by the reprex package (v1.0.0)
It will be like using 2nd year = (week-52), 3rd year = (week -104)...so on
for(i in 1:456548)
{
if (train[i,2] > 0 & train[i,2] <53)
{
train["weekdate"] <- as.Date(paste(2016, train$week, 1, sep="-"), "%Y-%U-%u")
}
if (train[i,2] > 52 & train[i,2] <105)
{
train["weekdate"] <- as.Date(paste(2017, (train$week-52), 1, sep="-"), "%Y-%U-%u")
}
if (train[i,2] > 104 & train[i,2] <150)
{
train["weekdate"] <- as.Date(paste(2018, (train$week-104), 1, sep="-"), "%Y-%U-%u")
}
}
How can a date/time object in R be transformed on the fraction of a julian day?
For example, how can I turn this date:
date <- as.POSIXct('2006-12-12 12:00:00',tz='GMT')
into a number like this
> fjday
[1] 365.5
where julian day is elapsed day counted from the january 1st. The fraction 0.5 means that it's 12pm, and therefore half of the day.
This is just an example, but my real data covers all the 365 days of year 2006.
Since all your dates are from the same year (2006) this should be pretty easy:
julian(date, origin = as.POSIXct('2006-01-01', tz = 'GMT'))
If you or another reader happen to expand your dataset to other years, then you can set the origin for the beginning of each year as follows:
sapply(date, function(x) julian(x, origin = as.POSIXct(paste0(format(x, "%Y"),'-01-01'), tz = 'GMT')))
Have a look at the difftime function:
> unclass(difftime('2006-12-12 12:00:00', '2006-01-01 00:00:00', tz="GMT", units = "days"))
[1] 345.5
attr(,"units")
[1] "days"
A function to convert POSIX to julian day, an extension of the answer above, source it before using.
julian_conv <- function(x) {
if (is.na(x)) { # Because julian() cannot accept NA values
return(NA)
}
else {
j <-julian(x, origin = as.POSIXlt(paste0(format(x, "%Y"),'-01-01')))
temp <- unclass(j) # To unclass the object julian day to extract julian day
return(temp[1] + 1) # Because Julian day 1 is 1 e.g., 2016-01-01
}
}
Example:
date <- as.POSIXct('2006-12-12 12:00:00')
julian_conv(date)
#[1] 345.5
I would like to find all of the Tuesdays between two dates. But if the Tuesday falls on a user-defined list of holidays, then I would like Wednesday instead.
This code works in my tests, but it is pretty janky and I am afraid it will fail silently.
low.date <- "1996-01-01"
high.date <- "1997-01-01"
holidays = c("01-01", "07-04", "12-25")
tues <- seq(as.Date(low.date), as.Date(high.date), by = 1)
tues <- subset(tues, format(tues, "%a") == "Tue")
tues <- ifelse(format(tues, "%m-%d") %in% holidays, tues + 1, tues)
tues <- as.Date(tues, origin = "1970-01-01")
Thanks! I see answers pointing to the timeDate package, but I only see methods for finding business days or holidays. Is there a cleaner/safer logic than what I'm using?
It's difficult to modify the logic of your solution. But here is a different form using wday function from lubridate package.
hol_tue <- wday(tues) == 3L & format(tues, "%m-%d") %in% holidays
wday(tues)[hol_tue] <- 4
Slightly inconveniently in lubridate package day count starts from Sunday with Sunday being day 1 as opposed to POSIXlt where it's 0.
POSIXlt in the base package gives you access to wday as a number, which is a little safer since names of days change from system to system.
low.date <- "1996-01-01"
high.date <- "1997-01-01"
holidays <- c("01-01", "07-04", "12-25")
all.days <- seq(as.Date(low.date), as.Date(high.date), by = "day")
# Tuesday is Day 2 of the week
all.tues <- all.days[as.POSIXlt(all.days)$wday == 2]
tues.holidays <- format(all.tues, "%m-%d") %in% holidays
all.tues[tues.holidays] <- all.tues[tues.holidays] + 1