先上结论:
1、yyyy-MM-dd'T'HH:mm:ss.SSSXXX的XXX表示时区,Z零时区,+08:00东八区(大致)
2、java 8,时间字符串不带时区,使用LocalDateTime,因为即使字符串附带了时区信息也不被使用;如果要使用字符串附带的时区信息则使用ZonedDateTime
3、使用DateTimeFormatter,毫秒都是右补零;SimpleDateFormat是左补零;解决方式使用三位毫秒格式,如:2023-02-13T00:00:00.12Z改为2023-02-13T00:00:00.120Z或2023-02-13T00:00:00.012Z再做数据类型转换
看代码和注释
package com.rootcloud;
import org.apache.commons.lang.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class Main21DateTest {
public static void main(String[] args) throws ParseException {
//结论:java 8,时间字符串不带时区,使用LocalDateTime,因为即使字符串附带了时区信息也不被使用;如果要使用字符串附带的时区信息则使用ZonedDateTime
//使用DateTimeFormatter,毫秒都是右补零;SimpleDateFormat是左补零;解决方式永远使用三位毫秒格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); //基准
System.out.println("2023-02-13T00:00:00.120");
System.out.println(sdf.parse("2023-02-13T00:00:00.120").getTime());
System.out.println("DateTimeFormatter+LocalDateTime");
//XXX代表时区
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
//8SH 输入 东八区时间,选择上海时间所在时区,输出 0时区时间,时间戳和基准时间相同(毫秒自动右补零)
final Instant instant8SH = LocalDateTime.parse("2023-02-13T00:00:00.12+08:00", dateTimeFormatter).atZone(ZoneId.of("Asia/Shanghai")).toInstant();
System.out.println("8SH");
System.out.println(instant8SH.toString());
System.out.println(instant8SH.toEpochMilli());
//8UTC与8SH相比,输入zoneId变成UTC,输出时间为 0时区2023-02-13T00:00:00.120Z,时间戳比8SH小8H,结论UTC会覆盖+08:00的效果
final Instant instant8UTC = LocalDateTime.parse("2023-02-13T00:00:00.12+08:00", dateTimeFormatter).atZone(ZoneId.of("UTC")).toInstant();
System.out.println("8UTC");
System.out.println(instant8UTC.toString());
System.out.println(instant8UTC.toEpochMilli());
//8Default输出和8SH相同,猜测1:覆盖成Asia/Shanghai所在时区,猜测2:不覆盖,使用字符串的时区
final Instant instant8Default = LocalDateTime.parse("2023-02-13T00:00:00.12+08:00", dateTimeFormatter).atZone(ZoneId.systemDefault()).toInstant();
System.out.println("8Default");
System.out.println(instant8Default.toString());
System.out.println(instant8Default.toEpochMilli());
//ZUTC 输入Z和UTC同为零时区,输出与基准差8H 符合预期
final Instant instantZUTC = LocalDateTime.parse("2023-02-13T00:00:00.12Z", dateTimeFormatter).atZone(ZoneId.of("UTC")).toInstant();
System.out.println("ZUTC");
System.out.println(instantZUTC.toString());
System.out.println(instantZUTC.toEpochMilli());
//ZDefault 与 8Default输出相等,default
final Instant instantZDefault = LocalDateTime.parse("2023-02-13T00:00:00.12Z", dateTimeFormatter).atZone(ZoneId.systemDefault()).toInstant();
System.out.println("ZDefault");
System.out.println(instantZDefault.toString());
System.out.println(instantZDefault.toEpochMilli());
//java.time.LocalDateTime.from 里看到有TemporalAccessor有多种实现,其中包括ZonedDateTime,自带时区
final Instant instant = ZonedDateTime.parse("2023-02-13T00:00:00.12Z", dateTimeFormatter).toInstant();
System.out.println("ZonedDateTime");
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
// 报错,必须定义XXX
// final DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
// final Instant instant2 = ZonedDateTime.parse("2023-02-13T00:00:00.120", dateTimeFormatter2).toInstant();
// System.out.println("ZonedDateTime");
// System.out.println(instant2.toString());
// System.out.println(instant2.toEpochMilli());
System.out.println("\nSimpleDateFormat+Date");
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date parse = simpleDateFormat.parse("2023-02-13T00:00:00.12Z");
System.out.println(parse.getTime());
parse = simpleDateFormat.parse("2023-02-13T00:00:00.12+08:00");
System.out.println(parse.getTime());
}
}
结果:
2023-02-13T00:00:00.120
1676217600120
DateTimeFormatter+LocalDateTime
8SH
2023-02-12T16:00:00.120Z
1676217600120
8UTC
2023-02-13T00:00:00.120Z
1676246400120
8Default
2023-02-12T16:00:00.120Z
1676217600120
ZUTC
2023-02-13T00:00:00.120Z
1676246400120
ZDefault
2023-02-12T16:00:00.120Z
1676217600120
ZonedDateTime
2023-02-13T00:00:00.120Z
1676246400120
ZonedDateTime
2023-02-13T00:00:00.120Z
1676246400120
SimpleDateFormat+Date
1676246400012
1676217600012