前言
- 這篇文章,不會解釋什么是本初子午線,只想以做實驗的方式來理解數據差8小時的問題。下面就先說結論,再來談原理。
解決方案
- 想必大家都很清楚:中國標准時間= UTC + 8小時。
- 那么所有和時區有關的地方,都有可能成為“凶手”。
如果是java寫入es怎么解決時區問題?
- 如果你使用java程序來寫入es,我推薦你寫入帶T的時間字符串。提供程序如下:
/**
* String timeZoneConvert = timeZoneConvert(
* new Date().getTime()
* , "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
* "Asia/Shanghai");
*
* @param date 毫秒
* @param pattern format時間格式
* @param timeZone 時區
* @return 如:2019-12-30T16:32:07.616+0800
*/
public static String timeZoneConvert(Long date,String pattern,String timeZone){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat(pattern);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
return simpleDateFormat.format(date);
}
- 為什么?因為java有些api是帶時區的。如new Date().getTime()默認是東八區,System.currentTimeMillis() 依賴於當前時區來計算毫秒值。
- 雖然上述例子依賴了這個api,但是這里只是想說明java程序所處的環境的時區同樣有影響,特別是這個程序很可能是容器化的,那么可能又和系統鏡像的時區有關了。
如果是logstash寫入es怎么解決時區問題?
- 建議input的時間源數據就是帶上時區的字符串,否則就要進行轉換。
mutate{
gsub => [
"time", "[+]", "T"
]
}
mutate{
replace => ["time","%{time}+08:00"]
}
或是:
date {
match => ["timestamp", "yyyy-MM-dd HH:mm:ss"]
target => "my_timestamp"
timezone => "+08:00"
}
如果是語句聚合es數據怎么解決時區問題?
- 指定time_zone配置
"aggs": {
"by_day": {
"date_histogram": {
"field": "date",
"interval": "day",
"time_zone": "Asia/Shanghai"
}
}
}
kibana顯示怎么解決時區問題?
- Management>>Advanced Settings設置時區。
原理&試驗
Es中和時間相關的數據類型
- 一般在寫入es的時候,會以json的方式寫入,由於json中沒有日期數據類型,所以日期如何存儲顯示,是由es決定的,也就是說es會進行隱式的類型轉換。
- es中的日期可以是:
- 格式化日期的字符串,例如"2019-12-30"或"2019/12/30 12:10:30"。
- 毫秒值。
- 秒值。
試驗
- 這里以不同的時間api准備了一些數據寫入es,讓我們來看看會發生什么。
- 數據打印出來如下:
{
"AsiaTime":"2019-12-30T16:32:07.616+0800",
"newDateTime":1577694727581,
"localTimeNow":"2019-12-30T16:32:07.615",
"systemCurrentTimeMilis":1577694727581,
"newDate":1577694727581
}
-
默認不設置索引模板的情況,寫入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時區改為東八區后顯示正常。
總結
- 時區問題,萬變不離其宗,搞清楚原理后,任意數據怎么變化,我們都能夠有方法應對,希望這篇文章對你有所幫助。
歡迎來公眾號【俠夢的開發筆記】 一起交流進步