java时区和时间的关系_Java 时间、日期与时区的关系

简介

本文主要是对Java中常用的时间类做一下梳理,包括Java 8中新增的日期/时间类等,以及它们和时区的关联性

Date / Calendar

java.util.Date 是最常用的类之一,它的精度为毫秒,因为它的有些地方不合理,后来出现了Calendar来替代。java.util.Date 本身存储的是时间戳(1970年1月1日 00:00:00 GMT以来此对象表示的毫秒数 ),所以它和时区地域是无关的,只是在显示的时候加载了TimeZone来调整了时间的显示。

Calendar的getInstance()方法有参数为TimeZone和Locale的重载,可以使用指定时区和语言环境获得一个日历。无参则使用默认时区和语言环境获得日历。

public static Calendar getInstance(){

return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));

}

// 重载的带有时区的方法

public static Calendar getInstance(TimeZone zone){

return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));

}

我们来看下如下的代码

public class Te {

public static void main(String[] args) throws ParseException {

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// 这边只是指定了这个SimpleDateFormat的时区为GMT时区,系统本身的时区还是默认的时区(中国时区)

dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

Date date = new Date(1525518893403L);// 中国时间:2018-5-5 19:14:53

System.out.println(dateFormat.format(date));

// 字符串没有时区信息

String dateStr = "2018-05-05 19:14:53";

Date newDate = dateFormat.parse(dateStr);

System.out.println(newDate);

System.out.println(dateFormat.format(newDate));

}

}

output:

2018-05-05 11:14:53

Sun May 06 03:14:53 CST 2018 (对应的值为:2018-05-06 03:14:53)

2018-05-05 19:14:53

从上面的结果可以知道,Date是不带时区信息,所以在dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); 后,输出的时间就是GMT时区的时间。

字符串的值被认为是GMT时间,所以newDate显示的时间是字符串时间 +8小时后的时间,从第三行输出也印证了这一点。

可以看到,上面的输出结果可能和我们预想的并不一致,Calendar 类作为新的类,没有那么复杂

public class Te {

public static void main(String[] args) throws ParseException {

Date date = new Date(1525518893403L);// 中国时间:2018-5-5 19:14:53

System.out.println(date);

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

calendar.setTime(date);

System.out.println(calendar.getTime());

System.out.println(calendar.get(Calendar.YEAR) + "-" + calendar.get(Calendar.MONTH) + "-" +

calendar.get(Calendar.DAY_OF_MONTH) + " " +

calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" +

calendar.get(Calendar.SECOND));

}

}

output:

Sat May 05 19:14:53 CST 2018

Sat May 05 19:14:53 CST 2018

2018-4-5 11:14:53

可以看到,我们在使用Calendar的时候,获取时间不能直接使用getTime(),因为其返回的是一个Date,而Date是没有时区信息的,应该使用calendar.get()方法。

java.sql.Date / java.sql.Timestamp

这两个类都和数据库有关系,看报名就知道了。且他们都是java.util.Date 的子类。因此,类似的,他们也都没有时区信息。

java.sql.Date 是只保留年月日,而没有时分秒信息,对应数据库(eg. mysql)中的date类型.

java.sql.Timestamp 精确到纳秒,对应数据库(eg.mysql)中的timestamp类型

#java8 新增的日期时间类

Instant:瞬时实例。

LocalDate:本地日期,不包含具体时间。例如:2014-01-14可以用来记录生日、纪念日、加盟日等。

LocalTime:本地时间,不包含日期。

LocalDateTime:组合了日期和时间,但不包含时差和时区信息。

ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差。

Instant

Instant 以Unix时间戳的形式存储日期时间 ,精确到纳秒

// 获取当前的时间戳

Instant timestamp = Instant.now();

System.out.println(timestamp);

// 类似的,从指定的时间戳生成 Instant

Instant specificTime = Instant.ofEpochMilli(System.currentTimeMillis());

System.out.println(specificTime);

output:

2018-05-05T12:44:54.037Z

2018-05-05T12:44:54.195Z

Instant 和Date类似,没有时区信息(也可以认为是0时区,即GMT时区)

ZonedDateTime

java8 把时区也分离出来了,现在转换时区很方便。如果要显示指定的时区,可以使用 ZonedDateTime

ZonedDateTime result=ZonedDateTime.ofInstant(Instant.now(),ZoneId.systemDefault());

System.out.println(result);

// ZonedDateTime 底层就是用Instant存储的

System.out.println(result.toInstant());

output:

2018-05-05T20:52:04.096+08:00[Asia/Shanghai]

2018-05-05T12:52:04.096Z

下面这个例子是时区的转换

//获取当前时区的日期时间

ZonedDateTime now = ZonedDateTime.now();

System.out.println(now);

System.out.println(now.withZoneSameInstant(ZoneId.of("America/New_York")));

//获取美国洛杉矶时区的日期时间,写这段代码的时候,北京时间是 2018-05-05 21:53:26,下面等于是生成了了纽约时间 2018-05-05 21:53:26。因为ZonedDateTime底层是用Instant存储的,所以USANow内的Instant的值和上面now的Instant值是不相等的。

ZonedDateTime USANow = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("America/New_York"));

System.out.println(USANow);

System.out.println(USANow.withZoneSameInstant(ZoneId.systemDefault()));

output:

2018-05-05T21:53:26.322+08:00[Asia/Shanghai]

2018-05-05T09:53:26.322-04:00[America/New_York]

2018-05-05T21:53:26.356-04:00[America/New_York]

2018-05-06T09:53:26.356+08:00[Asia/Shanghai]

相比与之前的时区转换,ZonedDateTime的操作是简便了很多,更便于理解

LocalDate / LocalTime

如上面介绍的所示,一个只有日期,一个只有时间,两者都是没有指定时区的 ​```java LocalDate today = LocalDate.now(); System.out.println(today);

LocalTime now = LocalTime.now(); System.out.println(now);

output: 2018-05-05 21:00:27.979

LocalDate还提供了很多有用的方法

​```java

// 构造日期

LocalDate date = LocalDate.of(2016, 4, 18);

LocalDate date2 = LocalDate.of(2016, 5, 18);

//比较两者相等

if (!date.equals(date2)) {

System.out.printf("date %s 和 date2 %s 不是同一天!%n", date, date2);

}

LocalDateTime是两者的聚合体,这里就不写了,这些类都有一些很好用的方法,查API文档即可,这里就不浪费时间记述了,浪费大家的时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值