0

I have date information given as <YEAR>-<WEEK-OF-YEAR> and I'd like to tell R "give me the POSIX dates of the first days for each of those weeks", how would I do that?

I do get it working by pasting"-1" (for "1st day of week") to the vector of <YEAR>-<WEEK-OF-YEAR> strings and then using conversion spec %u in the call to as.POSIXct for weeks 1-52, but not for week 53.

Example

weeks <- as.character(1:53)
weeks[nchar(weeks) == 1] <- paste0("0", weeks[nchar(weeks) == 1])
first_day_of_week_wday <- paste0("2015-", weeks, "-1")
first_day_of_week_posix <- as.POSIXct(first_day_of_week_wday,
  format = "%Y-%U-%u")

data.frame(
  wday = first_day_of_week_wday,
  posix = first_day_of_week_posix,
  stringsAsFactors = FALSE
)
#>         wday      posix
#> 1  2015-01-1 2015-01-05
#> 2  2015-02-1 2015-01-12
#> 3  2015-03-1 2015-01-19
#> 4  2015-04-1 2015-01-26
#> 5  2015-05-1 2015-02-02
#> 6  2015-06-1 2015-02-09
#> 7  2015-07-1 2015-02-16
#> 8  2015-08-1 2015-02-23
#> 9  2015-09-1 2015-03-02
#> 10 2015-10-1 2015-03-09
#> 11 2015-11-1 2015-03-16
#> 12 2015-12-1 2015-03-23
#> 13 2015-13-1 2015-03-30
#> 14 2015-14-1 2015-04-06
#> 15 2015-15-1 2015-04-13
#> 16 2015-16-1 2015-04-20
#> 17 2015-17-1 2015-04-27
#> 18 2015-18-1 2015-05-04
#> 19 2015-19-1 2015-05-11
#> 20 2015-20-1 2015-05-18
#> 21 2015-21-1 2015-05-25
#> 22 2015-22-1 2015-06-01
#> 23 2015-23-1 2015-06-08
#> 24 2015-24-1 2015-06-15
#> 25 2015-25-1 2015-06-22
#> 26 2015-26-1 2015-06-29
#> 27 2015-27-1 2015-07-06
#> 28 2015-28-1 2015-07-13
#> 29 2015-29-1 2015-07-20
#> 30 2015-30-1 2015-07-27
#> 31 2015-31-1 2015-08-03
#> 32 2015-32-1 2015-08-10
#> 33 2015-33-1 2015-08-17
#> 34 2015-34-1 2015-08-24
#> 35 2015-35-1 2015-08-31
#> 36 2015-36-1 2015-09-07
#> 37 2015-37-1 2015-09-14
#> 38 2015-38-1 2015-09-21
#> 39 2015-39-1 2015-09-28
#> 40 2015-40-1 2015-10-05
#> 41 2015-41-1 2015-10-12
#> 42 2015-42-1 2015-10-19
#> 43 2015-43-1 2015-10-26
#> 44 2015-44-1 2015-11-02
#> 45 2015-45-1 2015-11-09
#> 46 2015-46-1 2015-11-16
#> 47 2015-47-1 2015-11-23
#> 48 2015-48-1 2015-11-30
#> 49 2015-49-1 2015-12-07
#> 50 2015-50-1 2015-12-14
#> 51 2015-51-1 2015-12-21
#> 52 2015-52-1 2015-12-28
#> 53 2015-53-1       <NA>

Due dilligence

Apparently dates are treated quite differently on Windows vs. MacOS/Linux. Suggestion based on using %G instead of %Y as in the comments of this question gives the following result:

as.POSIXct(first_day_of_week_wday, format = "%G-%U-%u")
#>  [1] "2018-01-08 CET"  "2018-01-15 CET"  "2018-01-22 CET" 
#>  [4] "2018-01-29 CET"  "2018-02-05 CET"  "2018-02-12 CET" 
#>  [7] "2018-02-19 CET"  "2018-02-26 CET"  "2018-03-04 CET" 
#> [10] "2018-03-11 CET"  "2018-03-18 CET"  "2018-03-25 CET" 
#> [13] "2018-04-01 CEST" "2018-04-08 CEST" "2018-04-15 CEST"
#> [16] "2018-04-22 CEST" "2018-04-29 CEST" "2018-05-06 CEST"
#> [19] "2018-05-13 CEST" "2018-05-20 CEST" "2018-05-27 CEST"
#> [22] "2018-06-03 CEST" "2018-06-10 CEST" "2018-06-17 CEST"
#> [25] "2018-06-24 CEST" "2018-07-01 CEST" "2018-07-08 CEST"
#> [28] "2018-07-15 CEST" "2018-07-22 CEST" "2018-07-29 CEST"
#> [31] "2018-08-05 CEST" "2018-08-12 CEST" "2018-08-19 CEST"
#> [34] "2018-08-26 CEST" "2018-09-02 CEST" "2018-09-09 CEST"
#> [37] "2018-09-16 CEST" "2018-09-23 CEST" "2018-09-30 CEST"
#> [40] "2018-10-07 CEST" "2018-10-14 CEST" "2018-10-21 CEST"
#> [43] "2018-10-28 CEST" "2018-11-04 CET"  "2018-11-11 CET" 
#> [46] "2018-11-18 CET"  "2018-11-25 CET"  "2018-12-02 CET" 
#> [49] "2018-12-09 CET"  "2018-12-16 CET"  "2018-12-23 CET" 
#> [52] "2018-12-30 CET"  NA

as.POSIXct(first_day_of_week_wday, format = "%G-%V-%u")
#>  [1] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#>  [5] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#>  [9] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [13] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [17] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [21] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [25] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [29] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [33] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [37] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [41] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [45] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [49] "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET" "2018-01-26 CET"
#> [53] "2018-01-26 CET"
Rappster
  • 11,680
  • 7
  • 58
  • 113
  • 1
    Did you have a look at the `isoweek` package? `ISOweek2date` should solve your problem. – Buggy Jan 26 '18 at 15:43
  • @user3293236: if possible, I'd like to get this working within base R. But thanks for the pointer – Rappster Jan 26 '18 at 15:44
  • added some more explanation to my answer. Hope that helps with regard to the ISO standard on windows. – Buggy Jan 26 '18 at 15:58
  • Which of the different definitions of week of the year are you using? The US, the UK or the ISO convention? See my answer [here](https://stackoverflow.com/a/45587644/3817004) for an explanation. – Uwe Jan 28 '18 at 15:00
  • @Uwe the ISO convention – Rappster Jan 29 '18 at 11:14

2 Answers2

2

The ISOweeksolution:

library(ISOweek)
weeks <- as.character(1:53)
weeks[nchar(weeks) == 1] <- paste0("0", weeks[nchar(weeks) == 1])
first_day_of_week_wday <- paste0("2015-W", weeks, "-1")
ISOweek2date(first_day_of_week_wday)

Just some more clarification on why your second attempt with the %V won't work on windows.

From the package description: This is an substitute for the %V and %u formats which are not implemented on Windows. In addition, the package offers functions to convert from standard calender format yyyy-mm-dd to and from ISO 8601 week format yyyy-Www-d

Buggy
  • 1,829
  • 17
  • 24
  • Great, thanks for your effort. I extracted all the code I needed to use the ISOweek solution without relying on the whole package. Still it kind of blows my mind that this seems to be impossible to do with base R functionality on Windows – Rappster Jan 26 '18 at 16:13
0

The Base R solution:

You cannot produce a value for week 53 because strptime does not recognize there being a 'full' monday during that period. The code works if the date becomes 2016, week 1 instead of 2015, week 53.

weeks <- c(1:52,1)
yr <- c(rep('2015-',52),'2016-')
weeks[nchar(weeks) == 1] <- paste0("0", weeks[nchar(weeks) == 1])
first_day_of_week_wday <- paste0(yr, weeks, "-1")
first_day_of_week_posix <- as.POSIXct(first_day_of_week_wday,
                                      format = "%Y-%U-%u")

data.frame(
  wday = first_day_of_week_wday,
  posix = first_day_of_week_posix,
  stringsAsFactors = FALSE
)

        wday      posix
1   2015-1-1 2015-01-05
2   2015-2-1 2015-01-12
3   2015-3-1 2015-01-19
4   2015-4-1 2015-01-26
5   2015-5-1 2015-02-02
6   2015-6-1 2015-02-09
7   2015-7-1 2015-02-16
8   2015-8-1 2015-02-23
9   2015-9-1 2015-03-02
10 2015-10-1 2015-03-09
11 2015-11-1 2015-03-16
12 2015-12-1 2015-03-23
13 2015-13-1 2015-03-30
14 2015-14-1 2015-04-06
15 2015-15-1 2015-04-13
16 2015-16-1 2015-04-20
17 2015-17-1 2015-04-27
18 2015-18-1 2015-05-04
19 2015-19-1 2015-05-11
20 2015-20-1 2015-05-18
21 2015-21-1 2015-05-25
22 2015-22-1 2015-06-01
23 2015-23-1 2015-06-08
24 2015-24-1 2015-06-15
25 2015-25-1 2015-06-22
26 2015-26-1 2015-06-29
27 2015-27-1 2015-07-06
28 2015-28-1 2015-07-13
29 2015-29-1 2015-07-20
30 2015-30-1 2015-07-27
31 2015-31-1 2015-08-03
32 2015-32-1 2015-08-10
33 2015-33-1 2015-08-17
34 2015-34-1 2015-08-24
35 2015-35-1 2015-08-31
36 2015-36-1 2015-09-07
37 2015-37-1 2015-09-14
38 2015-38-1 2015-09-21
39 2015-39-1 2015-09-28
40 2015-40-1 2015-10-05
41 2015-41-1 2015-10-12
42 2015-42-1 2015-10-19
43 2015-43-1 2015-10-26
44 2015-44-1 2015-11-02
45 2015-45-1 2015-11-09
46 2015-46-1 2015-11-16
47 2015-47-1 2015-11-23
48 2015-48-1 2015-11-30
49 2015-49-1 2015-12-07
50 2015-50-1 2015-12-14
51 2015-51-1 2015-12-21
52 2015-52-1 2015-12-28
53  2016-1-1 2016-01-04
jessefleri
  • 109
  • 5
  • Okay, nice. It does feel hacky, but at least now I know how to workaround 53-week cases. Thanks! – Rappster Jan 26 '18 at 17:25
  • The correct answer depends on the convention for week of the year used: US, UK, or ISO. According to the US and UK conventions, there is *no* week 53 in 2015 (but there was one in 2012 and 2017). But according to the ISO convention, there was a week 53 in 2015. – Uwe Jan 28 '18 at 16:45
  • The OP now has confirmed that he is using the ISO convention. So, your answer returns the wrong results as the first ISO week of 2015 (2015-W01) starts on Monday, 2014-12-29. Consequently, all week numbers are off by one. The last ISO week of 2015 (2015-W53) starts on Monday, 2015-12-28. – Uwe Jan 28 '18 at 22:34