自Unix时代以来如何获得毫秒数?


30

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

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

date +%s

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

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

Answers:


28

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

echo $((`date +%s`*1000+`date +%-N`/1000000))

从纪元开始会天真地给您毫秒。

但是,正如斯蒂芬·查泽拉斯(Stephane Chazelas)在下面的评论中指出的那样,这是两个不同的date调用,将产生两个略有不同的时间。如果秒数在它们之间翻转,则计算将减少一整秒。所以:

echo $(($(date +'%s * 1000 + %-N / 1000000')))

或经过优化(感谢下面的评论,尽管这应该很明显):

echo $(( $(date '+%s%N') / 1000000));

我尝试了一下,而且效果很好,谢谢+ 1 /接受!
Eduard Florinescu

7
请注意,在您运行第一个日期和第二个日期的时间之间,可能已经过去了几百万纳秒,甚至可能不是同一秒。最好做$(($(date +'%s * 1000 + %N / 1000000')))。那仍然没有多大意义,但是会更可靠。
斯特凡Chazelas

1
通过关闭零填充固定为日期指出的(1)
阿洛伊斯Mahdal

3
%N在BSD和OS X中不可用
。– orkoden

1
为什么不只是echo $(( $(date '+%s%N') / 1000000))呢?
Hitechcomputergeek

47

使用GNU或ast-open实现date(如果FEATURE_DATE_NANO启用了该选项,则为astbox开放式实现),我将使用:

$ date +%s%3N

从Unix时代返回毫秒数。


5
优雅,优美,+ 1
Eduard Florinescu 2014年

1
Upvoting的优雅
sleepycal

确实很优雅,+ 1。如果像我一样,您想确定%3N是否需要进行必要的左零填充(无需阅读文档; ;-),可以这样做while sleep 0.05; do date +%s%3N; done,是的,必要的零在其中。
特里·布朗

谢谢特里!但是%3N确实是零填充。此外,我不认为您的解决方案会加零,只会延迟很小的响应时间。
javabeangrinder,

javabeangrinder,@ TerryBrown的代码不是解决方案,仅测试代码以确认%3N确实填充了0。
斯特凡·查泽拉斯

10

如果有人使用以外的其他Shell bashksh93并且zsh有一个浮点$SECONDS变量(如果您这样做)typeset -F SECONDS,则可以方便地准确地测量时间:

$ typeset -F SECONDS=0
$ do-something
something done
$ echo "$SECONDS seconds have elapsed"
18.3994340000 seconds have elapsed

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

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1364401642.2725396156
$ printf '%d\n' $((EPOCHREALTIME*1000))
1364401755993

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

$ t=$EPOCHREALTIME
$ echo $t $((t))
1568473231.6078064442 1568473231.6078064

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

从5.7(2018)版本开始,strftimeshell内置还支持%N纳秒级格式àla GNU date和a %.来指定精度,因此也可以通过以下方式检索自纪元以来的毫秒数:

zmodload zsh/datetime
strftime %s%3. $epochtime

(或使用存储在变量中-s var


请注意,变量“ $ SECONDS”未与EPOCH时间连接/相关。每个小数部分(毫秒,微秒和纳秒)可能会完全不同。
艾萨克

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

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


2

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

所以:

$ echo "$(( ${EPOCHREALTIME//.} / 1000 ))"
1568385422635

从纪元(1/1/70)起以毫秒为单位打印时间。

如果失败,则必须使用日期。GNU日期:

echo "$(date +'%s%3N')"

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;
}

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.