AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

    • 主页
    • 系统&网络
    • Ubuntu
    • Unix
    • DBA
    • Computer
    • Coding
    • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 497639
Accepted
confetti
confetti
Asked: 2019-01-31 00:30:29 +0800 CST2019-01-31 00:30:29 +0800 CST 2019-01-31 00:30:29 +0800 CST

使用日期和 bash 减去时间

  • 772

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

因此,如果这确实是一个时区问题,那么这种疯狂从何而来?

date gnu
  • 5 5 个回答
  • 31699 Views

5 个回答

  • Voted
  1. Best Answer
    Olorin
    2019-01-31T00:51:30+08:002019-01-31T00:51:30+08:00

    最后一个示例应该为您澄清了一些事情:timezones。

    $ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
    2019-01-19_03:00:00
    $ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S 
    2019-01-19_08:30:00
    

    由于输出明显因时区而异,我怀疑在没有指定时区的情况下对时间字符串采用了一些不明显的默认值。测试几个值,它似乎是UTC-05:00,但我不确定那是什么。

    $ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
    2019-01-19_08:00:00UTC
    $ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
    2019-01-19_03:00:00UTC
    $ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z           
    2019-01-19_05:00:00UTC
    

    它仅在执行日期算术时使用。


    这里的问题似乎- 2 hours不是算术,而是时区说明符:

    # TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
    date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
    date: parsed relative part: +1 hour(s)
    date: input timezone: parsed date/time string (-02)
    date: using specified time as starting value: '05:00:00'
    date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
    date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
    date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
    date:     new time = 1547884800 epoch-seconds
    date: timezone: TZ="UTC" environment value
    date: final: 1547884800.000000000 (epoch-seconds)
    date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
    date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
    2019-01-19_08:00:00UTC
    

    因此,不仅没有进行算术运算,而且时间似乎有 1 小时的夏令时调整,导致我们的时间有点荒谬。

    这也适用于添加:

    # TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
    date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
    date: parsed relative part: +1 hour(s)
    date: input timezone: parsed date/time string (+05:30)
    date: using specified time as starting value: '05:00:00'
    date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
    date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
    date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
    date:     new time = 1547857800 epoch-seconds
    date: timezone: TZ="UTC" environment value
    date: final: 1547857800.000000000 (epoch-seconds)
    date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
    date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
    2019-01-19_00:30:00UTC
    

    再调试一下,解析似乎是:(2019-01-19T05:00:00 - 2作为-2时区)和hours(= 1 小时),隐含添加。更容易查看是否使用分钟来代替:

    # TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
    date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
    date: parsed relative part: +1 minutes
    date: input timezone: parsed date/time string (-02)
    date: using specified time as starting value: '05:00:00'
    date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
    date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
    date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
    date:     new time = 1547881260 epoch-seconds
    date: timezone: TZ="UTC" environment value
    date: final: 1547881260.000000000 (epoch-seconds)
    date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
    date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
    2019-01-19_07:01:00UTC
    

    所以,好吧,日期算术正在完成,而不是我们要求的那个。¯\(ツ)/¯

    • 28
  2. pLumo
    2019-01-31T00:47:41+08:002019-01-31T00:47:41+08:00

    当您首先将输入日期转换为 ISO 8601 时,它可以正常工作:

    $ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
    So 9. Dez 18:39:55 CET 2018
    
    • 8
  3. mr.spuratic
    2019-02-01T04:26:44+08:002019-02-01T04:26:44+08:00

    GNUdate确实支持简单的日期算术,尽管@sudodus 的答案中显示的纪元时间计算有时更清晰(并且更便携)。

    当时间戳中没有指定时区时,使用 +/- 会在解析其他任何内容之前触发下一次匹配时区的尝试。

    这是一种方法,使用“ago”而不是“-”:

    $ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
    Sun Dec  9 18:39:55 GMT 2018
    

    或者

    $ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
    Sun Dec  9 18:39:55 GMT 2018
    

    (虽然您不能任意使用“Z”,但它在我的区域中有效,但这使其成为 UTC/GMT 区域时间戳 - 使用您自己的区域,或者通过附加${TZ:-$(date +%z)}到时间戳来使用 %z/%Z。)

    添加这些表格的额外时间条款调整时间:

    • “5 小时前”减去 5 小时
    • “4 小时”添加(隐式)4 小时
    • “3 小时后”添加(显式)3 小时(旧版本不支持)

    可以使用任何顺序的许多复杂调整(尽管诸如“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 节。

    • 6
  4. nxnev
    2019-01-31T01:47:11+08:002019-01-31T01:47:11+08:00

    TLDR:这不是错误。您刚刚发现了date. 使用 执行时间算术时date,请使用与时区无关的格式(如 Unix 时间)或仔细阅读文档以了解如何正确使用此命令。


    GNUdate使用您的系统设置(TZ环境变量,或者,如果未设置,系统默认值)来确定使用-d/--date选项提供的日期和+format参数报告的日期的时区。该--date选项还允许您为其自己的选项参数覆盖时区,但它不会覆盖+format. 恕我直言,这就是混乱的根源。

    考虑到我的时区是 UTC-6,比较以下命令:

    $ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1970-01-01 00:00:00 -06:00
    Unix: 21600
    
    $ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1969-12-31 18:00:00 -06:00
    Unix: 0
    
    $ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1970-01-01 00:00:00 +00:00
    Unix: 0
    

    第一个将我的时区用于-d和+format。第二个使用 UTC-d但我的时区为+format. 第三个对两者都使用 UTC。

    现在,比较以下简单操作:

    $ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1970-01-01 18:00:00 -06:00
    Unix: 86400
    
    $ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1970-01-02 00:00:00 +00:00
    Unix: 86400
    

    即使 Unix 时间告诉我同样的事情,“正常”时间也会因为我自己的时区而有所不同。

    如果我想做同样的操作但只使用我的时区:

    $ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
    Normal: 1970-01-02 00:00:00 -06:00
    Unix: 108000
    
    • 5
  5. sudodus
    2019-01-31T05:53:43+08:002019-01-31T05:53:43+08:00

    这个解决方案很容易理解,但是稍微复杂一些,所以我将它显示为一个 shellscript。

    • 转换为“自 1970-01-01 00:00:00 UTC 以来的秒数”
    • 添加或减去差异
    • date使用最终命令行转换回人类可读的格式

    脚本:

    #!/bin/bash
    
    startdate="2018-12-10 00:00:00"
    
    ddif="0"          # days
    diff="-5:-20:-5"  # hours:minutes:seconds
    
    #-----------------------------------------------------------------------------
    
    ss1970in=$(date -d "$startdate" "+%s")  # seconds since 1970-01-01 00:00:00 UTC
    printf "%11s\n" "$ss1970in"
    
    h=${diff%%:*}
    m=${diff#*:}
    m=${m%:*}
    s=${diff##*:}
    difs=$(( (((ddif*24+h)*60)+m)*60+s ))
    printf "%11s\n" "$difs"
    
    ss1970ut=$((ss1970in + difs))  # add/subtract the time difference
    printf "%11s\n" "$ss1970ut"
    
    date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"
    
    • 1

相关问题

  • 如何使用 awk 删除列的一部分

  • 日期可以为 GMT 时区格式化当前时间吗?[复制]

  • 从文件中获取所有访问日期

  • bsdtar:如何避免覆盖现有文件信息?

  • gpg —list-keys 命令在将私钥导入全新安装后输出 uid [未知]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助
subwaysurfers
my femboy roommate

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve