The day in which a week starts differs depending on context. For countries like the UK, the first day of the week is the first working day, which is Monday. This definition conforms with the ISO 8601 standard definition for the beginning of a week, but there are examples of situations where the first day of the week is different:
This package provides tools to convert dates to weeks and back where a week can start on any day. You can use this package for any of the following:
You can convert dates to weeks starting on any day by using
week_start argument. This argument can be a number from 1 to 7 representing
the ISO 8601 day of the week OR it can be a string representing the day of the
week in either an English locale or the locale defined on your computer. The
default of this argument is the value of
get_week_start(), which is a thin
options("aweek.week_start", 1L). Unless you have specified a
aweek.week_start option with
set_week_start(), this will always be
set to 1 (Monday).
It is highly recommended that you set the default
aweek.week_starteither in the beginning of your Rscript, Rmarkdown document, or in your .Rprofile.
library("aweek") set_week_start("Sunday") # setting the default week_start to Sunday set.seed(2019-03-03) dat <- as.Date("2019-03-03") + sample(-6:7, 10, replace = TRUE) dat print(w <- date2week(dat))
If you need a different day on the fly, you can supply an integer or character
day to the
# Use character days date2week(dat, week_start = "Monday") # Use ISO 8601 days date2week(dat, week_start = 1)
If you want to save two extra keystrokes, you can also use the
method for dates, which wraps
as.aweek(dat, week_start = 1)
What you get back is an
aweek class object. It can be converted back to a date
The calculation of weeks from dates requires knowledge of the current day of the week and the number of days past 1 January.
Week numbers are calculated in three steps:
d = 1L + ((i + (7L - s)) %% 7L).
m = date + (4 - d).
w = 1L + ((m - yyyy-01-01) %/% 7)
For example, here's how to calculate the week for Tuesday, 6 December 2016, assuming the week start is a Sunday:
the_date <- as.Date("2016-12-06") jan_1 <- as.Date("2016-01-01") i <- as.POSIXlt(the_date)$wday # 2, the ISO date for Tuesday s <- 7L # week_start for sunday # 1. Find the day of the week print(d <- 1L + ((i + (7L - s)) %% 7L)) # 2. Find the date that represents midweek print(m <- the_date + (4L - d)) # 3. Find the week print(w <- 1L + as.integer(m - jan_1) %/% 7L) # Format the week sprintf("2016-W%02d-%d", w, d)
For the weeks around 1 January, the year is determined by the week number. If the month is January, but the week number is 52 or 53, then the year for the week (YYYY) is the calendar year (yyyy) minus 1. However, if the month is December, but the week number is 1, then the year for the week (YYYY) is the calendar year (yyyy) plus 1.
The result you see above is an object of class "aweek". The
aweek class is a
character that contains the
week_start attribute. This attribute allows it to
be easily converted back to a date without the user needing to enter the start
day every time. You can convert a character that matches the
pattern to an
aweek class object with
x <- as.aweek("2019-W10-1") x
Under the hood, it checks the validity of the week string and then add the attribute and class:x <- "2019-W10-1" attr(x, "week_start") <- 7 # Sunday class(x) <- "aweek"
If you need to remove the class, you can just use
date2week() function only checks that dates are in ISO 8601 (yyyy-mm-dd)
format before converting to weeks, and otherwise assumes that the dates are
accurate so it's strongly recommended to make sure your dates are in either
POISXt format and accurate before converting to weeks. The
lubridate can be used for this
set_week_start() at the beginning of all your scripts to explicitly define
the day on which your weeks start. This can be overridden if need be in specific
parts of your scripts. Otherwise, the default will be dependent on the value of
week_start arguments default to
recommended to specify
week2date() if you
don't have an
Before you combine aweek objects, confirm that they are actually aweek objects
There are times where you would want to aggregate your days into weeks, you can
do this by specifying
floor_day = TRUE in
date2week(). For example, here we
can show the individual weeks:
print(wf <- date2week(dat, week_start = "Saturday", floor_day = TRUE)) table(wf)
If you convert this to date, then all the dates will represent the beginning of the week:
print(dwf <- week2date(wf)) weekdays(dwf)
If you want to aggregate your
aweek objects after you created them, you can
always use the
w <- date2week(dat) w trunc(w)
Weeks can be represented as factors, which is useful for tabulations across
weeks. You can use
factor = TRUE in
date2week() and it will automatically
fill in any missing weeks.
dat + c(0, 15) date2week(dat + c(0, 15), week_start = 1, factor = TRUE)
If you already have an aweek object and want to convert it to a factor, you
Be careful when combining factors with other dates or aweek objects as they will force the other objects to be truncated as well.
You can use
change_week_start() to convert between different week definitions
if you have an
w # week starting on Sunday ww <- change_week_start(w, week_start = "wednesday") # same dates, starting on Wednesday ww identical(as.Date(w), as.Date(ww))
# create a table with all days in the week d <- as.Date("2019-03-03") + 0:6 res <- lapply(weekdays(d), function(i) date2week(d, week_start = i)) names(res) <- weekdays(d) data.frame(res)
All of these columns contain the same dates:
You can add dates, aweek objects, or characters to aweek objects:
c(as.aweek("2010-W10-1"), res$Sunday, "2010-W12-1", as.Date(res$Monday) + 14)
However, you can not combine aweek objects with different
c(res$Sunday, res$Wednesday, res$Friday)
If you want to combine different aweek objects, you must first change their
wed <- change_week_start(res$Wednesday, get_week_start()) fri <- change_week_start(res$Friday, get_week_start()) c(res$Sunday, wed, fri)
Dates combined with aweek objects will will be automatically converted.
You can also add character representation of weeks, but be aware that it is
assumed that these have the same
week_start as the first object.
s <- c(res$Saturday, "2019-W14-3") s m <- c(res$Monday, "2019-W14-3") m
These will translate into different dates
You may encounter a situation where you have a merged data frame with weeks
starting on different days. This section will cover two situations where you
may have weeks as numbers and weeks as ISO-week strings. First we will create
our demonstration data that represents the same week with different
# create a table with all days in the week d <- as.Date("2019-03-03") + 0:6 res <- lapply(weekdays(d), function(i) date2week(d, week_start = i)) resn <- lapply(weekdays(d), function(i) date2week(d, week_start = i, numeric = TRUE)) datf <- data.frame(wday = rep(weekdays(d), each = 7), week = unlist(res), # note: unlist converts to character week_number = unlist(resn), year = 2019, stringsAsFactors = FALSE) datf$day <- substring(datf$week, 10, 11) head(datf, 10)
To get the weeks (numbers or strings) to aweek objects, you should use the
start argument to specify which day of the week they start on. Internally,
this translates the week to their corresponding dates and then to aweek objects
with the same
week_start attribute (which defaults to
Most commonly, you will have weeks across data sets represented by numbers.
These can be converted to aweek objects using the
and to dates using the
datf$aweek <- with(datf, get_aweek(week = week_number, year = year, day = day, start = wday)) datf$date <- with(datf, get_date(week = week_number, year = year, day = day, start = wday)) head(datf, 10)
These functions are also useful for constructing weeks or dates on the fly if you only have a week and a year:
get_aweek(11, 2019) get_date(11, 2019)
datf$aweek <- NULL datf$date <- NULL
If you have weeks formatted as ISO-week strings, then you can convert to aweek
datf$aweek <- with(datf, as.aweek(week, start = wday)) head(datf, 10) str(datf)
We can tabulate them to see how they transformed:
print(with(datf, table(before = week, after = aweek)), zero.print = ".")
If you receive data that contains week definitions, you can convert it back to a date if you know where the week starts.
week2date("2019-W10-1", week_start = "Sunday") # 2019-03-03 week2date("2019-W10-1", week_start = "Monday") # 2019-03-04
If you have an
aweek object, however, it will use the
defined in the object, even if the default
week_start attribute is different:
set_week_start("Monday") # Set the default week_start to ISO week get_week_start(w) # show the default week_start for w week2date(w) identical(week2date(w), dat) # TRUE identical(week2date(as.character(w)), dat) # FALSE
You can also use
as.POISXlt() if you have an
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.