[R] Match ISO 8601 week-of-year numbers to month-of-year numbers on Windows with German locale

S Ellison S.Ellison at LGCGroup.com
Wed Jan 18 13:35:38 CET 2017

> -----Original Message-----
> (yw <- format(posix, "%Y-%V"))
> > # [1] "2015-52" "2015-53" "2016-53" "2016-01"
> Which, after checking back with a calendar, would give me reason to believe
> that it using %V does in fact seem to work: it's an input to `format()` and R
> doesn't seem to ignore it as the correct week numbers (following ISO 8601)
> are returned.

Unfortunately it does _not_ work as an input to strptime() or as.Date(). Try
strptime(sprintf("2016-%02d", 1:52), "%Y-%V")

which all return the same (rather arbitrary-looking) date. (R 3.3.1 on Windows 7)

So you can easily extract the week number from a date, but you can't extract the month number from a week number using base R.

What you _could_ do is assign an appropriate weekday in each week and use that day to assign a month. Using the 8601 rules, Thursday seems sensible as that is the weekday used to define the week number. The following crude implementation (which allows some variation in the input string and a custom weekday defaulting to Thursday) seems to work in my UK locale, though I've not spent a lot of time debugging. You should be able to get it to work with minimal tweaking in another locale:

yw.to.month <- function(yw, yearformat="%Y", separator="-", monthformat="%m", weekday=4) {
	# yw  is a character vector assumed to be in %Y-%W" or "%y-%W"
	#     form (or with another separator specified by separator)
	# yearformat is a character string used by as.Date to convert the year.
	# separator is the year-week separator string in yw
	# monthformat is the output format, passed to format.Date
	# weekday is the (numerica) day of the week to be used to place the week 
	#         in a specific month. The default, 4, takes the Thursday.
	#Get the year as a character vector
	Y <- format(as.Date(yw, yearformat), "%Y")
	#Get the date of the first thursday in each year
	Jan01 <- as.Date(sprintf("%s-01-01", Y), "%Y-%m-%d") #constructs 1st Jan for each year
	J1.w <- as.numeric( format(Jan01, "%w") ) #numerical day of week for jan 1st
	date.increment <- ifelse(J1.w > weekday, 7 + weekday - J1.w, weekday - J1.w) #How far to first thursday?
	Thursday1 <- as.Date( Jan01 + date.increment ) #date for first thursday
	#Add the week number in yw to get the corresponding Thursday's date
	wknum <- as.numeric( gsub(sprintf(".+%s(.+)", separator), "\\1", yw) )
	Thursdays <- Thursday1 + 7 * (wknum - 1)

	#... and convert each Thursday date to month number 
	# using supplied monthformat
	format( Thursdays, monthformat )

#Construct a collection of "YYYY-WW" strings:
yw <- sprintf("%4d-%02d", rep(2015:2017, each=53), rep(1:53, 3))
	#NB: Week 53 does not exist in all years. e.g 'week 53' of 2016 is week 1 of 2017. 
	#But the week number is just used as an offset from the first specified weekday,
	#so the function does returns a valid year and month if the week number is 
	#after the year end. 

yw.to.month(yw, monthformat="%Y-%m")

#Use the month in which the Monday falls:
yw.to.month(yw, monthformat="%Y-%m", weekday=1)

Steve E

This email and any attachments are confidential. Any use...{{dropped:8}}

More information about the R-help mailing list