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

ts2date 1267619929

and

echo 1267619929 | ts2date

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


当前回答

在这个答案中,我复制了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

其他回答

在这个答案中,我复制了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

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

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

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

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


现在,如果你想要一个接受参数的脚本,如果没有提供参数,则读取stdin,你可以继续执行:

#!/bin/bash

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

我喜欢以前的特殊情况下的解决方案:printf '%(%c)T\n' $timestamp(如果你有Bash>=4.2), date -d @$timestamp(如果你有GNU Coreutils >= 5.3.0), date -r $timestamp(如果你是BSD/MacOS),但我需要一些更可移植的东西,我选择了jq,我到处都有JSON的帮助:

jq 'todate' <<< $timestamp

可以在函数中使用,以获得所需的效果:

ts2date() { [[ -n "$1" ]] && { jq 'todate' <<< $1 ; true;} || jq 'todate' ; }

在GNU Coreutils >= 5.3.0的系统上,例如Linux,您可以使用:

date -d @1267619929

我使用这个跨平台的一行代码:

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

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