本文由 简悦 SimpRead 转码, 原文地址 segmentfault.com
前言 这篇文章,不会解释什么是本初子午线,只想以做实验的方式来理解数据差 8 小时的问题。
前言
- 这篇文章,不会解释什么是本初子午线,只想以做实验的方式来理解数据差 8 小时的问题。下面就先说结论,再来谈原理。
解决方案
- 想必大家都很清楚:中国标准时间 = UTC + 8 小时。
- 那么所有和时区有关的地方,都有可能成为 “凶手”。
如果是 java 写入 es 怎么解决时区问题?
- 如果你使用 java 程序来写入 es,我推荐你写入带 T 的时间字符串。提供程序如下:
|
|
- 为什么?因为 java 有些 api 是带时区的。如 new Date().getTime() 默认是东八区,System.currentTimeMillis() 依赖于当前时区来计算毫秒值。
- 虽然上述例子依赖了这个 api,但是这里只是想说明 java 程序所处的环境的时区同样有影响,特别是这个程序很可能是容器化的,那么可能又和系统镜像的时区有关了。
如果是 logstash 写入 es 怎么解决时区问题?
- 建议 input 的时间源数据就是带上时区的字符串,否则就要进行转换。
|
|
或是:
|
|
如果是语句聚合 es 数据怎么解决时区问题?
- 指定 time_zone 配置
|
|
kibana 显示怎么解决时区问题?
- Management»Advanced Settings 设置时区。
原理 & 试验
Es 中和时间相关的数据类型
-
一般在写入 es 的时候,会以 json 的方式写入,由于 json 中没有日期数据类型,所以日期如何存储显示,是由 es 决定的,也就是说 es 会进行隐式的类型转换。
-
es 中的日期可以是:
- 格式化日期的字符串,例如 “2019-12-30” 或 “2019/12/30 12:10:30”。
- 毫秒值。
- 秒值。
试验
- 这里以不同的时间 api 准备了一些数据写入 es, 让我们来看看会发生什么。
- 数据打印出来如下:
|
|
- 默认不设置索引模板的情况,写入 es 后,我们发现带 时区‘T’的数据类型为 date。
- 接下来,我们将轮流设置这两个字段为 kibana 的时间搜索字段,看看会发生什么。
两个实验对时区的思考
- 实验一:以 localTimeNow 做时间搜索字段,显示比数据时间晚了 8 小时。
- 实验二:以 AsiaTime 做时间搜索字段,显示比数据时间早了 8 小时。
-
如何解释?当然是由于时区影响。记住这几个点,就很好理解了:
- es 内部,时间会转换成 UTC 格式,实际按照数值型存储。可以理解为毫秒数。
- kibana 会通过获取时区配置显示时间到界面。
首先来说实验一,为什么 kibana 上显示的时比数据时间多 8 个小时呢?明明是 30 号的数据,愣是跑到 31 号去了?
- 这条数据 “localTimeNow”:“2019-12-30T16:32:07.615”。带时区 T,默认是 UTC 时区,
而 kibana 获取的时区配置是 Asia/Shanghai,为东 8 区,相当于在原来的时间上加上 8 个小时显示,所以跑到 31 号去了。 用大腿想一下,你肯定知道,这种情况下如果把 kibana 时区设置为 UTC,当然数据就显示正常啦。
- 再来说实验二, “AsiaTime”:“2019-12-30T16:32:07.616+0800,由于上面设置了当前 kibana 时区为 UTC, 数据带东八区的时区,所以晚了 8 小时。同理将 kibana 时区改为东八区后显示正常。
总结
- 时区问题,万变不离其宗,搞清楚原理后,任意数据怎么变化,我们都能够有方法应对,希望这篇文章对你有所帮助。
欢迎来公众号【侠梦的开发笔记】 一起交流进步