`date` 命令没有 ISO-8601 周格式输入选项?

`date` 命令没有 ISO-8601 周格式输入选项?

我偶尔会使用该date命令根据 ISO-8601 周日期日历检查当前或未来日期的周数。为此,我只需使用:date +%V检查当前 ISO 周数并date -d "2021-12-25" +%V检查另一个日期(本例中为圣诞节)的 ISO 周数。

然而,似乎不可能反过来做到这一点。也就是说,给定“周数”格式的日期,获取“月-日期”格式的日期。例如,如果我运行date -d "2021-W50-3",它会生成一个错误,指出不支持该格式。为什么不是?有什么方法可以使用这种格式输入或存储日期吗?

答案1

GNUdate具有非标准-d选项,仅支持一组有限的日期时间格式,记录在info date 'Date input formats'(和在线这里)。

对于date支持更多日期格式(包括您所指的日期格式)的实现,您可以使用datefrom 的实现(它也可以使用GNU 之类的ast-open输入日期)。-ddate

如果作为 的一部分构建(但很少有这种情况),那么它也可以是dateksh93 shell 的内置函数ast-open,或者代替date,您可以使用它的printf内置函数(始终包含在内)及其%T说明符(bash尽管没有时间解析部分但已复制) :

$ builtin date
$ date -d '2021-W50-3' +%F
2021-12-15
$ printf '%(%F)T\n' 2021-W50-3
2021-12-15

bashshell(或任何其他 shell)中,您始终可以执行以下操作:

$ ksh93 -c '"${@:0}"' printf '%(%F)T\n' 2021-W50-3
2021-12-15

但请注意,根据系统的不同,ksh93 可能被称为ksh, ksh2020(或者甚至sh像在 Solaris 11+ 上一样;尽管它也被称为kshThere),或者根本不被称为,因为 ksh93(如 bash 或 zsh)默认情况下不会安装在所有系统上系统。

请注意,虽然标准strftime()可以根据规范生成该标准格式的日期%G-%V-%u,相应的标准函数解析时间戳(strptime())不支持%G也不%V(也不支持标准UNIXgetdate())。

GNUstrptime()目前已记录为理解它们(作为标准的扩展)但忽略它们(请参阅info libc strptime)。自由BSDstrptime()被记录为支持相同的指令,strftime()但在我对 FreeBSD 12.2 的测试中(使用 的zsh内置strftime -r),它似乎在那里不起作用。

不过POSIX、GNU 和 freebsdstrptime()确实支持%W

  • zsh:

    $ strftime -rs t %Y-W%W-%u 2021-W50-3 && strftime %F $t
    2021-12-15
    
  • busybox:

    $ busybox date -D %Y-W%W-%u -d 2021-W50-3 +%F
    2021-12-15
    

%Y-%W与虽然不一样%G-%V,但在这种情况下恰好重合。%W一月一日为 00,除非是星期一,在这种情况下为 01。而%V(ISO 周数)是一年的第一周 (01) 或上一年的最后一周(52 或 53),具体取决于该周是否在上一年或今年有更多天数。

答案2

可以通过使用两次执行来获得精确的 ISO 周日期(包括翻转到上一年或明年)date:一次用于校准已知日期(我选择 01-June),一次通过天数进行调整ISO 周/日差异。这不受闰年的影响——这就是使用 ISO 周而不是月的全部意义。

此函数将 2021-W50-3 格式转换为 2021-12-15,并进行显示年份翻转的测试。

#! /bin/bash

isoDate () {

    declare -a dR   #.. Required date
    declare -a dC   #.. Calibration date.
    printf 1>&2 '\nAsked %s\n' "${1}"   #debug
    IFS='-' read -a dR <<<"${1}"
    IFS='-' read -a dC <<<"$( date -d "${dR[0]}-06-01" '+%G-W%V-%u' )"
    dR[1]=${dR[1]#W}; dR[1]=${dR[1]#0}
    dC[1]=${dC[1]#W}; dC[1]=${dC[1]#0}
    declare Adj=$(( 7 * (${dR[1]} - ${dC[1]}) + ${dR[2]} - ${dC[2]} ))
    date -d "${dR[0]}-06-01 + ${Adj} days" '+%Y-%m-%d'
}

    Ymd=$( isoDate '2021-W50-3' )
    printf 'Found %s\n' "${Ymd}"
    date -d "${Ymd}" '+Check %G-W%V-%u'

    Ymd=$( isoDate '2020-W01-1' )
    printf 'Found %s\n' "${Ymd}"
    date -d "${Ymd}" '+Check %G-W%V-%u'

    Ymd=$( isoDate '2011-W52-7' )
    printf 'Found %s\n' "${Ymd}"
    date -d "${Ymd}" '+Check %G-W%V-%u'

结果:

$ ./isoDate

Asked 2021-W50-3
Found 2021-12-15
Check 2021-W50-3

Asked 2020-W01-1
Found 2019-12-30
Check 2020-W01-1

Asked 2011-W52-7
Found 2012-01-01
Check 2011-W52-7
$ 

相关内容