【问题标题】:How to convert timestamps to dates in Bash?如何在 Bash 中将时间戳转换为日期?
【发布时间】:2011-01-23 04:42:53
【问题描述】:

我需要一个将 Unix 时间戳转换为日期的 shell 命令或脚本。输入可以来自第一个参数或标准输入,允许以下使用模式:

ts2date 1267619929

echo 1267619929 | ts2date

两个命令都应输出“Wed Mar 3 13:38:49 2010”。

【问题讨论】:

    标签: bash date unix-timestamp


    【解决方案1】:

    如果您希望一次格式化多个时间戳,我编写了一个名为 datefmt 的 C 实用程序,用于格式化文本流中的时间戳:

    假设我们有一些包含 unix 时间戳的日志:

    $ cat logs.txt
    
    EVENTS  1638499687   blahblah log1
    EVENTS  1638499717   blahblah log2
    

    我们可以将此日志通过管道传输到 datefmt 中,以将这些时间戳转换为人类可读的日期:

    $ <logs.txt datefmt
    
    EVENTS  2021-12-02 18:48   blahblah log1
    EVENTS  2021-12-02 18:48   blahblah log2
    

    当然你也可以自定义格式:

    $ <logs.txt datefmt "DATE:'%m-%d %R'"
    
    EVENTS  DATE:'12-02 18:48'   blahblah log1
    EVENTS  DATE:'12-02 18:48'   blahblah log2
    

    我已经在 NixOS 中打包了它,希望它很快会在其他发行版中推广,但现在你需要下载 tarball 并使用 make 构建它

    【讨论】:

      【解决方案2】:

      我使用这个跨平台的单线:

      date -d @1267619929 2>/dev/null || date -r 1267619929
      

      它应该可以在 macOS 和流行的 Linux 发行版的现代版本中运行。

      【讨论】:

        【解决方案3】:

        我必须在我的 bash 历史记录中内联转换时间戳才能对我有意义。

        也许以下来自对How do I replace a substring by the output of a shell command with sed, awk or such? 的回答可能对其他读者也很有趣。 原始 sed 内联代码的荣誉转到 @Gabriel。

        cat ~/.bash_history | sed "s/^#\([0-9]\+\)$/echo -n '#'; date -u --d @\1 '\+\%Y-\%m-\%d \%T'/e" | less
        

        【讨论】:

        • 你应该看看jb55.com/datefmt,我已经写了一个C 工具来做这件事,它应该更快。
        【解决方案4】:

        虽然不是纯 bash,但以下脚本将使用 perl 将字符串中长度为 13 的时间戳转换为本地时区中的等效日期

        timestamp_to_date.sh

        #!/usr/bin/env bash
        IT=$(cat /dev/stdin)
        re='(.*)([0-9]{13})(.*)'
        while [[ $IT =~ $re ]]; do
          TIMESTAMP=${BASH_REMATCH[2]}
          AS_DATE=$(echo "$TIMESTAMP" | perl -pe 's/([\d]{10})([\d]{3})/localtime $1/eg;')
          IT="${IT/$TIMESTAMP/$AS_DATE}"    
        done
        echo "$IT"
        

        输入

        {"timestamp":"1573121629939","level":"DEBUG","thread":"http-nio-15372-exec-3","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor"}
        

        输出

        $ cat input | timestamp_to_date.sh
        
        {"timestamp":"Thu Nov  7 06:13:49 2019","level":"DEBUG","thread":"http-nio-15372-exec-3","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor"}
        

        【讨论】:

          【解决方案5】:

          您可以像这样从时间戳中获取格式化日期

          date +'%Y-%m-%d %H:%M:%S' -d "@timestamp"
          

          【讨论】:

          • 其他方式:date -ud "@1585667718" +'%Y-%m-%d %H:%M:%S'
          【解决方案6】:

          在 OSX 或 BSD 中,有一个等效的 -r 标志,它显然需要一个 unix 时间戳。这是一个运行四次 date 的示例:第一个 date 一次,显示它是什么;一个用于将%s 转换为unix 时间戳,最后一个用于-r,将%s 提供的内容转换回字符串。

          $  date; date +%s; date -r `date +%s`
          Tue Oct 24 16:27:42 CDT 2017
          1508880462
          Tue Oct 24 16:27:42 CDT 2017
          

          至少,似乎可以在我的机器上运行。

          $ uname -a
          Darwin XXX-XXXXXXXX 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
          

          【讨论】:

          • 如果你已经有一个时间戳值并且你只需要找到等效的日期,在 OS X 中你可以在命令行输入这个:date -r 1509453417
          • 确实如此。如果你看我的回答,我实际上是在证明这一点。
          【解决方案7】:

          从 Bash 4.2 开始,您可以使用 printf%(datefmt)T 格式:

          $ printf '%(%c)T\n' 1267619929
          Wed 03 Mar 2010 01:38:49 PM CET
          

          这很好,因为它是一个内置的 shell。 datefmt 的格式是strftime(3) 接受的字符串(参见man 3 strftime)。这里%c 是:

          %c 当前的首选日期和时间表示 语言环境。


          现在,如果您想要一个接受参数的脚本,并且如果没有提供,则读取标准输入,您可以继续:

          #!/bin/bash
          
          if (($#)); then
              printf '%(%c)T\n' "$@"
          else
              while read -r line; do
                  printf '%(%c)T\n' "$line"
              done
          fi
          

          【讨论】:

            【解决方案8】:

            此版本类似于 chiborg 的 答案,但它消除了对外部 ttycat 的需要。它使用date,但也可以轻松使用gawk。您可以更改 shebang 并将双方括号替换为单个方括号,这也将在 sh 中运行。

            #!/bin/bash
            LANG=C
            if [[ -z "$1" ]]
            then
                if [[ -p /dev/stdin ]]    # input from a pipe
                then
                    read -r p
                else
                    echo "No timestamp given." >&2
                    exit
                fi
            else
                p=$1
            fi
            date -d "@$p" +%c
            

            【讨论】:

            • +1:非常完整的答案,我认为 date 比 gawk 快。
            • @Bruno,你怎么知道 date 比 gawk 快?
            • @Bruno, @ghostdog74:在我的系统上,gawk 在一个仅由gawk 'BEGIN { print strftime("%c", 1256571985); }'date -d '@1256571985' +%c 组成的定时for 循环中(非常粗略地)比date 快15%输出重定向到/dev/null
            • date 对我来说比 gawk (mac osx 10.9.2, date 8.23, gawk 4.1.1) 快一点 (5%),但 (g)awk 的真正优势是接受管道许多时间戳的列(请参阅下面的答案),这使得脚本例如1000 个时间戳的速度是 250 倍。
            • 请注意,我的答案符合问题中所述的 OP 要求,但现在接受的答案不符合。
            【解决方案9】:
            date -r <number>
            

            在 Mac OS X 上适合我。

            【讨论】:

            • 是的,但它不能处理几分之一秒。
            • 这很令人困惑,因为它在大多数 linux 系统上都不是这样工作的,因为:freddy@hades ~ % date --help | grep -- -r -r, --reference=FILE 显示FILE的最后修改时间
            • 虽然这个答案的 cmets 是真的,但这些不是 rafa 的错,他们不会削弱他的答案。
            【解决方案10】:

            一些例子:

            $日期 2016 年 3 月 22 日星期二 16:47:06 CST $ date -d "2016 年 3 月 22 日星期二 16:47:06 CST" "+%s" 1458636426 $ 日期 +%s 1458636453 $日期-d@1458636426 2016 年 3 月 22 日星期二 16:47:06 CST $ 日期 --date='@1458636426' 2016 年 3 月 22 日星期二 16:47:06 CST

            【讨论】:

              【解决方案11】:

              你可以使用 GNU 日期,例如,

              $ sec=1267619929
              $ date -d "UTC 1970-01-01 $sec secs"
              

              $ date -ud @1267619929
              

              【讨论】:

                【解决方案12】:

                在此答案中,我复制了 Dennis Williamson 的答案并对其稍作修改,以便在将包含许多时间戳的列传递到脚本时大幅提高速度。例如,在我的机器上使用 xargs -n1 将 1000 个时间戳传送到原始脚本需要 6.929 秒,而使用此修改版本需要 0.027 秒:

                #!/bin/bash
                LANG=C
                if [[ -z "$1" ]]
                then
                    if [[ -p /dev/stdin ]]    # input from a pipe
                    then
                        cat - | gawk '{ print strftime("%c", $1); }'
                    else
                        echo "No timestamp given." >&2
                        exit
                    fi
                else
                    date -d @$1 +%c
                fi
                

                【讨论】:

                  【解决方案13】:

                  我在转换日志文件或监控它们时使用它:

                  tail -f <log file> | gawk \
                  '{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }'
                  

                  【讨论】:

                  • 正是我想要的,可以缩写为awk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
                  【解决方案14】:

                  我自己编写了一个脚本:

                  #!/bin/bash
                  LANG=C
                  if [ -z "$1" ]; then
                      if [  "$(tty)" = "not a tty" ]; then
                              p=`cat`;
                      else
                              echo "No timestamp given."
                              exit
                      fi
                  else
                      p=$1
                  fi
                  echo $p | gawk '{ print strftime("%c", $0); }'
                  

                  【讨论】:

                    【解决方案15】:

                    在更高版本的常见 Linux 发行版上,您可以使用:

                    date -d @1267619929
                    

                    【讨论】:

                    • 单线:date -d @$(date -u +%s)
                    • @ 是干什么用的?我在 GNU 手册页中根本没有看到。
                    • @mehaase - 手册页指出日期字符串太复杂,无法在手册页中记录,因此在 info: info '(coreutils) date invocation'中进行了描述>
                    • brew install coreutils; gdate -d @1267619929
                    【解决方案16】:

                    您可以使用这个简单的 awk 脚本:

                    #!/bin/gawk -f   
                    { print strftime("%c", $0); }
                    

                    示例用法:

                    $ echo '1098181096' | ./a.awk 
                    Tue 19 Oct 2004 03:18:16 AM PDT
                    $
                    

                    【讨论】:

                    • 这不适合第一次使用 - 有时我不想回显 TS 并改用参数。
                    • 在一些旧的busybox版本上,date -s @ 不起作用,awk 仍然起作用!没有标准输入的示例也会有所帮助。
                    【解决方案17】:

                    在 PHP 中

                    $unix_time = 1256571985;
                    
                    echo date("Y-m-d H:i:s",$unix_time)
                    

                    【讨论】:

                    • 很好,但我只是想使用 bash。
                    猜你喜欢
                    • 2014-10-26
                    • 1970-01-01
                    • 2019-08-24
                    • 2012-04-10
                    • 2016-11-26
                    • 2019-04-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多