如何使用 BSD 的 date 命令获取 Unix 时间晚上 11 点和今晚 CST 晚上 11 点?

如何使用 BSD 的 date 命令获取 Unix 时间晚上 11 点和今晚 CST 晚上 11 点?

BSDdate -j -f似乎混合了当天当前时间的秒和分钟,同时仍然接受'%H%p'时间格式。我想做的就是将输入格式转换为正确的 UNIX 时间。此外,将%Z的值更改为系统时区以外的任何值都会出错。

❯ /bin/date -j -f '%H%p %Z' '11PM PDT' '+%s'; gdate -d '11PM' '+%s'
1653546964
1653544800
# Run again
❯ /bin/date -j -f '%H%p %Z' '11PM PDT' '+%s'; gdate -d '11PM' '+%s'
1653546965
1653544800

我想要什么?

  1. 不让我运行命令的时间的分钟/秒影响结果
  2. 让任何时区都适用%Z

如果日期方面有不必要的困难,我可以使用另一种符合 POSIX 的方式来完成此任务。

我正在使用 zsh,因此 zsh 解决方案也可以工作(如果有)。 strftime -r 看起来很有希望,但会产生负值。

答案1

您应该能够指定 :%M:%S 作为格式字符串的一部分,并指定 :00:00 作为时间

% /bin/date -j -f '%H:%M:%S%p %Z' '11:00:00PM GMT'
Wed May 25 19:00:00 EDT 2022

FreeBSD 命令的联机帮助页date显示使用 strptime(3) 完成解析该手册页说

 The %Z format specifier only accepts time zone abbreviations of the local
 time zone, or the value "GMT".  This limitation is because of ambiguity
 due to of the over loading of time zone abbreviations.  One such example
 is EST which is both Eastern Standard Time and Eastern Australia Summer
 Time.

所以date不能用来做这样的时区转换。

相反,您可以计算 GMT 偏移量并将其与 一起使用%z

例如

% /bin/date -j -f '%H:%M:%S%p %z' "11:00:00PM $(TZ=America/Los_Angeles date +%z)"
Thu May 26 02:00:00 EDT 2022

而且,正确的是,洛杉矶今晚 11 点(当前太平洋夏令时间)是纽约第二天凌晨 2 点。

答案2

由于您使用 进行标记zsh,请注意,它zsh具有内置时间解析和格式化功能,模块strftime中内置有内置时间解析和格式化功能zsh/datetime,这是标准的原始接口strftime()(+ localtime()) 和strptime() (+ mktime()) 标准函数(具有支持亚秒的扩展)。

所以在这里,你可以移植(在 BSD、GNU 或任何既没有 GNU 也没有 BSD 的系统上date):

zmodload zsh/datetime
TZ=America/Los_Angeles strftime -s today %Y-%m-%d
TZ=America/Los_Angeles strftime -r "%Y-%m-%d %I%p" "$today 11PM"

今天 2022-05-26 我的时间,但仍然 2022-05-25 洛杉矶时间给出 1653544800 (2022-05-26T06:00:00+00:00)。

请注意,这%H是一天中的 24 小时格式的小时。%I如果使用 12 小时格式,则需要%p.

您还需要指定日期,否则默认为 1900-01-01(和返回的tm_year其他日期相关字段中的 0 值),因此您的数字为负数。struct tmstrptime()

还要注意,它%p依赖于语言环境。您可能需要将语言环境设置为,以C确保PM始终可以识别。

假设 CST 您指的是美国中部标准(或夏季?)时间(而不是中国时间或澳大利亚中部时间),您可以替换America/Los_Angeles为例如America/Regina或与您相关的任何区域,或者TZ=CST6硬编码标记CST为始终的时区UTC 以西 6 小时,无论一年中的什么时间(冬季/夏季)都使用该时间。

相关内容