I have list of week numbers extracted from huge log file, they were extracted using syntax:
$ date --date="Wed Mar 20 10:19:56 2012" +%W;
12
I want to create a simple bash function which can convert these week numbers to a date range. I suppose function should accept 2 arguments: $number and $year, example:
$ week() { ......... }
$ number=12; year=2012
$ week $number $year
"Mon Mar 19 2012" - "Sun Mar 25 2012"
To format date in YYYY-MM-DD format, use the command date +%F or printf "%(%F)T\n" $EPOCHSECONDS . The %F option is an alias for %Y-%m-%d . This format is the ISO 8601 format.
the OP's week num is from date +%W . you can try: date --date="2020-05-17 01:00:00" +%W outputs 19 and date --date="2020-05-18 01:00:00" +%W outputs 20 . GNU date's manual: %W - week number of year, with Monday as first day of week (00.. 53) .
Linux date Command Format Options%D – Display date as mm/dd/yy. %Y – Year (e.g., 2020) %m – Month (01-12)
With GNU date
:
$ cat weekof.sh
function weekof()
{
local week=$1 year=$2
local week_num_of_Jan_1 week_day_of_Jan_1
local first_Mon
local date_fmt="+%a %b %d %Y"
local mon sun
week_num_of_Jan_1=$(date -d $year-01-01 +%W)
week_day_of_Jan_1=$(date -d $year-01-01 +%u)
if ((week_num_of_Jan_1)); then
first_Mon=$year-01-01
else
first_Mon=$year-01-$((01 + (7 - week_day_of_Jan_1 + 1) ))
fi
mon=$(date -d "$first_Mon +$((week - 1)) week" "$date_fmt")
sun=$(date -d "$first_Mon +$((week - 1)) week + 6 day" "$date_fmt")
echo "\"$mon\" - \"$sun\""
}
weekof $1 $2
$ bash weekof.sh 12 2012
"Mon Mar 19 2012" - "Sun Mar 25 2012"
$ bash weekof.sh 1 2018
"Mon Jan 01 2018" - "Sun Jan 07 2018"
$
As the OP mentions, the week number is got by date +%W
. According to GNU date's manual:
%W
: week number of year, with Monday as first day of week (00..53)
So:
Everything depends on the definition of week numbers you are used too.
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:
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
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With