24

I have a vector of date objects (yyyy-mm-dd) and I want to determine if any of them are on weekend or not. Is there a function that can determine this straightaway?

I can use wday() in the lubridate package and then determine if returned value is 01 or 07, but anything else more straightforward?

x <- seq(Sys.Date()-10, Sys.Date(), by = 1)
x[lubridate::wday(x) %in% c(1, 7)]
hrbrmstr
  • 71,487
  • 11
  • 119
  • 180
DonDyck
  • 1,353
  • 4
  • 18
  • 35

7 Answers7

29

You can use the base R function weekdays().

x <- seq(Sys.Date() - 10, Sys.Date(), by = 1)
weekdays(x, abbr = TRUE)
# [1] "Wed" "Thu" "Fri" "Sat" "Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat"
x[grepl("S(at|un)", weekdays(x))]
# [1] "2014-10-11" "2014-10-12" "2014-10-18"

As far as lubridate goes, wday() has a label argument. When set to TRUE, the (abbreviated) day names are returned instead of numbers. Use the abbr argument to change to full names.

library(lubridate)
wday(x, label = TRUE)
# [1] Wed   Thurs Fri   Sat   Sun   Mon   Tues  Wed   Thurs Fri   Sat  
# Levels: Sun < Mon < Tues < Wed < Thurs < Fri < Sat
Rich Scriven
  • 90,041
  • 10
  • 148
  • 213
15

I put @AnandaMahto's suggestion here rather than a comment:

library(chron)
x <- seq(Sys.Date()-10, Sys.Date(), by = 1)
x[is.weekend(x)]

## [1] "2014-10-11" "2014-10-12" "2014-10-18"
Tyler Rinker
  • 99,090
  • 56
  • 292
  • 477
  • @ConstanzaGarcia Can you make this reproducible? You add a desparaging comment that can't be tested that may push others away from a correct answer. Conversely, you may be correct, if so I'd delete the answer or update it accordingly. I suspect you have something off in your data types that's causing the issue but would like to get to the problem (this answer or your data) either way. May I suggest you delete this comment and open a new question with your data that demonstrates the problem (a reproducible example) and then link back to this question/answer. – Tyler Rinker May 29 '19 at 12:49
10

Another approach could be to use format and %u, which gives a number for the day of the week, starting with "1" representing "Monday".

With that, you can do:

x <- seq(as.Date("2014-10-18")-10, Sys.Date(), by = 1)
format(x, "%u") %in% c(6, 7)
#  [1] FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE
x[format(x, "%u") %in% c(6, 7)]
# [1] "2014-10-11" "2014-10-12" "2014-10-18"
A5C1D2H2I1M1N2O1R2T1
  • 177,446
  • 27
  • 370
  • 450
  • 3
    Luckily, there is also `%w` that maps Sunday to `0`. So we can all live in peace. `data.frame(a = format(x, "%a"), u = format(x, "%u"), w = format(x, "%w"))`. – flodel Oct 18 '14 at 16:48
5

The wday in both lubridate and data.table (yes, data.table has pretty much everything but the kitchen sink :-) both do a variation on:

as.POSIXlt(x, tz = tz(x))$wday + 1 # lubridate
as.POSIXlt(x)$wday + 1L            # data.table

So you could, in theory, just do:

as.POSIXlt("2014-10-18")$wday + 1
## [1] 7

and then test for the weekend days as other answer(s) do.

hrbrmstr
  • 71,487
  • 11
  • 119
  • 180
  • **Note:** `c(1,2,3,4,5)` is weekday. `c(6,0)` is the weekend when you do `as.POSIXlt("2014-10-18")$wday` – agent18 Feb 28 '19 at 13:02
1

You could use isWeekend from package timeDate. Hard to do more straightforward :). wday specify which days should be considered as weekdays. By default from Mondays to Fridays.

> today <- isWeekend(Sys.Date(), wday = 1:5)
if (as.logical(today)){
  print("YES")
} else print("NO")

From the documentation :

## Dates in April, currentYear:
   currentYear = getRmetricsOptions("currentYear")
   tS = timeSequence(
      from = paste(currentYear, "-03-01", sep = ""),
      to = paste(currentYear, "-04-30", sep = ""))
   tS

## Subset of Weekends:
   isWeekend(tS)
   tS[isWeekend(tS)]

It works also with isWeekday.

Florent
  • 1,086
  • 11
  • 26
1

After looking a lot about this topic, I found this solution particularly simple using the package RQuantLib

install.packages("RQuantLib")
library(RQuantLib)
isBusinessDay(calendar="WeekendsOnly", dates=yourdatesofinterest)

You can modify this code with different calendars to add to the weekends different sets of holidays in different countries (below just an example, but they have many more).

isBusinessDay(calendar="UnitedStates", dates=yourdatesofinterest)
isBusinessDay(calendar="UnitedStates/Settlement", dates=yourdatesofinterest)
isBusinessDay(calendar="UnitedStates/NYSE", dates=yourdatesofinterest)
isBusinessDay(calendar="Sweden", dates=yourdatesofinterest)
isBusinessDay(calendar="Mexico", dates=yourdatesofinterest)

I hope it helps somebody

Ivan
  • 529
  • 8
  • 12
1

Using lubridate to avoid other packages, you can use:

is_weekday = function(timestamp){
  lubridate::wday(timestamp, week_start = 1) < 6
}
rsmith54
  • 677
  • 7
  • 13