Elasticsearch默认为UTC时间,即零时区,查询时若不指定时区,则默认以0时区查询,和我们所在的东八区差8小时。yyyy-MM-dd’T’HH:mm:ss.SSSZ,这里的Z就代表UTC时区。

默认的时区不能改

查询指定时区

Es在进行日期查询/聚合时可以指定时区:

  1. //日期范围查询
  2. POST datatypetest/_search
  3. {
  4. "query": {
  5. "range": {
  6. "date3": {
  7. "gte": "2018-07-05",
  8. "lte": "now",
  9. "time_zone": "Asia/Shanghai"//这就是东八区(北京时间/中国标准时间)
  10. }
  11. }
  12. }
  13. }
//日期聚合
GET my_index/_search?size=0
{
  "aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day",
        "time_zone": "Asia/Shanghai"
      }
    }
  }
}
//Java获取系统时区id
TimeZone.getDefault().getID()
//Es Java Api日期范围查询
QueryBuilders
  .rangeQuery("your date field")
  .gte("your date from")
  .lte("your date to")
  .timeZone(TimeZone.getDefault().getID());//此处只能设置时区id
//Es Java Api日期聚合查询
AggregationBuilders
    .dateHistogram("your alias")
    .timeZone(DateTimeZone.getDefault());//获取系统默认时区,此处timeZone对象是joda包中的DateTimeZone

在使用Kibana时,Kibana会默认获取浏览器时区,在显示数据时根据时区做日期的格式化。但使用DevTools写DSL或者直接请求Es时默认返回的都是UTC时间,会发现时间少了8小时。

改kibana时区

kibana 默认时区是浏览器时区。可以修改,修改方式如下:
Stack Management -> Advanced Settings ->Timezone for data formatting.
image.png

Logstash

默认UTC
真实同步案例讲解一下时区处理:

  • 数据源端:Mysql;
  • 数据目的端:Elasticsearch;
  • 同步方式:logstash,本质借助:logstash_input_jdbc 插件同步;
  • 时区处理:logstash filter 环节 ruby 脚本处理。

如下只给出了中间 filter 环节的脚本:

filter {
 ruby { 
   code => "event.set('timestamp', event.get('publish_time').time.localtime + 8*60*60)" 
 }
 ruby {
   code => "event.set('publish_time',event.get('timestamp'))"
 }
 mutate {
   remove_field => ["timestamp"]
 }
}

三行脚本含义,解释如下:

  • 第一行:将 publish_time 时间加 8 小时处理,赋值给 timestamp。

publish_time 到了 logstash 已转成了 UTC 时区了。
timestamp 类似似 C 语言中的交换两个数函数中的 temp 临时变量。

  • 第二行:将 timestamp 时间赋值给 publish_time。
  • 第三行:删除中转字段:timestamp。

源数据Mysql 效果:
image.png
同步后 效果:
image.png
如上两个截图,对比一下区别:

  • publish_time 做了时区处理,两者时间已一致,都是东 8 区。
  • update_time 未做时间处理,写入Elasticsearch 后由东8区时间 10:57:31 转为UTC时区时间 02:57:31,少了8小时。

    ingest pipeline 预处理

  • 步骤 1:定义预处理管道:chage_utc_to_asiash(名称自己定义即可)。

在该管道中实现了时区转换。

  • 步骤 2:创建索引同时指定缺省管道:chage_utc_to_asiash。
  • 步骤 3:写入数据(单条或 bulk 批量均可) ```shell PUT _ingest/pipeline/chage_utc_to_asiash { “processors”: [ {
    "date" : {
      "field" : "my_time",
      "target_field": "my_time", 
      "formats" : ["yyyy-MM-dd HH:mm:ss"],
      "timezone" : "Asia/Shanghai"
    }
    
    } ] }

PUT my-index-000001 { “settings”: { “default_pipeline”: “chage_utc_to_asiash” }, “mappings”: { “properties”: { “my_time”: { “type”: “date” } } } }

PUT my-index-000001/_doc/1 { “my_time”: “2021-08-09 08:07:16” }

当写入数据后,执行检索时,kibana dev tool 返回结果如下:
```shell
"hits" : [
      {
        "_index" : "my-index-000001",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "my_time" : "2021-08-09T08:07:16.000+08:00"
        }
      }
    ]

最明显的特征是:多了+08:00 时区(东8区)标志。