使用 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 0CET -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”

如何使用 PHP 将日期显示为 iso 8601 格式

无法解析ISO 8601格式的字符串,缺少冒号的冒号,到Java 8 Date

PowerShell中iso8601格式日期和DateTime对象互转实例

Jackson 将 ISO8601 格式的日期时间反序列化为 Java8 Instant