bash UNIX 日期:如何将周数(日期 +%W)转换为日期范围(周一至周日)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15606567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:58:38  来源:igfitidea点击:

UNIX date: How to convert week number (date +%W) to a date range (Mon-Sun)?

bashunixdateshunix-timestamp

提问by hellish

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:

我想创建一个简单的 bash 函数,可以将这些周数转换为日期范围。我想函数应该接受 2 个参数:$number 和 $year,例如:

$ week() { ......... }
$ number=12; year=2012
$ week $number $year
"Mon Mar 19 2012" - "Sun Mar 25 2012"

回答by pynexj

With GNU date:

GNU date

$ cat weekof.sh
function weekof()
{
    local week= year=
    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  
$ 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"
$


NOTE:

笔记:

As the OP mentions, the week numberis got by date +%W. According to GNU date's manual:

正如 OP 所提到的,周数是由date +%W. 根据 GNU 日期手册

%W: week number of year, with Monday as first day of week(00..53)

%W: 年的周数,以星期一为一周的第一天(00..53)

So:

所以:

  1. Each week would start from Mon.
  2. If Jan 1 is Mon, then the firstweek will be week #1.
  3. If Jan 1 is not Mon, then the first few days will be week #0and the week #1starts from the first Mon.
  1. 每个星期从星期一开始。
  2. 如果 Jan 1 是 Mon,那么第一周将是week #1
  3. 如果1月1日不星期一,然后头几天将是一周#0周#1从第一个星期一开始

回答by David ?míd

Monday is the first day of week, ISO week numbers:

星期一是一周的第一天,ISO 周数

function week2date () {
  local year=
  local week=
  local dayofweek=
  date -d "$year-01-01 +$(( $week * 7 + 1 - $(date -d "$year-01-04" +%u ) - 3 )) days -2 days + $dayofweek days" +"%Y-%m-%d"
}

week2date 2017 35 1
week2date 2017 35 7

Output:

输出:

2017-08-28
2017-09-03

回答by kvantour

Everything depends on the definition of week numbers you are used too.

一切都取决于您使用的周数的定义。

European (ISO 8601)

欧洲 (ISO 8601)

This ISO 8601 standardis widely used in the world: EU and most of other European countries, most of Asia, and Oceania

ISO 8601 标准在世界范围内广泛使用:欧盟和其他大部分欧洲国家、大部分亚洲和大洋洲

The ISO 8601 standard states the following:

ISO 8601 标准规定如下:

  • 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.
  • 一周有 7 天
  • 一周的第一天是星期一
  • 第一周是包含星期四的一年中的第一周 。这意味着这是一月份有 4 天或更多天的第一周。

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)

根据此定义,周数可能为 53。这些发生在 1 月 1 日是星期五(例如 2016-01-01、2010-01-01)。或者,如果前一年是闰年,也是星期六。(例如 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 "-01-01" "+%u")"
    # First Monday
    _F="$(date -d "-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*( - _V) )) days" "+%F")"       \
                        "$(date -d "$_F + $(( 7*( - _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)

美国或伊斯兰(非 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.

并非所有国家/地区都使用 ISO 8601 系统。他们使用更绝对的方法。美国系统用于加拿大、美国、新西兰、印度、日本、... 伊斯兰系统一般用于中东。两个系统非常相似。

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
  • 一周有 7 天
  • 一周的第一天是星期日
  • 第一周从 1 月 1 日开始

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 "-01-01" "+%w")"
    (( _w = _w + 1 ))
    # First Saturday
    _F="$(date -d "-01-01 + $(( (8 - _w) % 7)) days" "+%F")"
    # Week number of first Sunday
    [[ "$_F" == "-01-01" ]] && _V=1 || _V=2
    # Start and end
    _d1="$(date -d "$_F + $(( 7*( - _V) )) days" "+%F")"
    _d2="$(date -d "$_F + $(( 7*( - _V) + 6 )) days" "+%F")"
    [[ "$_d1" < "-01-01" ]] && _d1="-01-01"
    [[ "$_d2" > "-12-31" ]] && _d2="-12-31"
    [[ "$_d1" > "-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
  • 一周有 7 天
  • 一周的第一天是星期六
  • 第一周从 1 月 1 日开始

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 "-01-01" "+%w")"
    (( _w = (_w + 8) % 7 + 1 ))
    # First Saturday
    _F="$(date -d "-01-01 + $(( (8 - _w) % 7)) days" "+%F")"
    # Week number of first Saturday
    [[ "$_F" == "-01-01" ]] && _V=1 || _V=2
    # Start and end
    _d1="$(date -d "$_F + $(( 7*( - _V) )) days" "+%F")"
    _d2="$(date -d "$_F + $(( 7*( - _V) + 6 )) days" "+%F")"
    [[ "$_d1" < "-01-01" ]] && _d1="-01-01"
    [[ "$_d2" > "-12-31" ]] && _d2="-12-31"
    [[ "$_d1" > "-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.

注意:还有其他定义周数的方法。尽管如此,方法保持不变。

回答by das_j

If anybody needs it: I found an even shorter way (not sure if easier):

如果有人需要它:我找到了一种更短的方法(不确定是否更容易):

function weekof() {
        local year=
        local week=`echo  | sed 's/^0*//'` # Fixes random bug
        local dateFormat="+%a %b %d %Y"
        # Offset is the day of week, so we can calculate back to monday
        local offset="`date -d "$year/01/01 +$((week - 1)) week" "+%u"`"
        echo -n "`date -d "$year/01/01 +$((week - 1)) week +$((1 - $offset)) day" "$dateFormat"`" # Monday
        echo -n " - "
        echo "`date -d "$year/01/01 +$((week - 1)) week +$((7 - $offset)) day" "$dateFormat"`" # Sunday    }

I take the first day of the year and go n weeks forward to be somewhere in the right week. Then I take my weekday and go back/forward to reach monday and sunday.

我从一年中的第一天开始,然后向前走 n 周,以便在正确的一周内找到某个地方。然后我利用我的工作日来回/向前到达周一和周日。

回答by yupeng0921

If the start of a week is Sunday, you can use this version of weekof:

如果一周的开始是星期日,则可以使用此版本的 weekof:

function weekof()
{
    local week= year=
    local week_num_of_Jan_1 week_day_of_Jan_1
    local first_Sun
    local date_fmt="+%Y-%m-%d"
    local sun sat

    week_num_of_Jan_1=$(date -d $year-01-01 +%U)
    week_day_of_Jan_1=$(date -d $year-01-01 +%u)

    if ((week_num_of_Jan_1)); then
        first_Sun=$year-01-01
    else
        first_Sun=$year-01-$((01 + (7 - week_day_of_Jan_1) ))
    fi

    sun=$(date -d "$first_Sun +$((week - 1)) week" "$date_fmt")
    sat=$(date -d "$first_Sun +$((week - 1)) week + 6 day" "$date_fmt")
    echo "$sun $sat"
}