BSD 下解析任意自然语言日期

BSD 下解析任意自然语言日期

我正在使用 GNU date 命令来解析任意自然语言日期 - 例如,要检测某个纪元时间戳是否来自上周,我可以这样做:

if [ "$timestamp" -lt "$(date +"%s" -d "last sunday")" ]; then ...

现在,当我尝试将脚本移植到 FreeBSD 时,如何实现相同的功能?man date没有表现出任何承诺,除非我错过了一些明显的事情。

答案1

有许多FreeBSD 上的命令使用与 GNU 相同的 APIdate来输入用户的自然语言日期。我刚刚发现了一个可以被欺骗将该日期转换为 Unix 纪元时间的方法:

/usr/sbin/fifolog_reader -B 'last sunday' /dev/null 2>&1 |
  sed 's/^From[[:blank:]]*\([0-9]*\).*/\1/p'

(请注意,至少在我尝试过的 FreeBSD 9.1-RELEASE-p2 上,只有当您位于 UTC 时区并且它识别的日期规范不一定与 GNU 日期识别的日期规范相同时,它似乎才能可靠地工作) 。

请注意,某些 shell 内置了该功能。

ksh93:

if (( timestamp < $(printf '%(%s)T' 'last sunday') )); then

zsh:

autoload calendar_scandate
calendar_scandate 'last sun'
if (( timestamp < REPLY)); then...

或者你可以使用perlDate::Manip如果安装:

last_sun=$(perl -MDate::Manip -e 'print UnixDate("last sunday","%s")')
if [ "$timestamp" -lt "$last_sun" ]; then...

或者:

if perl -MDate::Manip -e 'exit 1 unless $ARGV[0] < UnixDate("last sunday","%s")
    ' "$timestamp"; then....

如果目的是检查文件时间戳,请注意 FreeBSDfind支持:

find file -prune -newermt 'last sunday'

在这种情况下,如果您想要本周开始的时间(从周日开始的周),您可以执行以下操作:

week_start=$(($(date '+%s - 86400*%w - 3600*%H - 60*%M - %S')))

这应该适用于 GNU 和 FreeBSD(或任何%s受支持的系统)。

在采用夏令时的时区中,夏令时切换前后会延迟一个小时。

答案2

确保兼容性的最佳方法可能是在 FreeBSD 系统上安装 GNU date。

您可以coreutils从 FreeBSD ports 集合中安装该软件包。这会将 GNU date 命令放入/usr/local/bin/gdate.

答案3

虽然它可能不适用于可以用自然语言轻松表达的所有操作,但 FreeBSDdate具有-v允许为单独的日期字段设置任意值和相对值的运算符,并且可以根据需要重复此操作以产生大多数效果。

例如,要获取“上周日”,可以应用“将所有时间字段清零”,然后应用“将工作日清零”,如下所示:

date -v0S -v0M -v0H -v0w

因此,bash 中的“给我自上周日开始以来的秒数,无论您是在 Linux 还是 BSD 上运行”,将如下所示:

last_sunday_start() {
    if [ "$(uname)" = "Linux" ]; then
        date +"%s" -d "next sunday -1 week"
    else
        date -v0S -v0M -v0H -v0w +"%s"
    fi
}

date请注意,如果您想获取“周日 00:00:00 发生的最后时间”,问题中的GNU示例是不正确的 - 当在周日期间调用时,它将返回上周日的开始时间。上面的代码还修复了 GNU 日期时间规范。

相关内容