一、使用Calendar/SimpleDateFormat转换
使用条件:jdk1.1+
Calendar
Calendar对象内部是包含时区对象的(TImeZone);所以可以通过它来转换
Calendar cal = Calendar.getInstance();
System.out.println("Date01 : " + cal.getTime());
cal.setTimeZone(TimeZone.getTimeZone("GMT+09:00"));
// 方式一(常规方式):自己拼时间,get方法内部会计算时区offset值 从而获取正确时区的时间
System.out.println("Date02 : " + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND));
System.out.println("========new Calendar==========");
Calendar cal1 = Calendar.getInstance();
System.out.println("Date01 : " + cal1.getTime());
cal1.setTimeZone(TimeZone.getTimeZone("GMT+09:00"));
// 方式二:先设置一下时间 任意字段;然后直接获取时间即可。 set方法执行后 会重置时间计算标识 getTime时就会根据时区重新计算时间
cal1.set(Calendar.YEAR, 2023);
System.out.println("Date02 : " + cal1.getTime());
SimpleDateFormat
format对象内部也是使用calendar来做转换
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT+09:00"));
// sysTimeZone的Date 转换为 +9 时区的时间字符串
sdf.format(new Date());
// +9 时区的时间字符串 转换为 sysTimeZone的Date对象
sdf.parse("2023-07-19 08:11:00");
二、使用ZonedDateTime转换
使用条件:jdk8+
ZoneDateTime 基本等于LocalDateTime + ZoneId 即带时区的LocalDateTime;
其内部封装了时区转化的函数,拿来即用。
// localDateTime
LocalDateTime.now().atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC+09:00")).toLocalDateTime();
// instant
Instant.now().atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC+09:00")).toLocalDateTime();
// util.Date
new Date().toInstant().atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC+09:00")).toLocalDateTime();
// Calendar
Calendar.getInstance().getTime().toInstant().atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC+09:00")).toLocalDateTime();
// zonedDateTime
ZonedDateTime.now(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC+09:00")).toLocalDateTime();
注意 : atZone的区别
Instant.atZone 记录时区+转换时间
LocalDateTime.atZone 仅记录时区 (类似ZonedDateTime.withZoneSameLocal)
三、利用时间戳类转换
最为灵活的一种方式
使用条件:jdk8+
利用时间戳(Instant类)与时区无关的特性来计算。即任何地区取到的时间戳都一致!
解释下时间戳:
指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,注意“现在”这个词。
如果是格林威治时间 ,现在指的是格林威治当前的时间;
如果是北京时间,现在指的是北京当前的时间。
// Date 系统时区 > 其他时区
Instant instant = new Date().toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of(timeZone));
Date convertedDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
// Date 其他时区 > 系统时区
LocalDateTime originalLocalDateTime = ((Date) originalDate).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
Date convertedDate = Date.from(originalLocalDateTime.toInstant(offset));
// LocalDateTime 系统时区 > 其他时区
Instant instant = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
LocalDateTime.ofInstant(instant, ZoneId.of(timeZone));
// LocalDateTime 其他时区 > 系统时区
Instant originalInstant = LocalDateTime.now().toInstant(offset);
LocalDateTime.ofInstant(originalInstant, ZoneId.systemDefault());
- 注意:util.Date对象其实就是个时间点且不含时区,他的toString方法是能看到时区相关的内容是具有误导性的,其内部并无时区相关的对象。
- 同样是toInstant LocalDateTime和Date的区别
LocalDateTime.toInstant(ZoneOffset) 带时区的特性可以用来计算不同时区的时间戳,而new Date().toInstant() 取得是当前系统时区的时间戳 - Instant 类为时间戳类,toString方法会把当前时间戳格式化,例如当前时间是2023-07-13 18:00:00 而Instant.now() 得到的是2023-07-13 10:00:00 (因为我们是东八区)