linux 使用printf内置功能打印当前时间(毫秒或纳秒)

wi3ka0sx  于 2023-01-12  发布在  Linux
关注(0)|答案(2)|浏览(511)

我们可以使用内置的printf函数打印当前时间,而无需调用date这样的外部命令,如下所示:

printf '%(%Y-%m-%d:%H:%M:%S)T %s\n' -1
# sample output: 2019-03-30:17:39:36,846

我们如何让printf也能打印毫秒或纳秒呢?在格式字符串中使用%3N%N是行不通的:

printf '%(%Y-%m-%d:%H:%M:%S,%3N)T %s\n' -1 # outputs 2019-03-30:17:38:16,%3N
printf '%(%Y-%m-%d:%H:%M:%S,%N)T %s\n' -1  # outputs 2019-03-30:17:38:16,%N

但是,date命令可以正常工作:

date +%Y-%m-%d:%H:%M:%S,%3N # gives 2019-03-30:17:39:36,846
date +%Y-%m-%d:%H:%M:%S,%N  # gives 2019-03-30:17:39:36,160643077

这是在Red Hat Linux版本7.3上进行的。

7xzttuei

7xzttuei1#

第5版和第1m版

  • ####EPOCHREALTIME精度为微秒的浮点值
  • ####EPOCHSECONDS自Unix纪元以来的秒数

正确的方式

简而言之:

IFS=. read ESEC NSEC <<<$EPOCHREALTIME
printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC

或者,如果您确实不需要存储值:

printf '%(%F:%T)T.%06.0f\n' ${EPOCHREALTIME/./ }

1.大约$EPOCHREALTIME

请注意:

EPOCHREALTIME
         Each time this parameter is referenced, it expands to the number
         of seconds since the Unix Epoch  (see  time(3))  as  a  floating
         point  value  with  micro-second  granularity.

如果我在同一行中两次输入同一个变量:

echo $EPOCHREALTIME...  $EPOCHREALTIME 
1572000683.886830... 1572000683.886840

或者更明确地说:

printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
761893
761925

echo $((  -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
37

我的乌藨子派也一样

printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
801459
801694

echo $((  -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
246

因此,查询这两次构建整数部分和小数部分的分离过程可能会导致以下问题:(在同一行上,第一次访问$ EPOCHREALTIME可能会给出:NNN1.999995,然后下一个:NNN2.000002。则结果将变为:NNN1.000002,具有***1000000***微秒误差)

2.警告!关于混合$EPOCHSECONDS$EPOCHREALTIME

两者一起使用不仅会导致第一次提到的错误!
$EPOCHSECONDS使用对time()的调用,该调用不会不断更新,而$EPOCHREALTIME使用对gettimeofday()的调用!因此结果可能会有很大差异:
我发现This answer to time() and gettimeofday() return different seconds有很好的解释。
如果我试穿我的主机:

epochVariableDiff () {
    local errcnt=0 lasterrcnt v1 v2 v3 us vals line
    while ((errcnt==0)) || ((errcnt>lasterrcnt)); do
        lasterrcnt=$errcnt
        printf -v vals '%(%s)T %s %s' -1 $EPOCHSECONDS $EPOCHREALTIME
        IFS=$' .' read v1 v2 v3 us <<<"$vals"
        [ "$v1" = "$v2" ] && [ "$v2" = "$v3" ] || ((errcnt++))
        [ $errcnt -eq 1 ] && echo "$line"
        printf -v line '%3d %s - %s - %s . %s' $errcnt $v1 $v2 $v3 $us
        printf "%s\r" "$line"
        ((errcnt)) && echo "$line"
        read -t ${1:-.0002}
    done
}


注:我使用read -t而不是sleep,因为sleep不是内置的
Nota2:您可以使用函数的参数来更改读取超时(休眠)的值

这可能会让事情变得更糟:

$ epochVariableDiff .0002
  0 1586851573 - 1586851573 - 1586851573 . 999894
  1 1586851573 - 1586851573 - 1586851574 . 000277
  2 1586851573 - 1586851573 - 1586851574 . 000686
  3 1586851573 - 1586851573 - 1586851574 . 001087
  4 1586851573 - 1586851573 - 1586851574 . 001502
  5 1586851573 - 1586851573 - 1586851574 . 001910
  6 1586851573 - 1586851573 - 1586851574 . 002309
  7 1586851573 - 1586851573 - 1586851574 . 002701
  8 1586851573 - 1586851573 - 1586851574 . 003108
  9 1586851573 - 1586851573 - 1586851574 . 003495
 10 1586851573 - 1586851573 - 1586851574 . 003899
 11 1586851573 - 1586851573 - 1586851574 . 004400
 12 1586851573 - 1586851573 - 1586851574 . 004898
 13 1586851573 - 1586851573 - 1586851574 . 005324
 14 1586851573 - 1586851573 - 1586851574 . 005720
 15 1586851573 - 1586851573 - 1586851574 . 006113
 16 1586851573 - 1586851573 - 1586851574 . 006526
 17 1586851573 - 1586851573 - 1586851574 . 006932
 18 1586851573 - 1586851573 - 1586851574 . 007324
 19 1586851573 - 1586851573 - 1586851574 . 007733
 19 1586851574 - 1586851574 - 1586851574 . 008144

其中$EPOCHREALTIME的整数部分可能比$EPOCHSECONDS(在我的主机上)增加超过8000微秒。

    • 注:**这似乎与一些 * bug * 有关,不同主机之间或同一主机重新启动后的结果可能会有很大差异,以及其他事情...奇怪的是,我可以在许多不同的主机(英特尔酷睿,英特尔至强,Amd64 ..)上重现它们,但在raspberry pi!?(相同的Debian bash v5.0.3(1)-发行版),不同的内核版本上却不行。
    • 正确:**这不是错误!混合time()gettimeofday()是错误!
    • 因此,请避免同时使用这两种方法!!!**

3.大约printf "..%06.0f"

注:我使用%06.0f而不是%d来确保$NSEC被解释为十进制(浮点),(如果变量以0开头,则防止八进制解释)。
比较:

printf "nn.%06.0f\n" 012345
nn.012345

printf "nn.%06.0f\n" 098765
nn.098765

以及

printf "nn.%d\n" 012345
nn.5349

printf "nn.%d\n" 098765
-bash: printf: 098765: invalid octal number
nn.0

样品运行:在每秒钟开始时显示时间...

小测试:

  • 等待下一秒,然后用微秒打印当前时间 *
while ! read -sn 1 -t .$(( 1000000 - 10#${EPOCHREALTIME#*.} )) _; do
    IFS=. read ESEC NSEC <<< $EPOCHREALTIME
    printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC
done

您可以通过按任意键结束此测试。

2023-01-06:17:28:51.000135
2023-01-06:17:28:52.000095
2023-01-06:17:28:53.000109
2023-01-06:17:28:54.000108
2023-01-06:17:28:55.000132
2023-01-06:17:28:56.000166
2023-01-06:17:28:57.000099
guykilcj

guykilcj2#

bash 5中,可以从EPOCHREALTIME中获取微秒精度,但是printf本身无法直接获取微秒精度,因此需要自己提取微秒。

$ echo $EPOCHREALTIME; printf '%(%F:%T)T.%d\n' "$EPOCHSECONDS" "${EPOCHREALTIME#*.}"; echo $EPOCHREALTIME
1554006709.936990
2019-03-31:00:31:49.937048
1554006709.937083

这需要一点时间,但结果似乎精确到大约0.05毫秒。

相关问题