如何获得自 Unix 纪元以来的毫秒数?

Edu*_*scu 37 bash timestamps

我想做一个 bash 脚本来测量浏览器的启动时间,因为我使用的是 html,它使用 JavaScript 以毫秒为单位获取加载时的时间戳。

在我调用浏览器之前的 shell 脚本中,我得到了时间戳:

date +%s
Run Code Online (Sandbox Code Playgroud)

问题是它以秒为单位获取时间戳,我需要以毫秒为单位,因为有时第二次运行时浏览器会在不到一秒的时间内启动,我需要能够使用毫秒而不是秒来精确测量该时间。

如何从 bash 脚本中获取以毫秒为单位的时间戳?

小智 59

使用 GNU 或 ast-open 实现date(或busybox',如果在FEATURE_DATE_NANO启用该选项的情况下构建),我将使用:

$ date +%s%3N
Run Code Online (Sandbox Code Playgroud)

它返回自 Unix 纪元以来的毫秒数。

  • 优雅,漂亮,+1 (5认同)
  • 确实优雅,+1。如果像我一样,您想确保 `%3N` 执行必要的左零填充(无需阅读文档。;-),您可以执行 `while sleep 0.05; 做日期 +%s%3N; done`,是的,必要的零在那里。 (2认同)

gol*_*cks 35

date +%s.%N会给你,例如,1364391019.877418748。%N 是当前秒经过的纳秒数。请注意,它是 9 位数字,默认情况下,如果 date 小于 100000000,它将用零填充它。如果我们想用数字进行数学运算,这实际上是一个问题,因为bash 将带有前导零的数字视为八进制。可以通过在字段规范中使用连字符来禁用此填充,因此:

echo $((`date +%s`*1000+`date +%-N`/1000000))
Run Code Online (Sandbox Code Playgroud)

会天真地给你自纪元以来的毫秒数。

然而,正如 Stephane Chazelas 在下面的评论中指出的那样,这是两个不同的date调用,它们将产生两个略有不同的时间。如果秒在它们之间滚动,则计算将整整一秒。所以:

echo $(($(date +'%s * 1000 + %-N / 1000000')))
Run Code Online (Sandbox Code Playgroud)

或优化(感谢下面的评论,虽然这应该是显而易见的):

echo $(( $(date '+%s%N') / 1000000));
Run Code Online (Sandbox Code Playgroud)

  • 请注意,在您运行第一个日期和第二个日期之间,可能已经过去了几百万纳秒,甚至可能不是同一秒。最好做`$(($(date +'%s * 1000 + %N / 1000000')))`。这仍然没有多大意义,但会更可靠。 (7认同)
  • `%N` 在 BSD 和 OS X 中不可用。 (4认同)
  • 为什么不只是`echo $(( $(date '+%s%N') / 1000000))`? (3认同)

Sté*_*las 14

万一有人使用其他外壳而不是bash,ksh93并且zsh有一个浮点$SECONDS变量,如果你这样做typeset -F SECONDS可以方便地准确测量时间:

$ typeset -F SECONDS=0
$ do-something
something done
$ echo "$SECONDS seconds have elapsed"
18.3994340000 seconds have elapsed
Run Code Online (Sandbox Code Playgroud)

由于版本 4.3.13 (2011)在模块中zsh有一个$EPOCHREALTIME特殊的浮点变量zsh/datetime

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1364401642.2725396156
$ printf '%d\n' $((EPOCHREALTIME*1000))
1364401755993
Run Code Online (Sandbox Code Playgroud)

请注意,这是从返回的两个整数(秒和纳秒)派生的clock_gettime()。在大多数系统上,这比单个 Cdouble浮点数所能容纳的精度更高,因此在算术表达式中使用它时会失去精度(1970 年头几个月的日期除外)。

$ t=$EPOCHREALTIME
$ echo $t $((t))
1568473231.6078064442 1568473231.6078064
Run Code Online (Sandbox Code Playgroud)

要计算高精度时差(尽管我怀疑您需要的精度超过毫秒),您可能需要使用$epochtime特殊数组(其中包含秒和纳秒作为两个单独的元素)。

从 5.7 (2018) 版本开始,strftimeshell 内置程序还支持%NGNU 纳秒格式date和 a%.来指定精度,因此也可以使用以下方法检索自纪元以来的毫秒数:

zmodload zsh/datetime
strftime %s%3. $epochtime
Run Code Online (Sandbox Code Playgroud)

(或存储在变量中-s var


man*_*ork 8

为了避免计算以获取毫秒,命令行 JavaScript 解释器可能会有所帮助:

bash-4.2$ node -e 'console.log(new Date().getTime())' # node.js
1364391220596

bash-4.2$ js60 -e 'print(new Date().getTime())'       # SpiderMonkey
1364391220610

bash-4.2$ jsc -e 'print(new Date().getTime())'        # WebKit 
1364391220622

bash-4.2$ seed -e 'new Date().getTime()'              # GNOME object bridge
1364391220669
Run Code Online (Sandbox Code Playgroud)

在 Ubuntu Eoan 上包含这些解释器的软件包:


ImH*_*ere 5

在 bash 5+ 中,有一个微秒级的变量:$EPOCHREALTIME.

所以:

$ echo "$(( ${EPOCHREALTIME//.} / 1000 ))"
1568385422635
Run Code Online (Sandbox Code Playgroud)

以毫秒为单位打印自纪元 (1/1/70) 以来的时间。

否则,您必须使用日期。GNU 日期:

echo "$(date +'%s%3N')"
Run Code Online (Sandbox Code Playgroud)

https://serverfault.com/a/423642/465827 中列出的替代方案之一

或者brew install coreutils对于 OS X

或者,如果其他一切都失败了,编译 (gcc epochInµsec.c) 这个 c 程序(根据需要调整):

#include <stdio.h>
#include <sys/time.h>
int main(void)
{
  struct timeval time_now;
    gettimeofday(&time_now,NULL);
    printf ("%ld secs, %ld usecs\n",time_now.tv_sec,time_now.tv_usec);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意,调用任何外部程序都需要时间来从磁盘读取和加载、启动、运行并最终打印输出。这将需要几毫秒。这是任何外部工具(包括日期)所能达到的最低精度。