我正在使用 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...
或者你可以使用perl
和Date::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 日期时间规范。