时间标准
GMT(Greenwich Mean Time, 格林威治标准时间)
西元1884年的国际会议上制定了全球性的标准时,以英国伦敦格林威治(Greenwich)这个地方为零度经线的起点(亦称为本初子午线),并以地球由西向东每24小时自转一周360°,定每隔15°经度,时差1小时。而每15°经线则称为该时区的中央经线,将全球划分为24个时区,其中包含23个整时区及180°经线左右两侧的2个半时区
UTC(Coordinated Universal Time,世界协调时间)
UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以“秒”为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本上UTC的本质强调的是比GMT更为精确的世界时间标准
协调世界时跟地区位置没有相关,不代表当前时刻某个地方的时间,所以在说某个地方时间时要加上时区。例如:中国就是UTC+8。
GMT并不等于UTC,只是格林尼治刚好在0时区上。所以GMT = UTC+0才是对的。
格式:2020-07-06T11:24:37.081Z
其中T表示时分秒的开始,结尾的Z表示这是一个世界标准时间
GMT与UTC区别
GMT和UTC都以伦敦格林威治时间为准,不同点是UTC比GMT更精准!
两者的区别在于前者是一个天文上的概念,而后者是基于一个原子钟。
在UTC中,每一年或两年会有一个“闰秒”
DST(Daylight Saving Time, 日光节约时间)
所谓日光节约时间(Daylight Saving Time,简称D.S.T.)是指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用,在英国则称为夏令时间(Summer Time)。这个构想于1784年由美国班杰明·富兰克林提出来,1915年德国成为第一个正式实施夏令日光节约时间的国家,以削减灯光照明和耗电开支。自此以后,全球以欧洲和北美为主的约70个国家都引用这个做法。目前被划分成两个时区的印度也正在商讨是否全国该统一实行夏令日光节约时间
中国实现DST时间范围:1986年至1991年。
美国
夏令时:每年3月第一个星期六到11月第二个星期日;
冬令时:每年3月第二个星期日到11月第一个星期六;
欧洲
夏令时:每年3月的最后一个星期天的凌晨1点开始,十月最后一个星期天凌晨1点结束;
冬令时:每年十月的最后一个星期天的凌晨1点开始,到第二年的三月份的最后一个星期天的凌晨1点结束;
CST 时间
CST却同时可以代表如下 4 个不同的时区:
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00
CST可以同时表示美国,澳大利亚,中国,古巴四个国家的标准时间。这四个地区之间并没有直接的关联,而是由于历史、文化或相关的时区命名约定。
ISO-8601
国际标准化组织的国际标准ISO 8601是日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。目前最新为第三版ISO8601:2004,第一版为ISO8601:1988,第二版为ISO8601:2000
年由4位数字组成YYYY,或者带正负号的四或五位数字表示±YYYYY。以公历公元1年为0001年,以公元前1年为0000年,公元前2年为-0001年。
月、日用两位数字表示:MM、DD。
只使用数字为基本格式。使用短横线"-"间隔开年、月、日为扩展格式。
小时、分和秒都用2位数表示,对UTC时间最后加一个大写字母Z,其他时区用实际时间加时差表示。如UTC时间下午2点30分5秒表示为14:30:05Z或143005Z,当时的北京时间表示为22:30:05+08:00或223005+0800,也可以简化成223005+08。
注:大家还记得java的Date类吗?它默认就是使用ISO-8601表示的。
JAVA Date
我们就可以认为java.util.Java其实表示的就是从格林威治1970年1月1日零点到现在这一时刻的总秒数。
从Date的源码中也可以看到,Date中是不包含时区有关的信息的,因为时间戳和时区没有关系。
如setDate(0)就是1997/1/1 00:00:00。但是获取时会加上时间的偏移量,我们是东八区,所以setDate(0)的显示是1997/1/1 08:00:00。
即时设置时区,获取的时间仍然是当地时间
public static void main(String[] args) {
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
Date time = Calendar.getInstance(timeZone).getTime();
System.out.println(time);
}
########################################
Mon Jan 15 11:36:12 CST 2024
设置默认时区,才会修改时区信息
public static void main(String[] args) {
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
TimeZone.setDefault(timeZone);
Date date =new Date();
System.out.println(date);
}
########################################
Sun Jan 14 19:36:12 PST 2024
- PST 代表太平洋标准时间(Pacific Standard Time),是指美国西部地区的标准时间。在冬季,当没有实行夏令时时,该时区使用 PST。
- CST 代表中部标准时间(Central Standard Time),是指美国中部地区的标准时间。在冬季,当没有实行夏令时时,该时区使用 CST。
java8之后新的时间类带有时区信息
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
LocalDateTime now1 = LocalDateTime.now(zoneId);
System.out.println(now1);
System.out.println(LocalDateTime.now(ZoneId.of("+00:00"))); //0时区的现在时间
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
System.out.println(Instant.now());
}
########################################
2024-01-15T13:49:12.188
2024-01-14T21:49:12.189
2024-01-15T05:49:12.191
2024-01-15T05:49:12.191Z
ES时间类型数据处理
Date field type
JSON doesn’t have a date data type, so dates in Elasticsearch can either be:
- strings containing formatted dates, e.g.
"2015-01-01"
or"2015/01/01 12:10:30"
. - a number representing milliseconds-since-the-epoch.
- a number representing seconds-since-the-epoch (configuration).
Internally, dates are converted to UTC (if the time-zone is specified) and stored as a long number representing milliseconds-since-the-epoch.
format
In JSON documents, dates are represented as strings. Elasticsearch uses a set of preconfigured formats to recognize and parse these strings into a long value representing milliseconds-since-the-epoch in UTC.
Besides the built-in formats, your own custom formats can be specified using the familiar yyyy/MM/dd
syntax:
DateFormat示例
model_annotations | es_mapping | es_data_browser(2024-01-05 10:15:32) utc+8 | java_search no_formate | java_search formate |
---|---|---|---|---|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") @Field(type = FieldType.Date, pattern = "yyyy-MM-dd HH:mm:ss.SSS", format = DateFormat.custom) private Date startTime; | type:date format:yyyy-MM-dd HH:mm:ss.SSS | 2024-01-05 02:15:32.161 | 1704422421661 | "2024-01-05 02:34:20.432" |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") @Field(type = FieldType.Date) private Date startTime1; | type:date format:date_optional_time||epoch_millis | 2024-01-05T02:15:32.161Z | 1704422421661 | "2024-01-05 10:34:20.432" |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6") @Field(type = FieldType.Date_Nanos) private Date startTime2; | type:date_nanos format:date_optional_time||epoch_millis | 同上 | 同上 | 同上 |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6")@Field(type = FieldType.Date, format = DateFormat.epoch_millis) private Date startTime3; | type:date format:epoch_millis | 1704420932161 (2024-01-05 10:15:32) | 1704422421661 (2024-01-05 10:40:21) | "2024-01-05 08:34:20.432" |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6")@Field(type = FieldType.Date, format = DateFormat.epoch_second) private Date startTime4; | type:date format:epoch_second | 1704420932.161 | 1704422421661 | "2024-01-05 08:34:20.432" |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6")@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second) private Date startTime5; | type:date format:date_hour_minute_second | 2024-01-05T02:15:32 | 1704422421000 | "2024-01-05 08:34:20.000" |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6")@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second_fraction) private Date startTime6; | type:date format:date_hour_minute_second_fraction | 同上 | 同上 | 同上 |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+6")@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second_millis) private Date startTime7; | type:date format:date_hour_minute_second_millis | 同上 | 同上 | 同上 |
结论
1、自定义formate:pattern = "yyyy-MM-dd HH:mm:ss.SSS", format = DateFormat.custom
保存在es中是字符串,并且有空格,es空格不支持排序,要使具有空格的字符串格式的时间支持排序,可以将其转换为标准的时间格式,例如ISO 8601格式(如"2024-01-05T17:22:24")
2、通过es注解生成的es mapping,默认formate { DateFormat.date_optional_time, DateFormat.epoch_millis },写入es保存的是utc时间,格式为:2024-01-05T02:15:32.161Z
3、如果单指定date的formate 为format = DateFormat.epoch_millis,写入es是带有时区计算后的毫秒值
4、只要es 的时间类型formate不是epoch_millis,写入都是utc时间,程序返回的都是毫秒值,并且自动加上时区,自定义formate也返回加上时区的毫秒值。
5、程序查询自定义类型的date数据时,需要自行添加时区参数(猜测因为存储的是字符串,所以要通过时区信息转换,之后才能进行es数据匹配)
queryBuilder = QueryBuilders.rangeQuery(key).timeZone("Asia/Shanghai").gte("2023-01-01");
6、如果date类型formate包含多个,查询时只要参数包含在formate的集合中,es会自行formate,不包含则报错。
7、代码属性不设置JsonFormat,默认返回毫秒值(已带有时区计算),可根据毫秒值转换时间