在软件开发领域,准确无误地处理日期和时间信息是构建稳定、可靠应用程序的关键一环。随着技术的演进,Java作为一门广泛应用的编程语言,其处理日期和时间的API也经历了显著的变化和发展,旨在为开发者提供更为强大、灵活且易用的工具集。从最初的
java.util.Date
和Calendar
,到Java 8中革命性的新日期时间API,每一次进步都标志着Java在时间处理方面的成熟与完善。本文将深入探讨Java中处理日期和时间的相关API,从基础概念到高级应用,引导您掌握高效、精确地操作日期时间数据的方法,从而在编码实践中告别时间处理的烦恼,迈向更高层次的编程体验。
在我们的实际开发中,日期和时间是非常常用的,例如用户的注册、数据的增删改、对敏感信息的操作等等都需要记录下日期和时间。那我们接下来,就来了解一下其中的相关内容吧。
一、什么是日期和时间
日期指的是某一天,例如:
- 2022-11-18:2022 年 11 月 18 日;
- 2021-6-14:2021 年 6 月 14 日。
时间就是指某一个时刻,它分为两种,一种是带日期的时间,另外一种是不带日期的时间,例如:
- 2022-10-24 08:30:23:2022 年 10 月 24 日 8 时 30 分 23 秒;
- 11:22:33:11 时 22 分 33 秒。
二、什么是时区
我们在初中地理知识中学过,地球上的不同地区是有时差的,因此想要准确定位一个时刻,还需要加上时区。
时区有以下 3 种表示方式:
- GMT 或者 UTC 加时区偏移表示:例如:GMT+08:00 或者 UTC+08:00 表示东八区;
- 缩写表示:例如:CST 表示 China Standard Time(中国标准时间),但是此缩写也可表示 Central Standard Time USA(美国中部时间),容易混淆不推荐使用;
- 洲 / 城市:例如:Asia/Shanghai 表示上海所在地的时区。注意城市名称不是任意的城市,而是由国际标准组织规定的城市。
你还在为找不到真正免费的编程学习网站而苦恼吗?来云端源想编程社区,编程课程视频,项目实战,在线编程,在学习过程中有什么问题还可以免费咨询在线老师,源想桌面,让编程更有创造性,创作空间,梳理知识,让知识创造财富,快去看看吧。
三、Date 类的使用
在 JDK 的 java.util 包中,提供了一个 Date 类用于表示日期和时间。java.util.Date 类日期表示特定的时间瞬间,精度为毫秒。随着 JDK 版本的不断升级和发展,Date 类中大部分的构造方法和普通方法都已经不再推荐使用。目前 JDK 8 中,Date 类只有两个构造方法是可以使用的。
我们下面来看一下这个类的构造方法和常用方法。
3.1 构造方法
- Date():创建一个对应当前时间的日期对象;
- Date(long date):创建指定毫秒数的日期对象。
由于其他 4 个构造方法已经过期,这里我们不进行介绍。
3.2 实例
创建日期对象,并打印 toString() 方法的结果:
import java.util.Date;
public class DateDemo1 {
public static void main(String[] args) {
// 实例化一个date对象
Date date = new Date();
// 调用 toString() 方法
String s = date.toString();
System.out.println(s);
}
}
运行结果:
Wed Jun 10 10:21:10 CST 2020
我执行代码的时间是 2020 年 06 月 10 日 10:22:10 星期三,因此得到了如上的运行结果。
调用 getTime() 方法获取当前日期对象自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数:
import java.util.Date;
public class DateDemo2 {
public static void main(String[] args) {
// 实例化一个date对象
Date date = new Date();
// 调用 getTime() 方法
long time = date.getTime();
System.out.println(time);
}
}
运行结果:
1591755946922
3.3、 补充说明
对于 Date 类,只需要了解如何通过创建对象封装时间值即可。由于 Date 类在设计之初,没有考虑到国际化的问题,因此从 JDK1.1 开始,Date 类相应的功能也被 Calendar 类中的方法取代。
四、 Calendar 类的使用
- Calendar 类用于完成日期和时间字段的操作,它可以通过特定的方法设置和读取日期的特定部分,比如年、月、日、时、分和秒等。
- Calendar 类是一个抽象类,不可以被实例化。
- 在程序中需要调用其静态方法 getInstance()来得到一个 Calendar 对象,然后才能调用其相应的方法。
Calendar calendar = Calendar.getInstance();
4.1 实例化
由于 Calendar 类是一个抽象类,不能直接实例化,想要获取其实例对象通常有两种方法:
- 使用 Calendar.getInstance() 方法(更常用);
- 调用它的子类的 GregorianCalendar 的构造方法。
实例如下:
Calendar calendar = Calendar.getInstance();
4.2 常用方法
- static Calendar getInstance():使用默认时区和区域设置获取日历;
- int get(int field):返回给定日历字段的值;
- void set(int field, int value):将给定的日历字段设置为给定值。(此外,set() 还有很多重载方法)
更多常用方法和静态字段请查阅官方文档。
4.3 实例
4.3.1 get () 方法实例
import java.util.Calendar;
public class CalendarDemo1 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
// 获取今天是这一周的第几天
int i = calendar.get(Calendar.DAY_OF_WEEK);
// 获取今天是这一月的第几天
int i1 = calendar.get(Calendar.DAY_OF_MONTH);
// 获取今天是这一月的第几周
int i2 = calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH);
// 获取今天是这一年的第几天
int i3 = calendar.get(Calendar.DAY_OF_YEAR);
System.out.println("今天是这一周的第" + i + "天");
System.out.println("今天是这一月的第" + i1 + "天");
System.out.println("今天是这一月的第" + i2 + "周");
System.out.println("今天是这一年的第" + i3 + "天");
}
}
运行此段代码的时间是 2020 年 06 月 10 日,运行结果如下:
今天是这一周的第4天
今天是这一月的第10天
今天是这一月的第2周
今天是这一年的第162天
通过调用 get() 方法,我们很方便地获取到了当前时间在日历上是第几天。要特别注意的是,获取月份,返回的值是从 0 开始的(0 ~ 11),依次表示 1 月到 12 月;获取一周的第 n 天,这里的返回值为 1~7,1 表示周日,2 表示周一,以此类推。
4.3.2 set () 方法实例
import java.util.Calendar;
public class CalendarDemo2 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
// 设置2022年:
calendar.set(Calendar.YEAR, 2022);
// 设置9月: (8表示9月)
calendar.set(Calendar.MONTH, 8);
// 设置9日:
calendar.set(Calendar.DATE, 9);
// 设置时间:
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
System.out.println(calendar.getTime().toString());
}
}
运行结果:
Fri Sep 09 00:00:00 CST 2022
上面代码分别设置了日历的年、月、日、时、分、秒,Calendar.getTime() 可以将一个 Calendar 对象转换成 Date 对象,最后再打印这个对象。
五、Java8 后新的日期和时间 API
5.1 为什么要提供新的 API
JDK 1.0 中包含了 一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用 了。而 Calendar 并不比 Date 好多少。它们面临的问题是:
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date 中的年份是从 1900 开始的,而月份都从 0 开始。
格式化:格式化只对 Date 有用,Calendar 则不行。 此外,它们也不是线程安全的;不能处理闰秒等。 总结:对日期和时间的操作一直是 Java 程序员最痛苦的地方之一。
在 Java8 以后,提供了新的日期和时间 API,旧 API 的如下缺点得到了解决:
- 可变性:旧的 API 日期和时间是可变的,日期和时间这样的类应该是不可变的;
- 偏移性:Date 中的年份是从 1990 年开始,月份是从 0 开始,星期天是用 1 表示的,不了解 API 的开发者很容易用错;
- 格式化:SimpleDateFormat 只能用于格式化 Date 类型,不能格式化 Calendar 类型。
5.2 新 API 概述
Java 8 的日期时间 API 吸取了 Joda-Time 的精华,提供了更优秀易用的 API,位于 java.time 包中,包含了 LocalTime(本地时间)、LocalDate(本地日期)、LocalDateTime(本地日期时间)、ZonedDateTime(带时区的日期时间)和 Duration(时间间隔)类。
而 java.util.Date 类下面增加了 toInstant() 方法,用于把 Date 转换为新的类型。这些 API 大大简化了日期时间的运算。
对偏移性的不合理设计也有修正:月份使用 1~12 表示 1 月 到 12 月,星期使用 1 ~ 7 表示星期一到星期天。
另外,使用了新的 DateTimeFormatter 来取代旧的 SimpleDateFormat。
5.3 LocalDateTime 相关类的使用
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeDemo1 {
public static void main(String[] args) {
// 获取当前日期
LocalDate localDate = LocalDate.now();
// 获取当前时间
LocalTime localTime = LocalTime.now();
// 获取当前日期和时间
LocalDateTime localDateTime = LocalDateTime.now();
// 打印
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);
}
}
运行结果:
2020-06-10
14:17:48.618294
2020-06-10T14:17:48.618421
在实际开发中,LocalDateTime 相较于 LocalDate 和 LocalTime 更加常用。
本地日期和时间通过 now() 获取到的总是以当前默认时区返回的。
另外,可以使用 of() 方法来设置当前日期和时间:
// 2020-9-30
LocalDate date = LocalDate.of(2020, 9, 30);
// 14:15:10
LocalTime time = LocalTime.of(14, 15, 10);
// 将date和time组合成一个LocalDateTime
LocalDateTime dateTime1 = LocalDateTime.of(date, time);
// 设置 年、月、日、时、分、秒
LocalDateTime dateTime2 = LocalDateTime.of(2020, 10, 21, 14, 14);
六、小结
通过本文章的学习,我们知道了日期、时间和时区的基本概念,在 Java 8 之前,通过 Date 类、Calendar 类以及 SimpleDateFormat 类来操作日期和时间,Java 8 以后,java.time 包下新增了一批新的日期时间 API,修复了旧 API 的一些缺点,简化了开发者操作日期和时间的难度。本小节内容比较简单,梳理了 Java 对于日期时间处理的相关 API,大家参照文档,加以练习即可。