【elasticsearch】數據早8小時Or晚8小時,你知道爲何嗎,附解決方案

前言
  • 這篇文章,不會解釋什麼是本初子午線,只想以作實驗的方式來理解數據差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"]
      }

或是:java

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設置時區。

file

原理&試驗
Es中和時間相關的數據類型
  • 通常在寫入es的時候,會以json的方式寫入,因爲json中沒有日期數據類型,因此日期如何存儲顯示,是由es決定的,也就是說es會進行隱式的類型轉換。
  • es中的日期能夠是:json

    • 格式化日期的字符串,例如"2019-12-30"或"2019/12/30 12:10:30"。
    • 毫秒值。
    • 秒值。
試驗
  • 這裏以不一樣的時間api準備了一些數據寫入es,讓咱們來看看會發生什麼。

file

  • 數據打印出來以下:
{
    "AsiaTime":"2019-12-30T16:32:07.616+0800",
    "newDateTime":1577694727581,
    "localTimeNow":"2019-12-30T16:32:07.615",
    "systemCurrentTimeMilis":1577694727581,
    "newDate":1577694727581
}
  • 默認不設置索引模板的狀況,寫入es後,咱們發現帶 時區‘T’的數據類型爲date。

file

  • 接下來,咱們將輪流設置這兩個字段爲kibana的時間搜索字段,看看會發生什麼。
兩個實驗對時區的思考
  • 實驗一:以localTimeNow作時間搜索字段,顯示比數據時間晚了8小時。

file

  • 實驗二:以AsiaTime作時間搜索字段,顯示比數據時間早了8小時。

file

  • 如何解釋?固然是因爲時區影響。記住這幾個點,就很好理解了:segmentfault

    • es內部,時間會轉換成UTC格式,實際按照數值型存儲。能夠理解爲毫秒數。
    • kibana會經過獲取時區配置顯示時間到界面。

首先來講實驗一,爲何kibana上顯示的時比數據時間多8個小時呢?明明是30號的數據,愣是跑到31號去了?api

  • 這條數據 "localTimeNow":"2019-12-30T16:32:07.615"。帶時區T,默認是UTC時區,

而kibana獲取的時區配置是Asia/Shanghai,爲東8區,至關於在原來的時間上加上8個小時顯示,因此跑到31號去了。
用大腿想一下,你確定知道,這種狀況下若是把kibana時區設置爲UTC,固然數據就顯示正常啦。spa

  • 再來講實驗二, "AsiaTime":"2019-12-30T16:32:07.616+0800,因爲上面設置了當前kibana時區爲UTC,數據帶東八區的時區,因此晚了8小時。同理將kibana時區改成東八區後顯示正常。

總結

  • 時區問題,萬變不離其宗,搞清楚原理後,任意數據怎麼變化,咱們都可以有方法應對,但願這篇文章對你有所幫助。
歡迎來公衆號【俠夢的開發筆記】 一塊兒交流進步
相關文章
相關標籤/搜索