15

Within R, say I have a vector of some Lubridate dates:

> Date
"2012-01-01 UTC"
"2013-01-01 UTC"

Next, suppose I want to see what week number these days fall in:

> week(Date)
1
1

Lubridate is fantastic!

But wait...I'm dealing a time series with 10,000 rows of data...and the data spans 3 years.

I've been struggling with finding some way to make this happen:

> result of awesome R code here
1
54

The question: is there a succinct way to coax out a list of week numbers over multiyear periods within Lubridate? More directly, I would like the first week of the second year to be represented as the 54th week. And the first week in the third year to be represented as the 107th week, ad nauseum.

So far, I've attempted a number of hackney schemes but cannot seem to create something not fastened together with scotch tape. Any advice would be greatly appreciated. Thanks in advance.

tumultous_rooster
  • 12,150
  • 32
  • 92
  • 149
  • You want to generate the offset in weeks from January of the lowest year in the series? – beroe Nov 05 '13 at 01:32
  • essentially you want to calculate difference between dates in terms of week. Right? In that case @beroe's answer seems correct – CHP Nov 05 '13 at 02:09
  • Your added explanation helps, but it is not very accurate. There are only two days at the end of a typical year that are in week 53 (Dec 30 and 31). Dec 29th is in week 52 (or 53 on leap years). So do you want January 1st of the following year to say 54 anyway? If so, use agstudy's answer. If not, use `trunc()` on my answer to get just the integer part. – beroe Nov 05 '13 at 07:46

4 Answers4

15

To get the interval from a particular date to another date, you can just subtract...

If tda is your vector of dates, then

tda - min(tda)

will be the difference in seconds between them.

To get the units out in weeks:

(tda - min(tda))/eweeks(1)

To do it from a particular date:

tda - ymd(19960101)

This gives the number of days from 1996 to each value.

From there, you can divide by days per week, or seconds per week.

(tda - ymd(19960101))/eweeks(1)

To get only the integer part, and starting from January 2012:

trunc((tda - ymd(20111225))/eweeks(1))

Test data:

tda = ymd(c(20120101, 20120106, 20130101, 20130108))

Output:

 1  1 53 54
beroe
  • 11,784
  • 5
  • 34
  • 79
6

Since eweeks() is now deprecated, I thought I'd add to @beroe's answer.

If tda is your date vector, you can get the week numbers with:

weeknos <- (interval(min(tda), tda) %/% weeks(1)) + 1

where %/% causes integer division. ( 5 / 3 = 1.667; 5 %/% 3 = 1)

s-heins
  • 679
  • 1
  • 8
  • 20
3

You can do something like this :

week(dat) +53*(year(dat)-min(year(dat)))
agstudy
  • 119,832
  • 17
  • 199
  • 261
  • This was my first thought as well, but this may not be robust. Do all years have 53 weeks? How about days in the beginning of the second year that fall in the same week as the last week of the first year? etc. – ialm Nov 05 '13 at 01:57
  • 1
    @ialm yes that's why I am saying that " like this" ... I am just giving the idea here not the final solution. – agstudy Nov 05 '13 at 02:02
0

Given you like lubridate (as do I)

year_week <- function(x,base) week(x) - week(base) + 52*(year(x) - year(base))
test <- ymd(c(20120101, 20120106, 20130101, 20130108))
year_week(test, "2012-01-01")

Giving

[1]  0  0 52 53
Surpdeh
  • 81
  • 3
  • Having just read @agstudy comment above, this approach will have the same problem - not all years have 52 weeks.... – Surpdeh May 20 '20 at 01:48