使用 date 命令生成 iso-8601 格式的时间序列,如何处理服务器系统日期原点偏移?
Posted
技术标签:
【中文标题】使用 date 命令生成 iso-8601 格式的时间序列,如何处理服务器系统日期原点偏移?【英文标题】:Generate time serie in iso-8601 format using date command, how to deal with server system date origin offset? 【发布时间】:2014-06-11 20:28:15 【问题描述】:我有以下 bash 函数,它在运行 ubuntu 的机器上生成 iso-8601 格式的纪元列表,它工作正常。 (其中 isdate 和 isint bash 函数用于测试输入)
gen_epoch()
#@ USAGE: gen_epoch [start_date_iso] [end_date_iso] [increment_in_seconds]
#@
#@ TASK : generate an epoch list (epoch list in isodate format).
#@ result on STDOUT: [epoch_list]
#@ error_code : 2 0
## test argument
if [ "$#" -ne 3 ]; then echo "$FUNCNAME: input error [nb_of_input]"; return 2
elif [ $( isdate $1 &> /dev/null; echo $? ) -eq 2 ]; then echo "$FUNCNAME: argument error [$1]"; return 2
elif [ $( isdate $2 &> /dev/null; echo $? ) -eq 2 ]; then echo "$FUNCNAME: argument error [$2]"; return 2
elif [ $( isint $3 &> /dev/null; echo $? ) -eq 2 ]; then echo "$FUNCNAME: argument error [$3]"; return 2
else local beg=$( TZ=UTC date --date="$1" +%s ); local end=$( TZ=UTC date --date="$2" +%s ); local inc=$3; fi
## generate epoch
while [ $beg -le $end ]
do
local date_out=$( TZ=UTC date --date="UTC 1970-01-01 $beg secs" --iso-8601=seconds ); beg=$(( $beg + $inc ))
echo $date_out%+*
done
它为此命令行示例生成预期值:
gen_epoch 2014-04-01T00:00:00 2014-04-01T07:00:00 3600
预期值:
2014-04-01T00:00:00
2014-04-01T01:00:00
2014-04-01T02:00:00
2014-04-01T03:00:00
2014-04-01T04:00:00
2014-04-01T05:00:00
2014-04-01T06:00:00
2014-04-01T07:00:00
但是我在没有root权限的服务器上尝试过这个功能,我发现了以下结果:
2014-03-31T17:00:00
2014-03-31T18:00:00
2014-03-31T19:00:00
2014-03-31T20:00:00
2014-03-31T21:00:00
2014-03-31T22:00:00
2014-03-31T23:00:00
2014-04-01T00:00:00
我发现服务器时间原点不在 1970-01-01T00:00:00。
输入TZ=UTC date --date="1970-01-01T00:00:00" +%s
命令给出-25200
的值,对应于7 小时的延迟,而它应该给出0。
我的问题是如何在服务器上纠正这个问题?
假设我不知道我在哪台机器上运行它,你能帮我找到一个等效的解决方案吗?所以我知道系统时间是否正确?
【问题讨论】:
【参考方案1】:不是一个完整的答案,但评论太长了。
我猜这个特定的服务器在设置时配置不正确。问题是 Bios 时钟设置为本地时间,而系统认为它是 UTC(反之亦然)(使用hwclock
查询硬件时钟设置)。
如果系统配置不正确并且您由于任何原因无法修复它(没有超级用户帐户或其他),我建议在您的软件中提供“修复时区描述文件并在 TZ 中指定它像这样的变量:TZ=:/path/to/fixing/timezone date --date="1970-01-01T00:00:00" +%s
。显然,您必须预先计算哪个 TZ 描述文件修复了问题并使用正确的。通常可用的时区存储在 /usr/share/zoneinfo
【讨论】:
我尝试了以下方法(可能我误解了您的建议):for i in /usr/share/zoneinfo/*; do if [ -f $i ]; then echo $i##*/ $( TZ=$i date --date="1970-01-01T00:00:00" +%s); fi; done
。在我的计算机上,对于不同的时区(UTC 0
、CET -3600
等),我收到了明显不同的结果,同时在服务器上我得到的所有文件的值都相同,-25200
。这是否意味着这些文件已损坏?服务器上hwclock
不存在。
什么是服务器操作系统?问题uname -a
。这个想法是分发一个适合特定系统的 zoneinfo 文件,并使用:/path/to/filename
系统在TZ
中指定它。问题是 :/filename
是一个 Linux(或者更确切地说是 GNU libc)扩展,所以你应该确保你的服务器实际上是 GNU Linux :)
我已经验证,两台机器都是GNU/Linux。我的机器:Linux hostname 3.13.0-24-generic #46-Ubuntu SMP Thu Apr 10 19:11:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
和服务器:Linux hostname 2.6.18-348.3.1.el5 #1 SMP Mon Mar 11 15:43:13 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux
。
您有root
访问服务器的权限吗?如果有,请检查/sbin/hwclock
并修复硬件时钟。如果您不这样做,只需尝试通过选择东半球的时区来补偿不正确的系统设置。我猜你需要像TZ=UTC+07:00 -date="1970-01-01T00:00:00" +%s
这样的东西。
很遗憾我没有,但我可以与管理员交谈 :)。我已经尝试过你的建议,但我得到了相同的 -25200
值。以上是关于使用 date 命令生成 iso-8601 格式的时间序列,如何处理服务器系统日期原点偏移?的主要内容,如果未能解决你的问题,请参考以下文章
c++11:使用HowardHinnant/date.h解析ISO8601格式字符串,并解决时区问题
使用具有 ISO 8601 格式的“DateTime.LocalNow”
无法解析ISO 8601格式的字符串,缺少冒号的冒号,到Java 8 Date