获取毫秒级时间的Linux命令

434
如何在Bash shell脚本中获取毫秒级的时间?

22
date +%s.%N会给您纳秒级的时间戳,您可以使用它吗? - Wrikken
1
@Wrikken 这个不太具有可移植性。 - Camilo Martin
25
通常我使用这个命令在Unix Bash脚本中获取包含毫秒级独特时间的完整日期,以创建临时文件名。如果您的系统无法处理毫秒级别,可以使用3到6和9分别转换为微秒或纳秒。 - Nitin Mahesh
2
Try date -Ins - SO Stinks
1
@CamiloMartin 为什么这个不可移植? - bmitc
17个回答

531
  • date +"%T.%N" returns the current time with nanoseconds.

    06:46:41.431857000
    
  • date +"%T.%6N" returns the current time with nanoseconds rounded to the first 6 digits, which is microseconds.

    06:47:07.183172
    
  • date +"%T.%3N" returns the current time with nanoseconds rounded to the first 3 digits, which is milliseconds.

    06:47:42.773
    
一般来说,date命令的格式中的每个字段都可以指定一个可选的字段宽度。

55
%xN:对于字段宽度来说真不错! - fduff
4
日期加时间格式为:"年份-月份-日期.小时:分钟:秒.毫秒",对应的命令为:date +"%Y-%m-%d.%H:%M:%S.%3N"。 - Nitin Mahesh
7
我猜这个答案比被标记为正确的那个更好。 - kcondezo

457

date +%s%N 返回当前秒数和纳秒数的总和。

因此,echo $(($(date +%s%N)/1000000)) 是你所需要的。

示例:

$ echo $(($(date +%s%N)/1000000))
1535546718115

date +%s 返回自计算机元年以来经过的秒数,如果这个信息对你有用的话。


114
无法在Mac OS上运行,因为date不支持%N - yegor256
41
该问题要求提供Linux命令。@alper的答案对于使用GNU coreutils的date命令有效。将您的OSX转换为GNU:在Mac OS X上安装和使用GNU命令行工具 - caligari
96
根据@michael-defort的答案,"date +%s%3N"更快。 - caligari
19
在苹果电脑上,您需要使用MacPorts或Homebrew安装coreutils软件包中的GNU版日期命令,然后使用gdate命令。请参考这个问题:https://dev59.com/j2kw5IYBdhLWcg3wkLX2 - Pierz
2
虽然date +%s%3N似乎更简单或更好,但在一些其他偏移量计算中使用它会导致时间戳减少1毫秒!但是,这个解决方案在偏移量计算中运作得很完美。 - Arsinux
显示剩余2条评论

128

Nano 是 10−9,而 milli 是 10−3。因此,我们可以使用纳秒的前三个字符来获取毫秒:

date +%s%3N

来自man date

%N 纳秒 (000000000..999999999)

%s 自1970年01月01日00时00分00秒UTC以来的秒数

来源:Server Fault的如何在Bash中获取当前Unix时间的毫秒数?


1
我感到非常自豪,@Peter Mortensen 在我的一篇文章上进行了出色的活跃阅读 :) 谢谢!! - fedorqui

74
在 OS X 上,date 命令不支持 %N 标志,建议使用Homebrew 安装 coreutils。这将使您可以使用名为 gdate 的命令,其行为与 Linux 系统上的 date 命令相同。
brew install coreutils

为了获得更“本地”的体验,您可以将以下内容添加到您的 .bash_aliases 文件中:

对于更好的理解,请查看原文。

alias date='gdate'

然后执行

$ date +%s%N

29
这是一个适用于Linux的便携式技巧,用于获取毫秒级时间。
#!/bin/sh
read up rest </proc/uptime; t1="${up%.*}${up#*.}"
sleep 3    # your command
read up rest </proc/uptime; t2="${up%.*}${up#*.}"

millisec=$(( 10*(t2-t1) ))
echo $millisec

输出结果为:
3010

这是一个非常便宜的操作,它与shell内部和procfs一起工作。

5
目前只有一个可以在Xeon Phi BusyBox v1.27.0 (2017-09-27 13:20:28 EDT) MicroOS上运行的程序,我很愿意点赞三次! - Cadoiz
2
我正在使用BusyBox 1.27.1。这也是唯一可行的解决方案。 - Jim Fell
1
我不知道为什么我没早点找到这个。这应该是被接受和完美的答案。我长期以来一直相信在一个posix shell中没有办法获得亚秒级准确时间(不涉及慢解释器或依赖带有%N支持的日期命令)。 - undefined

22
纯bash解决方案
自从bash 5.0(于2019年1月7日发布)起,您可以使用内置变量EPOCHREALTIME,它包含自纪元以来的秒数,包括小数点后的微秒(μs)精度(echo $EPOCHREALTIME在英语中打印出类似于1547624774.371210的内容,或者在德语、法语等其他语言中打印出1547624774,371210)。通过去除小数分隔符和最后三位,我们可以得到毫秒:
要么使用
(( t = ${EPOCHREALTIME/[^0-9]/} / 1000 ))

或者

t=${EPOCHREALTIME/[^0-9]/} # remove the decimal separator (s → µs)
t=${t%???}                 # remove the last three digits (µs → ms)

无论如何,t将会是类似于1547624774371的东西。

请注意,小数点分隔符是本地化的,所以在我的系统上,使用法语,我得到的结果是 1695071065,749507。您可以通过设置 LC_ALL=C 来强制使用句点作为小数点分隔符。 - undefined
1
@wjandrea 谢谢你的提示。非常好的观点!我发现在这里使用LC_ALL有些复杂,因为我们要么必须在子shell中使用它(这会使设置t变得复杂),要么手动恢复它。这两种方法都不理想。但是我找到了一个简短的通用解决方案,并更新了答案。 - undefined

14
其他答案在大多数情况下可能已经足够了,但是我认为我应该补充一下,因为我在BusyBox系统上遇到了一个问题。
所讨论的系统不支持%N格式选项,并且没有Python或Perl解释器。
经过长时间的思考,我们(感谢Dave!)想出了这个解决方案:
adjtimex | awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }'

它从 adjtimex 的输出中提取秒和微秒(通常用于设置系统时钟选项),并将它们打印在一起,没有换行符。请注意,微秒字段必须预先用零填充,但这不会影响秒字段,因为它本来就比六位数长。从中转换微秒到毫秒应该很容易。
如果您需要一个尾随的新行(可能因为看起来更好),那么请尝试
adjtimex | awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }' && printf "\n"

请注意,这需要adjtimexawk可用。如果没有,您可以使用BusyBox在本地指向它们:
ln -s /bin/busybox ./adjtimex
ln -s /bin/busybox ./awk

然后调用上述内容如下:
./adjtimex | ./awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }'

或者您可以将它们放入您的PATH中。

编辑:

上述方法在我的BusyBox设备上有效。在Ubuntu上,我尝试了同样的方法,并意识到adjtimex有不同的版本。在Ubuntu上,这个命令可以输出带有小数点微秒的时间(包括一个换行符)。

sudo apt-get install adjtimex
adjtimex -p | awk '/raw time:/ { print $6 }'

虽然在Ubuntu上也可以这样做,但我会使用date +%s%N


1
哇,太棒了!确实你的命令有效,但我不知道为什么。我在哪里可以找到 awk 命令的文档?你是怎么想出构建字符串来从 adjtimex 输出中提取所需信息的? - Satria
1
超棒的BusyBox解决方案。 - Codebling
1
如果有可能自己编译Busybox,启用“CONFIG_FEATURE_DATE_NANO”将是另一种方法。 - Bl00dh0und

11

date 命令在 OS X 上不提供毫秒级别的时间,因此使用来自 Python 的别名。

millis(){  python -c "import time; print(int(time.time()*1000))"; }

或者

alias millis='python -c "import time; print(int(time.time()*1000))"'

编辑:按照@CharlesDuffy的评论。 分叉任何子进程都需要额外的时间。

$ time date +%s%N
1597103627N
date +%s%N  0.00s user 0.00s system 63% cpu 0.006 total

Python仍在改进其VM启动时间,但它并不像预编译代码(如date)那样快。

在我的计算机上,它需要大约30ms-60ms(即date所需的6ms的5倍至10倍)。

$ time python -c "import time; print(int(time.time()*1000))"
1597103899460
python -c "import time; print(int(time.time()*1000))"  0.03s user 0.01s system 83% cpu 0.053 total

我认为 awkpython 更轻量级,因此 awk 处理的时间范围在6毫秒到12毫秒之间(即 date 的1倍到2倍):

$ time awk '@load "time"; BEGIN{print int(1000 * gettimeofday())}'
1597103729525
awk '@load "time"; BEGIN{print int(1000 * gettimeofday())}'  0.00s user 0.00s system 74% cpu 0.010 total

7
然而,一旦你使用fork()创建了一个独立的进程,执行了Python解释器并让它加载库/初始化,写入其结果并退出后,该结果将不再准确。 - Charles Duffy

7

显示日期、时间及时区:

date +"%d-%m-%Y %T.%N %Z"

输出:22-04-2020 18:01:35.970289239 IST


4
我只是想补充一下 Alper's answer 的内容,以下是我为了使这项工作正常运行而必须执行的步骤:
在 Mac 上,您需要 brew install coreutils,这样我们就可以使用 gdate。否则,在 Linux 上,只需使用 date。并且此函数将帮助您计算命令的时间而无需创建临时文件或其他任何内容:
function timeit() {
    start=`gdate +%s%N`
    bash -c $1
    end=`gdate +%s%N`
    runtime=$(((end-start)/1000000000.0))
    echo " seconds"
}

而且你可以将它与字符串一起使用:

timeit 'tsc --noEmit'

1
我喜欢这个解决方案,但我更感兴趣的是毫秒。我将此函数移植到我的Ubuntu的.bashrc文件中: start=$(date +%s%N); $*; end=$(date +%s%N); runtime=$(((end-start)/1000000)); echo "$runtime ms" }``` - Uluaiv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接