If you don't have access to GNU date
(does it even make sense to get nanosecond precision when invoking date
alone takes a few thousands if not millions of those), but if switching to other shells is an option, you can do:
In zsh
:
TZ=UTC0 print -rP '%D{%FT%T.%9.Z}'
(here using prompt expansion via print -P
)
Or:
zmodload zsh/datetime
TZ=UTC0 strftime %FT%T.%9.Z $epochtime
Or to store in a variable:
TZ=UTC0 print -rPv var '%D{%FT%T.%9.Z}'
Or:
zmodload zsh/datetime
TZ=UTC0 strftime -s var %FT%T.%9.Z $epochtime
Or:
() { local -x TZ=UTC0; var=${(%):-%D{%FT%T.%9.Z}}; }
With ksh93:
TZ=UTC0 printf '%(%FT%T.%NZ)T\n'
Or to store in a variable:
var=${ printf '%(%FT%T.%NZ)T'; }
bash
did copy a subset of ksh93
's printf '%(format)T' datespec
a few years back, but does not support %N
for nanoseconds.
Since version 5.0, it added support for the $EPOCHSECONDS
and $EPOCHREALTIME
variables (not $epochtime
array) from zsh. Only with microsecond precision, but may be enough for your use case:
t=$EPOCHREALTIME; TZ=UTC0 printf "%(%FT%T)T.${t#*.}Z\n" "${t%.*}"
All of those use only builtins and don't fork any process, so you should be able to run quite a few per millisecond.
$ repeat 10 TZ=UTC0 print -rP '%D{%FT%T.%9.Z}'
2022-03-17T12:04:56.563450377Z
2022-03-17T12:04:56.563488246Z
2022-03-17T12:04:56.563512375Z
2022-03-17T12:04:56.563530355Z
2022-03-17T12:04:56.563545833Z
2022-03-17T12:04:56.563559764Z
2022-03-17T12:04:56.563575171Z
2022-03-17T12:04:56.563594030Z
2022-03-17T12:04:56.563611980Z
2022-03-17T12:04:56.563626251Z
$ repeat 10 date -u +%FT%T.%NZ
2022-03-17T12:05:28.902806919Z
2022-03-17T12:05:28.905552036Z
2022-03-17T12:05:28.907594864Z
2022-03-17T12:05:28.908563238Z
2022-03-17T12:05:28.909433758Z
2022-03-17T12:05:28.910549552Z
2022-03-17T12:05:28.911642330Z
2022-03-17T12:05:28.912596098Z
2022-03-17T12:05:28.913575587Z
2022-03-17T12:05:28.914538184Z
date
implementation you are using.