Everything depends on the definition of week numbers you are
used too.
European (ISO 8601)
This ISO 8601 standard is widely used in the world: EU and most of other
European countries, most of Asia, and Oceania
The ISO 8601 standard states the following:
- There are 7 days in a week
- The first day of the week is a Monday
- The first week is the first week of the year which contains a
Thursday. This means it is the first week with 4 days or more
in January.
With this definition, it is possible to have a week number 53. These occur with the first of January is on a
Friday (E.g. 2016-01-01, 2010-01-01). Or, if the year before was a
leap year, also a Saturday. (E.g. 2005-01-01)
December 2015 January 2016
Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW
1 2 3 4 5 6 49 1 2 3 53
7 8 9 10 11 12 13 50 4 5 6 7 8 9 10 01
14 15 16 17 18 19 20 51 11 12 13 14 15 16 17 02
21 22 23 24 25 26 27 52 18 19 20 21 22 23 24 03
28 29 30 31 53 25 26 27 28 29 30 31 04
function week_range() {
local _u _F _V
# dow Jan 01 (Mon 01 ... Sun 07)
_u="$(date -d "$1-01-01" "+%u")"
# First Monday
_F="$(date -d "$1-01-01 + $(( (8 - _u) % 7)) days" "+%F")"
# Week number of first Monday
_V="$(date -d "$_F" "+%V")"
printf -- "%s-%s\n" "$(date -d "$_F + $(( 7*($2 - _V) )) days" "+%F")" \
"$(date -d "$_F + $(( 7*($2 - _V) + 6 )) days" "+%F")"
}
$ week_range 2016 1; done
2016-01-04 - 2016-01-10
$ week_range 2020 1; done
2019-12-30 - 2020-01-05 << week one starts in the previous year
$ week_range 2020 20
2020-05-11 - 2020-05-17
American or Islamic (Not ISO 8601)
Not all countries use the ISO 8601 system. They use a more absolute approach.
The American system is used in Canada, United States, New Zealand, India, Japan,...
The Islamic system is generally used in the middle east.
Both systems are very similar.
American:
- There are 7 days in a week
- The first day of the week is a Sunday
- The first week starts on the 1st of January
With this definition, it is possible to have partial weeks at the
beginning and the end of a year. Hence the first and last week of the
year could not contain all weekdays.
December 2015 January 2016
Su Mo Tu We Th Fr Sa CW Su Mo Tu We Th Fr Sa CW
1 2 3 4 5 49 1 2 01
6 7 8 9 10 11 12 50 3 4 5 6 7 8 9 02
13 14 15 16 17 18 19 51 10 11 12 13 14 15 16 03
20 21 22 23 24 25 26 52 17 18 19 20 21 22 23 04
27 28 29 30 31 53 24 25 26 27 28 29 30 05
31 06
function week_range() {
local _w _F _V _d1 _d2
# dow Jan 01 (Sun 01 ... Sat 07)
_w="$(date -d "$1-01-01" "+%w")"
(( _w = _w + 1 ))
# First Saturday
_F="$(date -d "$1-01-01 + $(( (8 - _w) % 7)) days" "+%F")"
# Week number of first Sunday
[[ "$_F" == "$1-01-01" ]] && _V=1 || _V=2
# Start and end
_d1="$(date -d "$_F + $(( 7*($2 - _V) )) days" "+%F")"
_d2="$(date -d "$_F + $(( 7*($2 - _V) + 6 )) days" "+%F")"
[[ "$_d1" < "$1-01-01" ]] && _d1="$1-01-01"
[[ "$_d2" > "$1-12-31" ]] && _d2="$1-12-31"
[[ "$_d1" > "$1-12-31" ]] && echo "invalid week number" > /dev/stderr && return
printf -- "%s - %s\n" \
"$(date -d "$_d1" "+%m/%d/%Y")" \
"$(date -d "$_d2" "+%m/%d/%Y")"
}
$ week_range 2015 53
12/27/2015 - 12/31/2015
$ week_range 2016 1
01/01/2016 - 01/02/2016
$ week_range 2020 20
05/10/2020 - 05/16/2020
Islamic:
- There are 7 days in a week
- The first day of the week is a Saturday
- The first week starts on the 1st of January
With this definition, it is possible to have partial weeks at the
beginning and the end of a year. Hence the first and last week of the
year could not contain all weekdays.
December 2015 January 2016
Sa Su Mo Tu We Th Fr CW Sa Su Mo Tu We Th Fr CW
1 2 3 4 49 1 01
5 6 7 8 9 10 11 50 2 3 4 5 6 7 8 02
12 13 14 15 16 17 18 51 9 10 11 12 13 14 15 03
19 20 21 22 23 24 25 52 16 17 18 19 20 21 22 04
26 27 28 29 30 31 53 23 24 25 26 27 28 29 05
30 31 06
function week_range() {
local _w _F _V _d1 _d2
# dow Jan 01 (Sat 01 ... Fri 07)
_w="$(date -d "$1-01-01" "+%w")"
(( _w = (_w + 8) % 7 + 1 ))
# First Saturday
_F="$(date -d "$1-01-01 + $(( (8 - _w) % 7)) days" "+%F")"
# Week number of first Saturday
[[ "$_F" == "$1-01-01" ]] && _V=1 || _V=2
# Start and end
_d1="$(date -d "$_F + $(( 7*($2 - _V) )) days" "+%F")"
_d2="$(date -d "$_F + $(( 7*($2 - _V) + 6 )) days" "+%F")"
[[ "$_d1" < "$1-01-01" ]] && _d1="$1-01-01"
[[ "$_d2" > "$1-12-31" ]] && _d2="$1-12-31"
[[ "$_d1" > "$1-12-31" ]] && echo "invalid week number" > /dev/stderr && return
printf -- "%s - %s\n" "${_d1//-//}" "${_d2//-//}"
}
$ week_range 2015 53
2015/12/26 - 2015/12/31
$ week_range 2016 1
2016/01/01 - 2016/01/01
$ week_range 2020 20
2020/05/09 - 2020/05/15
Note: There are other methods of defining a week number. Nonetheless, the approach stays the same.