我刚刚注意到,POSIXdate
似乎没有%s
或%N
格式项。所以我不能使用那些。在我的 shell 脚本中获取纪元时间戳的替代方法是什么?
答案1
对于整数秒的纪元时间,则为:
awk 'BEGIN{srand(); print srand()}'
或者:
awk 'BEGIN{print srand(srand())}'
作为在 POSIX 中awk
,srand()
不带参数使用当前时间作为伪随机生成器的种子。它还返回前一个种子,因此srand()
上面的第二个返回用于前一个种子的纪元时间。
您可以通过以下方式获得小数部分:
echo|LC_ALL=C TZ=UTC0 diff -u /dev/null - |sed -n '2s/.*\(\.[0-9]*\).*/\1/p'
POSIX 确实指定了输出格式diff -u
,并且当文件为 时使用当前时间-
。
但是,自从您在获得输出之前调用以来,可能已经过去了数千甚至数百万纳秒awk
,甚至可能不是同一秒。但是,您可以通过<epochtime> % 60
与以下内容进行比较来检查情况是否如此第二diff
如果您愿意的话,可以将其作为标头中 (UTC) 时间戳的一部分。
1 关于这个awk
解决方案,请注意 POSIX 过去并没有用太多的语言来表达它。我做到了提出异议不久前向 POSIX 询问了不明确的措辞,还指出在当今时代强制实现使用这种可怜的熵源是不合理的。相反,解决是明确要求srand()
使用纪元时间。
答案2
编写一个 C 程序来调用time()
并打印结果。借用示例程序time()
函数的规范,我们称之为例如seconds.c
:
#include <stdio.h>
#include <stdint.h>
#include <time.h>
int main(void)
{
time_t t = time(NULL);
printf("%ju\n", (uintmax_t) t);
return 0;
}
并用 进行编译c99 -o seconds seconds.c
。 (如果我读到规格正确的是,这应该是编译它的标准方法。)
或者,您可以获取分解的日期并计算秒数。这相对容易,因为每一天的长度都是 86400 秒。我们确实需要去掉某些值的前导零,这样 shell 算术就不会将它们视为八进制:
作为外壳函数:
epochtime() {
eval "$(date -u +'y=%Y j=%j h=%H m=%M s=%S')"
s=${s#0}
m=${m#0}
h=${h#0}
j=${j#0}
j=${j#0}
t=$(( ((y-1970)*365 + (y-1969)/4 + j - 1)*86400 + h*3600 + m*60 + s))
echo "$t"
}
关于闰年计算的注意事项:纪元后的第一个闰年是 1972 年,并且 (1972-1969)/4 = 3/4 = 0 ,而 (1973-1969)/4 = 4/4 = 1 (依赖于整数截断)。因此 (year-1969)/4 给出了闰年的数量前本年度。今年可能的闰日包含在%j
值“一年中的某一天”中。该数字从 1 开始计数,但我们想要的是经过的完整天数,因此表达式中需要负一。
答案3
您可以使用自定义date
格式字符串来完成此操作,该字符串为自纪元以来的秒数内的 POSIX 公式生成 shell 算术表达式:
secs=$((`TZ=GMT0 date \
+"((%Y-1600)*365+(%Y-1600)/4-(%Y-1600)/100+(%Y-1600)/400+1%j-1000-135140)\
*86400+(1%H-100)*3600+(1%M-100)*60+(1%S-100)"`))