SE 网络上的所有其他问题都处理假设日期为now
( Q ) 或仅指定日期 ( Q ) 的情况。
我想要做的是提供一个日期和时间,然后从中减去一个时间。
这是我首先尝试的:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
这导致2018-12-10 06:39:55
- 它增加了 7 小时。然后减去 20:05 分钟。
在阅读了man
和info
页面之后date
,我想我已经修复了它:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
但是,同样的结果。它甚至从哪里得到 7 小时?
我也尝试了其他日期,因为我想也许那天我们有 7200 闰秒,谁知道哈哈。但同样的结果。
再举几个例子:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
但在这里它变得有趣。如果我省略输入时间,它可以正常工作:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
我错过了什么?
更新:我在Z
最后添加了一个,它改变了行为:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
不过我还是很困惑。关于日期的GNU 信息页面中没有太多关于此的内容。
我猜这是一个时区问题,但在ISO 8601上引用了 The Calendar Wiki:
如果没有给出带有时间表示的 UTC 关系信息,则假定时间为本地时间。
这就是我想要的。我的当地时间也设置正确。在我提供日期时间并想从中减去一些东西的简单情况下,我不确定为什么日期会与时区混淆。它不应该先从日期字符串中减去小时数吗?即使它确实先将其转换为日期然后进行减法,如果我省略任何减法,我就会得到我想要的:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
因此,如果这确实是一个时区问题,那么这种疯狂从何而来?
最后一个示例应该为您澄清了一些事情:timezones。
由于输出明显因时区而异,我怀疑在没有指定时区的情况下对时间字符串采用了一些不明显的默认值。测试几个值,它似乎是UTC-05:00,但我不确定那是什么。
它仅在执行日期算术时使用。
这里的问题似乎
- 2 hours
不是算术,而是时区说明符:因此,不仅没有进行算术运算,而且时间似乎有 1 小时的
夏令时调整,导致我们的时间有点荒谬。这也适用于添加:
再调试一下,解析似乎是:(
2019-01-19T05:00:00 - 2
作为-2
时区)和hours
(= 1 小时),隐含添加。更容易查看是否使用分钟来代替:所以,好吧,日期算术正在完成,而不是我们要求的那个。¯\(ツ)/¯
当您首先将输入日期转换为 ISO 8601 时,它可以正常工作:
GNU
date
确实支持简单的日期算术,尽管@sudodus 的答案中显示的纪元时间计算有时更清晰(并且更便携)。当时间戳中没有指定时区时,使用 +/- 会在解析其他任何内容之前触发下一次匹配时区的尝试。
这是一种方法,使用“ago”而不是“-”:
或者
(虽然您不能任意使用“Z”,但它在我的区域中有效,但这使其成为 UTC/GMT 区域时间戳 - 使用您自己的区域,或者通过附加
${TZ:-$(date +%z)}
到时间戳来使用 %z/%Z。)添加这些表格的额外时间条款调整时间:
可以使用任何顺序的许多复杂调整(尽管诸如“14 周后上周一”之类的相对和可变术语正在自找麻烦 ;-)
(这里还有一个小记号,
date
总是会给出一个有效的日期,所以date -d "2019-01-31 1 month"
给出 2019-03-03,就像“下个月”一样)鉴于支持的时间和日期格式种类繁多,时区解析必然是草率的:它可以是单个或多个字母后缀、小时或小时:分钟偏移量、名称“America/Denver”(甚至是文件名在
TZ
变量的情况下)。您的
2018-12-10T00:00:00
版本不起作用,因为“T”只是一个分隔符,而不是时区,在末尾添加“Z”也可以按预期工作(取决于所选区域的正确性)。请参阅: https ://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html ,特别是第 7.7 节。
TLDR:这不是错误。您刚刚发现了
date
. 使用 执行时间算术时date
,请使用与时区无关的格式(如 Unix 时间)或仔细阅读文档以了解如何正确使用此命令。GNU
date
使用您的系统设置(TZ
环境变量,或者,如果未设置,系统默认值)来确定使用-d
/--date
选项提供的日期和+format
参数报告的日期的时区。该--date
选项还允许您为其自己的选项参数覆盖时区,但它不会覆盖+format
. 恕我直言,这就是混乱的根源。考虑到我的时区是 UTC-6,比较以下命令:
第一个将我的时区用于
-d
和+format
。第二个使用 UTC-d
但我的时区为+format
. 第三个对两者都使用 UTC。现在,比较以下简单操作:
即使 Unix 时间告诉我同样的事情,“正常”时间也会因为我自己的时区而有所不同。
如果我想做同样的操作但只使用我的时区:
这个解决方案很容易理解,但是稍微复杂一些,所以我将它显示为一个 shellscript。
date
使用最终命令行转换回人类可读的格式脚本: