我偶尔会使用该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
支持更多日期格式(包括您所指的日期格式)的实现,您可以使用date
from 的实现(它也可以使用GNU 之类的ast-open
输入日期)。-d
date
如果作为 的一部分构建(但很少有这种情况),那么它也可以是date
ksh93 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
在bash
shell(或任何其他 shell)中,您始终可以执行以下操作:
$ ksh93 -c '"${@:0}"' printf '%(%F)T\n' 2021-W50-3
2021-12-15
但请注意,根据系统的不同,ksh93 可能被称为ksh
, ksh2020
(或者甚至sh
像在 Solaris 11+ 上一样;尽管它也被称为ksh
There),或者根本不被称为,因为 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
$