-1

I will write the code because it is difficult to explain. I want to do the following.

x <- as.Date("2020-01-01")
y <- as.Date("2020-03-31") 

library(lubridate)

date <- seq(x, y, by = "day")

start <- floor_date(date, 'weeks')
end <- ceiling_date(date, 'weeks') - 1

df <- data.frame(
  start_date = start,
  end_date = end
)

df <- unique(df)

df
   start_date   end_date
1  2019-12-29 2020-01-04
5  2020-01-05 2020-01-11
12 2020-01-12 2020-01-18
19 2020-01-19 2020-01-25
26 2020-01-26 2020-02-01
33 2020-02-02 2020-02-08
40 2020-02-09 2020-02-15
47 2020-02-16 2020-02-22
54 2020-02-23 2020-02-29
61 2020-03-01 2020-03-07
68 2020-03-08 2020-03-14
75 2020-03-15 2020-03-21
82 2020-03-22 2020-03-28
89 2020-03-29 2020-04-04

I want to output all the belonging weeks by inputting the period. Can you make the above code smarter?

Tim Ikata
  • 201
  • 1
  • 7

2 Answers2

1

you could tray an approach like this.. it groups by ISO weeknumbers, and gives the min/max date from the sample data for each group.
You can alter the by-argument, to get the groups you need. for example lubridate::epiweek() if you need weeks to start on a Sunday, see the bottom part.

  1. First, you'll have to calculate the startdate of the first week, and the end date of the last week (I assume weeks start on Monday, for Sunday see bottom of answer).
  2. Create a sequence of days, from startdate to enddate
  3. group by weeknumber, select min and max date for each group

week start on Monday

library( data.table )
library( lubridate )

x <- as.Date("2020-01-01")
y <- as.Date("2020-03-31") 

#assuming weeks start on a Monday
# calculate first date of starting week
start = x - lubridate::wday( x, week_start = 1) + 1
# calculate last date of ending week
end   = y + 7 - lubridate::wday( y, week_start = 1 ) 

mydata <- data.table( 
  date = seq( start, end, by = "1 days" )
)
#group dates by ISO weeknumber, return min and max data
mydata[, 
       .( start = min(date), end = max(date) ), 
       by = .( weeknumber = lubridate::isoweek( date ) ) ]

#     weeknumber      start        end
#  1:          1 2019-12-30 2020-01-05
#  2:          2 2020-01-06 2020-01-12
#  3:          3 2020-01-13 2020-01-19
#  4:          4 2020-01-20 2020-01-26
#  5:          5 2020-01-27 2020-02-02
#  6:          6 2020-02-03 2020-02-09
#  7:          7 2020-02-10 2020-02-16
#  8:          8 2020-02-17 2020-02-23
#  9:          9 2020-02-24 2020-03-01
# 10:         10 2020-03-02 2020-03-08
# 11:         11 2020-03-09 2020-03-15
# 12:         12 2020-03-16 2020-03-22
# 13:         13 2020-03-23 2020-03-29
# 14:         14 2020-03-30 2020-04-05

week start on Sunday

start = x - lubridate::wday( x, week_start = 7) + 1  #!! <-- week_start = 7
# calculate last date of ending week
end   = y + 7 - lubridate::wday( y, week_start = 7 ) #!! <-- week_start = 7

mydata <- data.table( 
  date = seq( start, end, by = "1 days" )
)
#group dates by ISO weeknumber, return min and max data
mydata[, 
       .( start = min(date), end = max(date) ), 
       by = .( weeknumber = lubridate::epiweek( date ) ) ] #!! <-- epiweek

#     weeknumber      start        end
#  1:          1 2019-12-29 2020-01-04
#  2:          2 2020-01-05 2020-01-11
#  3:          3 2020-01-12 2020-01-18
#  4:          4 2020-01-19 2020-01-25
#  5:          5 2020-01-26 2020-02-01
#  6:          6 2020-02-02 2020-02-08
#  7:          7 2020-02-09 2020-02-15
#  8:          8 2020-02-16 2020-02-22
#  9:          9 2020-02-23 2020-02-29
# 10:         10 2020-03-01 2020-03-07
# 11:         11 2020-03-08 2020-03-14
# 12:         12 2020-03-15 2020-03-21
# 13:         13 2020-03-22 2020-03-28
# 14:         14 2020-03-29 2020-04-04
Wimpel
  • 26,031
  • 1
  • 20
  • 37
  • thank you for your answer. It's a smarter code than mine. However, when the week number is 1, the start is 2019-12-29, and when the weeknumbe is 14, I want to get 2020-04-04. Is this possible? – Tim Ikata Jul 14 '20 at 05:55
1

You can create a sequence of weekly dates, subtract the current week day from each day to get start_date and add 6 days to start_date to get end_date.

create_weekly_dataframe <- function(x, y) {
   seq_dates <- seq(x, y + 7, by = "week")
   start_date <- seq_dates - as.integer(format(x, '%u'))
   subset(data.frame(start_date = start_date, end_date = start_date + 6), 
          start_date <= y)
}

create_weekly_dataframe(x, y)


#   start_date   end_date
#1  2019-12-29 2020-01-04
#2  2020-01-05 2020-01-11
#3  2020-01-12 2020-01-18
#4  2020-01-19 2020-01-25
#5  2020-01-26 2020-02-01
#6  2020-02-02 2020-02-08
#7  2020-02-09 2020-02-15
#8  2020-02-16 2020-02-22
#9  2020-02-23 2020-02-29
#10 2020-03-01 2020-03-07
#11 2020-03-08 2020-03-14
#12 2020-03-15 2020-03-21
#13 2020-03-22 2020-03-28
#14 2020-03-29 2020-04-04
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Thank you for saying that the questions are not duplicated. Most of the code I was looking for. But some dates have bugs. `y <- as.Date("2020-04-30") ` `y <- as.Date("2020-07-31") ` If you set these dates to end_date, they will be retrieved until the next week. Do you know the cause? – Tim Ikata Jul 14 '20 at 06:11
  • @TimIkata Perhaps, you can use `subset` to remove such dates. Updated the answer. – Ronak Shah Jul 14 '20 at 06:35