5
dates <- NULL

date <- as.Date("01/01/2014","%d/%m/%Y")

dates <- data.frame(date=as.Date(character())
                    ,cal_day_in_year_num = numeric()
                    ,cal_week_id = numeric()
                    ,cal_week_start_date = as.Date(character())
                    ,cal_week_end_date = as.Date(character())
)

for (i in 1:365) {

  dates[i,1] <- date + days(i-1) ## date

  dates[i,2] <- yday(dates[i,1]) ## cal_day_in_year_num

  dates[i,3] <- paste(year(dates[i,1]),sprintf("%02d",week(dates[i,1])),sep="") ## cal_week_id

  dates[i,4] <- floor_date(dates[i,1], "week") ## cal_week_start_date

  dates[i,5] <- ceiling_date(dates[i,1], "week") ## cal_week_end_date

}

View(dates)

For given dates I'm trying to use the lubridate function to calculate the corresponding start and end dates of the week

The issue I'm having is that lubridate is taking the first day of the week to be Sunday, where as I need it to be Monday - does anyone have a way round this?

Sam Gilbert
  • 1,642
  • 3
  • 21
  • 38
  • Although this might not be the official way, you could simply add +1? – Wave Oct 02 '14 at 11:59
  • 1
    unfortunately I don't think that adding 1 to cal_week_start_date will work as for example Sunday will still be classed wrongly – Sam Gilbert Oct 02 '14 at 12:13

3 Answers3

9

You can make your own functions to do this in base. For example,

start.of.week <- function(date)
  date - (setNames(c(6,0:5),0:6) [strftime(date,'%w')])

end.of.week <- function(date)
  date + (setNames(c(0,6:1),0:6) [strftime(date,'%w')])

start.of.week(as.Date(c('2014-01-05','2014-10-02','2014-09-22','2014-09-27')))
# "2013-12-30" "2014-09-29" "2014-09-22" "2014-09-22"
end.of.week(as.Date(c('2014-01-05','2014-10-02','2014-09-22','2014-09-27')))
# "2014-01-05" "2014-10-05" "2014-09-28" "2014-09-28"
nograpes
  • 18,623
  • 1
  • 44
  • 67
  • Note that I would have used `strftime(date,'%u%')` to get a day of week integer that uses Monday, but the Windows version of `strftime` doesn't support `'%u%`. This works on Windows too. – nograpes Oct 02 '14 at 14:27
  • Thanks function is great + will use strftime going forwards – Sam Gilbert Oct 02 '14 at 15:03
1

slightly late, but just to say that now there is an option in lubridate, which defaults to sunday, but can be set to something else. See the documentation, e.g.

# set Monday to be the start of the week globally
options("lubridate.week.start" = 1)

# use lubridate functions
wday(...)
gira
  • 175
  • 6
-1

As Wave commented, you can just use +1 to change the date. You can also do the same as you have done without the need of the slow for loop.

date <- as.Date("01/01/2014","%d/%m/%Y")

yday(date) <-yday(date) + 0:364
dates <- data.frame(date = date,
                    cal_day_in_year_num = yday(date),
                    cal_week_id = paste(year(date),sprintf("%02d",week(date)),sep=""),
                    cal_week_start_date = NA,
                    cal_week_end_date = NA
                    )

# find the minimum date in the time series
min_date <- min(dates$date)
# find the previous Monday of the minimum date
for(i in 1:7){
  if(wday(min_date-i, label=TRUE)=="Mon"){
    start_date <- min_date-i
  }
}

# get the number of days between the minimum date and all days
diff_days <- as.numeric(difftime(dates$date,start_date, units="days"))
# Remove the excess days from each date
dates$cal_week_start_date <- dates$date-diff_days%%7
# Fix up the end of the week based on the start of the week
dates$cal_week_end_date <- dates$cal_week_start_date+7
Jase_
  • 1,186
  • 9
  • 12
  • hi, unfortunately that doesn't work please check the 5th of January in your example. Since Sunday is considered the start and end date calculations within a week get split – Sam Gilbert Oct 02 '14 at 12:24
  • You can work around the sunday problem with an ifelse statement: dates$cal_week_start_dat=ifelse(wday(dates$date,label=T)=="Sun",floor_date(dates$date, "week")-6,floor_date(dates$date, "week")+1). – Wave Oct 02 '14 at 12:56