3

I have dates encoded in a weekly time format (European convention >> 01 through 52/53, e.g. "2016-48") and would like to standardize them to a POSIX date:

require(magrittr)
(x <- as.POSIXct("2016-12-01") %>% format("%Y-%V"))
# [1] "2016-48"
as.POSIXct(x, format = "%Y-%V")
# [1] "2016-01-11 CET"

I expected the last statement to return "2016-12-01" again. What am I missing here?


Edit

Thanks to Dirk, I was able to piece it together:

y <- sprintf("%s-1", x)

While I still don't get why this doesn't work

(as.POSIXct(y, format = "%Y-%V-%u"))
# [1] "2016-01-11 CET"

this does

(as.POSIXct(y, format = "%Y-%U-%u")
# [1] "2016-11-28 CET"

Edit 2

Oh my, I think using %V is a very bad idea in general:

as.POSIXct("2016-01-01") %>% format("%Y-%V")
# [1] "2016-53"

Should this be considered to be on a "serious bug" level that requires further action?!

Sticking to either %U or %W seems to be the right way to go

as.POSIXct("2016-01-01") %>% format("%Y-%U")
# [1] "2016-00"

Edit 3

Nope, not quite finished/still puzzled: the approach doesn't work for the very first week

(x <- as.POSIXct("2016-01-01") %>% format("%Y-%W"))
# [1] "2016-00"

as.POSIXct(sprintf("%s-1", x), format = "%Y-%W-%u")
# [1] NA

It does for week 01 as defined in the underlying convention when using %U or %W (so "week 2", actually)

as.POSIXct("2016-01-1", format = "%Y-%W-%u")
# [1] "2016-01-04 CET"
Rappster
  • 11,680
  • 7
  • 58
  • 113
  • 3
    You can _reduce_ a date to a year-week number, but you cannot go back as there are seven possibly values in that week. – Dirk Eddelbuettel Jan 11 '17 at 18:10
  • @DirkEddelbuettel: aha, that makes sense. Do you know of any workarounds? I do need to infer the month, I don't really care about the exact day – Rappster Jan 11 '17 at 18:14
  • 1
    From memory there is also a _weekday_ formatter. If you just append a value (one, say) you should have the beginning of the week. – Dirk Eddelbuettel Jan 11 '17 at 18:15
  • @DirkEddelbuettel Thanks Dirk! R doesn't really seem to like `%V` though - even though it says it does, sort of, in `strptime` ;-) As always: what a pain. In that regard: thanks for `anydate`! – Rappster Jan 11 '17 at 18:23
  • Related: [How to Parse Year + Week Number in R?](http://stackoverflow.com/questions/9380435/how-to-parse-year-week-number-in-r) – Henrik Jan 11 '17 at 18:30
  • @Henrik thanks for the pointer – Rappster Jan 11 '17 at 18:36
  • @DirkEddelbuettel could you think of any fix for making the hack work for the *very first* week (`00` in `%U` or `%W` convention)? See **Edit 3** for an example – Rappster Jan 11 '17 at 18:49
  • Unsure. My instinct would be to examine how C library variant of `strptime()` / `strftime()` works on your OS. I think on all-but-Windows R uses the external C library one. – Dirk Eddelbuettel Jan 11 '17 at 19:47
  • @DirkEddelbuettel Thanks... stupid Windows ;-) I don't know anything about C, but maybe I'll manage to find it somehow. At all: any help in shedding light on this greatly appreciated – Rappster Jan 11 '17 at 20:07
  • I had issues with `%V` here too when testing, and I am on Ubuntu. There may be something else going on but I don't have the spare time to go digging. Most importantly we have your question answered. – Dirk Eddelbuettel Jan 11 '17 at 20:09
  • 1
    As explained in [this answer](https://stackoverflow.com/a/45543682/3817004) in more detail, you need to use the `%G` week-based year format specifier instead of `%Y` when formating dates as ISO week, i.e., `%G-W%V-%u` for one of the ISO 8601 compliant formats. – Uwe Aug 07 '17 at 09:47

1 Answers1

2

As I have to deal a lot with reporting by ISO weeks, I've created the ISOweek package some years ago.

The package includes the function ISOweek2date() which returns the date of a given weekdate (year, week of the year, day of week according to ISO 8601). It's the inverse function to date2ISOweek().

With ISOweek, your examples become:

library(ISOweek)

# define dates to convert
dates <- as.Date(c("2016-12-01", "2016-01-01"))

# convert to full ISO 8601 week-based date yyyy-Www-d
(week_dates <- date2ISOweek(dates))
[1] "2016-W48-4" "2015-W53-5"
# convert back to class Date 
ISOweek2date(week_dates)
[1] "2016-12-01" "2016-01-01"

Note that date2ISOweek() requires a full ISO week-based date in the format yyyy-Www-d including the day of the week (1 to 7, Monday to Sunday).

So, if you only have year and ISO week number you have to create a character string with a day of the week specified.

A typical phrase in many reports is, e.g., "reporting week 31 ending 2017-08-06":h

yr <- 2017
wk <- 31
ISOweek2date(sprintf("%4i-W%02i-%1i", yr, wk, 7))
 [1] "2017-08-06"

Addendum

Please, see this answer for another use case and more background information on the ISOweek package.

Community
  • 1
  • 1
Uwe
  • 34,565
  • 10
  • 75
  • 109