JDK8 前后的 Date 日期时间 API
每博一文案
师父说:人只要活在世界上,就会有很多的烦恼,痛苦或是快乐,取决于逆的内心,只要心里拥有温暖灿烂的阳光,
那么悲伤又有什么好畏惧的呢?
人生如行路,一路艰辛,一路风景,路上你会遇到很多艰难险阻,也许你生活得并不富裕,
也许你的工作股不够好,也许你总是爱而不得,但请你一定不要放弃。
这个世界上有温暖,有感动,有柔情,只要用阳光的心态去面对生活,你就能收获一个乐观积极的自己。
用微笑的力量感染周围的人,照亮前进道路上位置的黑暗,去努力成为他们人生路上的太阳。
世界的模样取决于你凝视它的目光,就算再艰难困苦的生活,
只要微笑着撑过去了,就是胜利。
不要放弃拥抱阳光的权力,也不要畏惧内心里的悲伤,温暖一定会将冰冷融化,光明与期许总是相伴而来。
—————— 一禅心灵庙语
文章目录
- JDK8 前后的 Date 日期时间 API
- 每博一文案
- 1. JDK 8 之前: java.util.Date类
- 2. JDK 8 之前 : java.text.SimpleDateFormat类 (字符串<-->日期时间) 日期格式设定
- 3. JDK 8 之前 : java.util.Calendar(日历)
- 4. JDK 8 中的 :LocalDate、LocalTime、LocalDateTime
- 5. JDK 8 中的 : java.time.format.DateTimeFormatter
- 6. Instant 类的使用
- 7. JDK 8 中的 :处理日期时间的工具类: ChronoUnit ,Duration,Period
- 8. 其他的API
- 9. 关于日期时间的算法题
- 10. 总结:
- 11. 最后:
1. JDK 8 之前: java.util.Date类
有两种表示时间的基本方法。
- 人类时间:比如年、月、日、时、分和秒。
- 机器时间:以时间线连续测量时间,从一个称为时代的起点开始,以纳秒为单位。
Date-Time 包提供了丰富的表示日期和时间的类。Date-Time API 中的某些类用于表示机器时间,其他类更适合表示人类时间。
首先确定您需要的日期和时间的哪些方面,然后选择满足这些需求的课程或课程。选择基于时间的课程时, 首先要确定是否需要表示人类时间或机器时间。然后,您可以确定需要表示的时间。你需要一个时区吗? 日期和时间?仅限日期?如果你需要一个日期,你需要月,日和年,或者一个子集?
时间戳: 就是毫秒值,某段时间到 1970年1月1日 0 时 0 分 0 秒 0毫秒 的毫秒值。
Date的构造器: 只有两个,其他的都已经过时了,不推荐使用了。
public Date();
public Date(long date);
举例: 需要注意的是,Date有两个一个是 util包下的另一个是 sql数据库包下的,这里我们导入的是 util下的。
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Date date = new Date(); // 默认获取的当前系统的时间
System.out.println(date);
Date date2 = new Date(0L); // 设置毫秒值(long类型的)时间戳,创建Date对象
System.out.println(date2); // 0L 时间戳:表示的是 1970年1月1日 0时0分0秒 0毫秒
}
}
java.util.Date类中常用的方法
Date类中大多数的方法都是过时了,不推荐使用了。
这里就只有一个比较常用,还没有过时的方法
getTime() : 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。就是Date对象表示的时间到 1970 年 1 月 1 日 00:00:00 GMT 的毫秒值,又称为 “时间戳”。
举例:
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Date date = new Date(); // 默认获取的当前系统的时间
System.out.println(date);
System.out.println(date.getTime()); // 获取到当前系统时间到1970年1月1日 0时0分0秒 0毫秒 的毫秒值
Date date2 = new Date(0L); // 设置毫秒值(long类型的)时间戳,创建Date对象
System.out.println(date2); // 0L 时间戳:表示的是 1970年1月1日 0时0分0秒 0毫秒
System.out.println(date2.getTime());
}
}
举例: 需求: 打印时间原点开始一年之后的时间
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Date d2 = new Date(0L); // 123 默认是 int 类型的,0L 时间戳:表示的是 1970年1月1日 0时0分0秒 0毫秒
// 2. 获取到Date对象的时间戳(毫秒值)
long time = d2.getTime();
// 将这个毫秒值 + 一年的毫秒值
time += 1000L * 60 * 60 * 24 * 365; // 不要将 L long类型给忘记了,不然类型就不对了。
// 4. 通过该增加了一年的时间戳(毫秒值)
d2.setTime(time);
System.out.println(d2);
}
}
1.1 java.sql.Date 类
java.sql.Date 是有关数据库的一个日期时间的类,这里就不多介绍了,这个不是我们的重点。
举例:
如何将包下的 java.util.Date 类型的日期时间 转换为 ————> java.sql.Date 包下的日期时间 ???
思路:
java.util.Date 包下的 与 java.sql.Date 包下 两者之间共同的参数是: 时间戳: 就是毫秒值,某段时间到 1970年1月1日 0 时 0 分 0 秒 0毫秒 的毫秒值。 利用这一点。
创建 java.util.Date 包下的日期类型获取其中的时间戳 作为参数,创建 java.sql.Date 包下的 日期时间。
public class DateTest {
public static void main(String[] args) {
java.sql.Date date = new java.sql.Date(new java.util.Date().getTime());
// new java.util.Date().getTime() 获取到当前系统时间的时间戳:到 1970年1月1日 0 时 0 分 0 秒 0毫秒 的毫秒值。
System.out.println(date);
}
}
错误演示:
public class DateTest {
public static void main(String[] args) {
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(0L);
// 报: java.lang.ClassCastException 类转换异常
sqlDate = (java.sql.Date) utilDate; // 报异常: 将一个不是多态(实例的)的父类对象强制转换为子类对象是报异常的
}
}
将 父类 java.util.Date 强制转换为子类 java.sql.Date 会报类型转换异常,如果可以将父类类型 强制转换为子类类型(不是多态)的话,那子类中该有的成员变量/方法都会没有的,不合理.
可以将 java.sql.Date 转换为 —> java.util.Date 类,因为 java.sql.Date 是 extends 继承了 java.util.Date 类的 多态
public class DateTest {
public static void main(String[] args) {
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(0L);
utilDate = sqlDate;
System.out.println(utilDate);
// 也可以一体化
java.util.Date date = new java.sql.Date(0L); // 注意参数是 long类型,整数默认是 int 类型
System.out.println(date);
}
}
2. JDK 8 之前 : java.text.SimpleDateFormat类 (字符串<–>日期时间) 日期格式设定
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat
类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
- 它允许进行格式化:日期类型 ——> String 字符串类型、解析:字符串类型 ——> 日期类型 。
SimpleDateFormat 构造器:
public SimpleDateFormat(); // 用默认的模式和默认语言环境的日期格式符号构造 SimpleDateFormat。注:此构造方法可能不支持所有语言环境。要覆盖所有地区,请使用 DateFormat 类中的工厂方法
public SimpleDateFormat(String pattern); // 用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat。注:此构造方法可能不支持所有语言环境。要覆盖所有语言环境,请使用 DateFormat 类中的工厂方法
这里我们一般使用 public SimpleDateFormat(String pattern); 这个构造器创建 SimpDateFormat 对象,其中的 pattern 参数表示 日期时间的格式(即是我们字符串表示日期时间的格式,也是我们显示 Date 类型的格式,这两者之间的格式必须一致,不然会报异常。
如下是对应的格式 :
我们先来认识以下几个 格式和解析的方法
- public StringBuffer format(Date date) 表示 将给定的 Date 格式化为日期/时间字符串,并将结果添加到给定的 StringBuffer。StringBuffer 可以转换为 String 类型
- public Date parse(String source) 表示解析字符串的文本,生成 Date。注意会抛出
NullPointerException
- 如果 source为 null。
举例: 格式化: 将给定 Date 转换为 ——> String 字符串类型
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Date date = new Date(); // 默认是当前系统时间
// 指定日期格式,创建 SimpleDateFormat 对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
// 将 Date 转换为 String 类型
String str = simpleDateFormat.format(date);
System.out.println(str);
// 或者
// 指定日期格式,创建 SimpleDateFormat 对象
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("YYYY年MM月dd日 hh时mm分ss秒");
// 将 Date 转换为 String 类型
String str2 = simpleDateFormat2.format(date);
System.out.println(str2);
}
}
举例: 解析: 将String 类型 ——> Date 类型 :注意String 类型的格式要和创建SimpleDateFormat 对象的格式要一致,不然包异常
public class DateTest {
public static void main(String[] args) {
String str = "2023-1-20 21:00:01";
String str2 = "2023年1月20日 22时06分00秒";
Date date = null;
Date date2 = null;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("YYYY年MM月dd日 hh时mm分ss秒");
try {
date = simpleDateFormat.parse(str);
date2 = simpleDateFormat2.parse(str2);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date);
System.out.println(date2);
}
}
**如果字符串日期的格式 与 SimpleDateFormat 设定的格式不一致报异常: **
3. JDK 8 之前 : java.util.Calendar(日历)
Calendar 是一个抽象类,主用用于完成日期字段之间相互操作的功能。
** abstract
抽象类是无法 new 的,所以如何创建对象 ???**
- 使用 Calendar.getInstance() 静态方法,抽象类中的静态方法,不能被继承,不能被重写,仅仅只能其抽象类自己使用,通过 类名.方法名() 直接调用。像不像单例模式。
- 调用它的子类
GregorianCalendar
的构造器 多态性
Calendar 底层原理: 会根据系统的不同时区来获取不同的日历对象,默认表示当前系统时间。
其中会把时间中的 纪元,年,月,日,时,分,秒,星期 等等的都放到一个数组当中。
细节:
- 月份:范围: 0~11 如果获取出来的 0 那么实际上就是我们中国的 1 月。
- 星期:在老外的眼里:星期日是一周中的第 1 天,1(星期日),2(星期一),3(星期二),4(星期三),5(星期四),6(星期五),7(星期六)
常用的方法如下:
- public int get(int field)
通过对应的常量获取到对应的数组下标中记录的信息
举例:
import java.util.Calendar;
public class CalendarTest {
public static void main(String[] args) {
// 调用 Calendar.getInstance() 类方法(静态方法)/创建 Calendar 对象
Calendar calendar = Calendar.getInstance(); // 默认是当前系统的时间
int month = calendar.get(Calendar.MONTH); // 获取到Calendar 对象中的月份
int year = calendar.get(Calendar.YEAR); // 获取到Calendar 对象中的年
int date = calendar.get(Calendar.DATE); // 获取到Calendar 对象中的天数
System.out.println(month);
System.out.println(year);
System.out.println(date);
}
}
- public void set(int field, int value) 表示修改 Calendar 对象中的日历中的某个字段信息,如:年,月,日
- public abstract void add(int field, int amount) 表示:根据日历的规则,为给定的日历字段添加或减去指定的时间量。如:年,月,日
举例:
import java.util.Calendar;
public class CalendarTest {
public static void main(String[] args) {
// Calendar.getInstance() 类方法(静态方法)/创建 Calendar 对象
Calendar calendar = Calendar.getInstance(); // 默认是当前系统的时间。
System.out.println(calendar);
System.out.println(calendar.get(Calendar.YEAR)); // 获取 Calendar 对象的年份
calendar.set(Calendar.YEAR, 2000); // 修改 Calendar 对象的年份
System.out.println(calendar.get(Calendar.YEAR));
calendar.add(Calendar.YEAR, 1); // 添加 1 年
System.out.println(calendar.get(Calendar.YEAR)); // 获取Calendar 对象的年份
calendar.add(Calendar.YEAR, -2); // 减少 2 年
System.out.println(calendar.get(Calendar.YEAR)); // 获取Calendar 对象的年份
}
}
4. JDK 8 中的 :LocalDate、LocalTime、LocalDateTime
日期时间在计算机实际记录的是一个毫秒值 :long 类型的时间戳, 仅仅只是适用于计算机解读。
但是却不利于,人类阅读。
就比如: 如果我们跟别人说:“我们在88988902399323”见面,别晚了了,那么就很难让人明白了。
我们希望时昼夜和四季有关,这样就利于我们人类自身阅读了,但是这样事情就变的复杂了,因为: JDK1.0 中包含了一个 java.util.Date
类,但是它的大多数方法已经在JDK 1.1 引入了 Caledar 类之后被弃用了。而 Calendar 并不比 Date 好多少。
它们面临的问题是:
JDK8之前的 与 JDK8之后的区别
- **可变性:**像日期和时间这样的类应该是不可变的
- **偏移性:**Date 中的年份是从 1970 开始的,而月份也是老外的 0 开始,
- 格式化: 只对Date 有用,Calendar 则不行,此外,它们也不是线程安全的,不能处理闰秒 等
第三次引入的API是成功的,并且 Java 8中引入的 java.time
API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。 新的java.time
中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)
和持续时间(Duration)
的类。历史悠久的 Date 类新增了 toInstant()
方法, 用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简 化了日期时间和本地化的管理。
新时间日期API
java.time
– 包含值对象的基础包
java.time.chrono
– 提供对不同的日历系统的访问
java.time.format
– 格式化和解析时间和日期
java.time.temporal
– 包括底层框架和扩展特性
java.time.zone
– 包含时区支持的类
说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
所以这里我们认识一些常用的就可以了。
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变
的对象,分别表示使用 ISO-8601
日历系统的日期、时间、日期和时间。
ISO-8601:日历系统是国际标准化组织制定的现代公民的日期和时间的表示 法,也就是公历
它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
- LocalDate 代表IOS格式(yyyy-MM-dd)的日期(年,月,日) 没有时分秒,可以存储 生日、纪念日等日期。
- LocalTime 表示一个时间(时,分,秒) ,而不是日期,也就是没有 年月日。
- LocalDateTime 是用来表示日期(年月日)和时间(时分秒)的,这是一个最常用的类之一。是 LocalDate ,LocalTime。
4.1 LocalDate,LocalTime,LocalDateTime 常用的方法
LocalDate ,LocatTime,LocalDateTime 这三者的常用的方法基本上相似的,所以这里我们就放在一起讲解了。
4.1.1 now() 类方法
首先创建对象,调用其中的方法。但是 LocalDate , LocalTime,LocalDateTime 这三者是没有构造器的。
而是调用其中的 now()
静态方法,创建对应的对象。
public static LocalDate now(); // 默认创建当前系统日期(年月日)的 LocalDate对象
public static LocalTime now(); // 默认创建当前系统时间(时分秒)的 LocalTime对象
public static LocalDateTime now(); // 默认创建当前系统日期时间(年月日时分秒) LocalDateTime 对象
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class JDK8Date {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now(); // 静态方法获取到当前系统日期(年月日) localDate对象
System.out.println(localDate);
LocalTime localTime = LocalTime.now(); // 静态方法获取到当前系统时间(时分秒) localTime对象
System.out.println(localTime);
LocalDateTime localDateTime = LocalDateTime.now(); // 静态方法获取当前系统日期时间 LocalDateTime 对象
System.out.println(localDateTime);
}
}
4.1.2 of( ) 类方法
LocalTime,LocalDate,LocalDateTime 类的 of 方法:
public static LocalTime of(int hour,int minute,int second); // 设置指定的时,分,秒 创建 LocalTime对象
public static LocalDate of(int year,int month,int dayOfMonth); // 设置指定的 年,月,日 创建 LocalDate对象
public static LocalDateTime of(int year,int month,int dayOfMonth,int hour,int minute,int second); // 设置指定的年,月,日,时,分,秒 创建 LocalDateTime 对象
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class JDK8Date {
public static void main(String[] args) {
LocalTime localTime = LocalTime.of(15,20,36);
LocalDate localDate = LocalDate.of(2023,1,20);
LocalDateTime localDateTime = LocalDateTime.of(2023,1,20,15,20,36);
System.out.println(localTime);
System.out.println(localDate);
System.out.println(localDateTime);
}
}
4.1.3 getxxx( ) 对象方法
LocalTime,LocalDate,LocalDateTime 类的 getXXX() 方法: 获取对应对象中的年,月,日,时,分,秒,星期几
public DayOfWeek getDayOfWeek();
public int getYear(); // 获取年
public Month getMonth(); // 获取月份
public int getHour(); // 获取小时
public int getMinute(); // 获取分钟
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class JDK8Date {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now(); // 静态方法获取到当前系统日期(年月日) localDate对象
System.out.println(localDate.getDayOfYear()); // 获取年份
LocalTime localTime = LocalTime.now(); // 静态方法获取到当前系统时间(时分秒) localTime对象
System.out.println(localTime.getHour()); // 获取小时
LocalDateTime localDateTime = LocalDateTime.now(); // 静态方法获取当前系统日期时间 LocalDateTime 对象
System.out.println(localDateTime.getDayOfWeek()); // 获取星期
}
}
4.1.4 with() 修改 withDayOfMonth()/withDayOfYear()/withMonth()/withYear()
LocalTime,LocalDate,LocalDateTime 类的 WithXXX() 方法: 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
public LocalTime withHour(int hour); // 返回这个LocalTime的副本对象,并更改日期值,不可变
public LocalDate withYear(int year); // 返回此日期的副本,并更改年份。 如果一年中的日期无效,它将被更改为该月的最后一个有效日期。
public LocalDateTime withMonth(int month); // 返回此年份更改的LocalDateTime的副本。 时间不影响计算,结果将相同。 如果一年中的日期无效,它将被更改为该月的最后一个有效日期。
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class JDK8Date {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now(); // 静态方法获取到当前系统日期(年月日) localDate对象
System.out.println(localDate);
LocalDate localDate2 = localDate.withYear(2020); // 修改年份,,不可变,返回一个新的LocalDate对象
System.out.println(localDate2);
LocalTime localTime = LocalTime.now(); // 静态方法获取到当前系统时间(时分秒) localTime对象
System.out.println(localTime);
LocalTime localTime2 = localTime.withHour(20); // 修改小时,不可变,返回一个新的LocalTime对象
System.out.println(localTime2);
LocalDateTime localDateTime = LocalDateTime.now(); // 静态方法获取当前系统日期时间 LocalDateTime 对象
System.out.println(localDateTime);
LocalDateTime localDateTime2 = localDateTime.withMonth(6); // 修改月份,不可变,返回一个新的LocalDateTime对象
System.out.println(localDateTime2);
}
}
4.1.5 plusXXX() 和 / minuXXX()
- plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours(): 向当前对象添加几天、几周、几个月、几年、几小时
- minusMonths() , minusWeeks(),minusDays(),minusYears(),minusHours() :从当前对象减去几月、几周、几天、几年、几小时
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class JDK8Date {
public static void main(String[] args) {
// 不可变性: 不是从原本的对象上修改的,而是返回一个新键修改的对象
LocalDate localDate = LocalDate.now(); // 静态方法获取到当前系统日期(年月日) localDate对象
System.out.println(localDate);
LocalDate localDate2 = localDate.plusYears(1); // 增加 1 年份,,不可变,返回一个新的LocalDate对象
System.out.println(localDate2);
LocalDate localDate3 = localDate.minusYears(1); // 减去 1 年份,,不可变,返回一个新的LocalDate对象
System.out.println(localDate3);
LocalTime localTime = LocalTime.now(); // 静态方法获取到当前系统时间(时分秒) localTime对象
System.out.println(localTime);
LocalTime localTime2 = localTime.plusHours(20); // 增加 20 小时,不可变,返回一个新的LocalTime对象
System.out.println(localTime2);
LocalTime localTime3 = localTime.minusHours(20); // 减少 20 小时,不可变,返回一个新的LocalTime对象
System.out.println(localTime3);
LocalDateTime localDateTime = LocalDateTime.now(); // 静态方法获取当前系统日期时间 LocalDateTime 对象
System.out.println(localDateTime);
LocalDateTime localDateTime2 = localDateTime.plusMonths(6); // 增加 6 月份,不可变,返回一个新的LocalDateTime对象
System.out.println(localDateTime2);
LocalDateTime localDateTime3 = localDateTime.minusMonths(6); // 减少 6 月份,不可变,返回一个新的LocalDateTime对象
System.out.println(localDateTime3);
}
}
5. JDK 8 中的 : java.time.format.DateTimeFormatter
java.time.format.DateTimeFormatter
类:该类提供了三种格式化方法:
-
预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
-
本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
-
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
常用的方法:
- public static DateTimeFormatter ofPattern(String pattern) :静态方法,返回一个指定字符串格式/日期时间格式的 DatTimeFormatter 一般是使用该方法,创建 DateTimeFormatter 对象的。
- public String format(TemporalAccessor temporal) : 将对应格式的日期时间 ——> 转换为 字符串类型
- public TemporalAccessor parse(CharSequence text) : 将对应格式的字符串的格式 ——> 转换为 日期时间类型。
- 注意: 字符串的格式 与 日期时间类型的格式是要保持一致的,不然报异常
java.time.format.DateTimeParseException
**预定义的标准格式。如:**ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME 进行格式化,和解析
举例:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class JDKDateTimeFormatter {
public static void main(String[] args) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
// 格式化: 将日期 --> 字符串类型
LocalDateTime localDateTime = LocalDateTime.now(); // 当前系统的时间
String str = dateTimeFormatter.format(localDateTime); // 将日期 --> 字符串类型
System.out.println(str);
// 解析: 将字符串 --> 日期时间类型
String str2 = "2019-02-18T15:42:18.797"; // 注意格式:日期时间的格式 要 和字符串的格式 一致,不然报异常
TemporalAccessor temporalAccessor = dateTimeFormatter.parse(str2);
System.out.println(temporalAccessor);
}
}
第二种格式就不介绍了,我们这里直接介绍第三种方式,自定义的方式,这种方式才是我们开发中经常用的方式。
自定义格式
举例:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class JDKDateTimeFormatter {
public static void main(String[] args) {
// 重点: 方式三: 自定义的格式,如: ofPattern("yyy-MM-dd hh:mm:ss")
// 将日期 ---> 字符串
// 创建自定义格式的 DateTimeFormatter 对象的实例
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String s = formatter.format(LocalDateTime.now()); // LocalDateTime.now()默认是当前系统时间的LocalDateTime对象
System.out.println(s);
// 将字符串 ————> 日期
TemporalAccessor parse = formatter.parse("2019-09-07 02:09:09"); // 注意格式需要对应起来,
System.out.println(parse);
}
}
6. Instant 类的使用
Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
-
在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是 时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中, 也是从1970年开始,但以毫秒为单位。
-
java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间 单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。 概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒 数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
-
(1 ns = 10 ^ -9 s) 1秒 = 1000毫秒 =106微秒=109纳秒
时间戳:
是指格林威治时间 1970 年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
Instant 没有构造器,通过 now() 静态方法 创建 Instant 对象
public static Instant now(); // 默认返回的当前系统的日期时间的 Instant 对象
举例:
import java.time.Instant;
public class InstantTest {
public static void main(String[] args) {
// 通过 Instant.now() 创建 Instant 对象
Instant instant = Instant.now(); // 默认是当前系统的日期时间
System.out.println(instant);
}
}
Instant 常用的方法
- public static Instant ofEpochMilli(long epochMilli) :表示静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象
- public long toEpochMilli() : 表示 返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳
举例:
import java.time.Instant;
public class InstantTest {
public static void main(String[] args) {
Instant instant = Instant.ofEpochMilli(1000);
System.out.println(instant);
// 获取当前时间到 1970年1月1日0时0分0秒
Instant instant2 = Instant.now();
long toEpochMilli = instant2.toEpochMilli();
System.out.println(toEpochMilli); // 获取到对应 Instant 对象中的时间戳,毫秒值
}
}
7. JDK 8 中的 :处理日期时间的工具类: ChronoUnit ,Duration,Period
- Duraiton: 在测量机器时间的情况下,Duration 最合适,例如使用 Instant 对象的代码。Duration 对象以秒或纳秒度量, 不使用基于 Date 的结构,如年、月和日,尽管类提供了转换为天数、小时和分钟的方法。 Duration 用于计算两个 “时间” 间隔(秒,纳秒) 。
举例:
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class DurationPeriodChrono {
public static void main(String[] args) {
// 创建当前系统时间的 LocalDateTime 对象
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
// 创建指定时间的 LocalDateTime 对象
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 0, 00, 00);
System.out.println(birthDate);
// 创建Duration 计算两个“时间” 间隔的工具对象。
Duration duration = Duration.between(birthDate, today); // 第二个参数 - 第一个参数
System.out.println("相差的时间间隔对象: " + duration);
System.out.println(duration.toDays()); // 两个时间差的天数
System.out.println(duration.toHours()); // 两个时间差的小时数
System.out.println(duration.toMinutes()); // 两个时间差的分钟数
System.out.println(duration.toMillis()); // 两个时间差的毫秒数
System.out.println(duration.toNanos()); // 两个时间差的纳秒数
}
}
ChronoUnit : 大多基于 temporal 对象都提供了一个无参数的 now()
方法,它提供了使用系统时钟和默认时区的当前日期和时间。 这些基于时间的对象还提供了一个单参数 now (clock) 方法, 允许您传入另一个时钟。ChronoUnit 用于计算两个 “日期” 间隔
举例:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class DurationPeriodChrono {
public static void main(String[] args) {
// 获取当前系统日期时间的 LocalDateTime 对象
LocalDateTime today = LocalDateTime.now();
System.out.println(today);
// 创建自定义日期时间的 LocalDateTime对象
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
System.out.println(birthDate);
System.out.println("相差的年数: " + ChronoUnit.YEARS.between(birthDate, today));
System.out.println("相差的月数: " + ChronoUnit.MONTHS.between(birthDate, today));
System.out.println("相差的周数: " + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数: " + ChronoUnit.DAYS.between(birthDate, today));
System.out.println("相差的时数: " + ChronoUnit.HOURS.between(birthDate, today));
System.out.println("相差的分钟数: " + ChronoUnit.MINUTES.between(birthDate, today));
System.out.println("相差的秒数: " + ChronoUnit.SECONDS.between(birthDate, today));
System.out.println("相差的毫秒数: " + ChronoUnit.MILLIS.between(birthDate, today));
System.out.println("相差的纳秒数: " + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的微秒数: " + ChronoUnit.MICROS.between(birthDate, today));
System.out.println("相差的半天数: " + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的十年数: " + ChronoUnit.DECADES.between(birthDate, today));
System.out.println("相差的世纪(百年)数: " + ChronoUnit.CENTURIES.between(birthDate, today));
System.out.println("相差的千年数: " + ChronoUnit.MILLENNIA.between(birthDate, today));
System.out.println("相差的纪元数: " + ChronoUnit.ERAS.between(birthDate, today));
}
}
Period: 要用基于日期的值(年、月、日)来定义大量的时间,使用周期类。周期类提供了各种 get 方法, 例如 getMonths
, getDays
和 getYears
,这样您就可以从周期中提取出时间的数量。时间由三个单位组成:月、日、年。为了显示在一个单位时间内测量的时间量,比如天数,你可以使用 ChronoUnit.between 的方法。 Period 用于计算两个 “日期” 间隔(年,月,日)
举例:
import java.time.LocalDate;
import java.time.Period;
public class DurationPeriodChrono {
public static void main(String[] args) {
// 当前系统的年月日中 的LocalDate 对象
LocalDate today = LocalDate.now();
System.out.println(today);
// 生日的年月日
LocalDate birthDate = LocalDate.of(2000, 1, 1);
System.out.println(birthDate);
// Period 用于计算两个 "日期" 间隔的工具类
Period period = Period.between(birthDate, today); // 第二个参数 - 第一个参数
System.out.println("相差的时间间隔对象: " + period);
System.out.println(period.getYears()); // 相差的年
System.out.println(period.getMonths()); // 相差的月
System.out.println(period.getDays()); // 相差的天数
System.out.println(period.toTotalMonths()); // 相差的总月数
}
}
8. 其他的API
- ZoneId 该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris
static Set<String> getAvailableZoneIds(); // 获取java中支持的所有时区
static ZoneId systemDefault(); // 获取系统默认时区
static ZonId of(String zoneId); // 获取一个指定时区
import java.time.ZoneId;
import java.util.Set;
public class ZoneldAndZonedDateTimeTest {
public static void main(String[] args) {
// 1.获取到所有的时区名称
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
System.out.println(zoneIds); // America/Cuiaba
System.out.println(zoneIds.size()); // 共有 599 个时区
// 2. 获取到当前系统的默认时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId); // Asia/Shanghai 注意了没有北京的只有上海的
}
}
- ZonedDateTime一个在ISO-8601日历系统时区的日期时间,如 2007-12- 03T10:15:30+01:00 Europe/Paris。 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等
细节:jdk8 新增的时间对象都是不可变的如果我们修改了,减少了,增加了时间,那么调用者是不会发生该改变的,而是生产一个新的时间。
带时区的 ZoneDateTime类
static ZonedDateTime now() // 获取当前时间的ZonedDateTime对象
static ZonedDateTime ofxxx(....) // 获取指定时间的ZoneDateTime对象
static ZonedDateTime withXxx(时间) // 修改时间系别的方法
static ZonedDateTime minusXxx(时间) // 减少时间系别的方法
static ZonedDateTime plusXxx(时间) // 增加时间系别的方法
举例:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;
public class ZoneldAndZonedDateTimeTest {
public static void main(String[] args) {
// 1. 获取当前系统时间的对象(带时区)
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
// 2. 获取指定时间对象(带时区的)
ZonedDateTime zonedDateTime2 = ZonedDateTime.of(2023, 10, 1,
11, 12, 12, 0, ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime2);
// 通过Instant + 时区的方式指定获取时间对象
Instant instant = Instant.ofEpochMilli(0L);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime time = ZonedDateTime.ofInstant(instant, zoneId);
System.out.println(time);
// 3.withxxx 修改时间系别的方法
ZonedDateTime time2 = time.withYear(2000);
System.out.println(time2);
// 减少时间
ZonedDateTime time3 = time.minusYears(1);
System.out.println(time3);
// 增加时间
ZonedDateTime time4 = time.plusYears(1);
System.out.println(time4);
}
}
-
Clock: 使用时区提供对当前即时、日期和时间的访问的时钟。持续时间:Duration,用于计算两个“时间”间隔
-
日期间隔:Period,用于计算两个“日期”间隔
-
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整 到“下一个工作日”等操作。
-
TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。
9. 关于日期时间的算法题
- 比较两个 Date 对象,哪个时间在前,哪个时间在后,Date 类型是不可以之间比较的,我们需要比较的是 Date 各自的时间戳。
import java.util.Date;
import java.util.Random;
public class DateExam {
public static void main(String[] args) {
Random random = new Random();
// random.nextLong()生产 long范围内的随机值,Math.abs()绝对值
Date date1 = new Date(Math.abs(random.nextLong()));
Date date2 = new Date(Math.abs(random.nextLong()));
if(date1.getTime() > date2.getTime()) {
System.out.println("date2时间在前");
} else if(date1.getTime() < date2.getTime()) {
System.out.println("date1时间在前");
} else {
System.out.println("date1 == date2 的时间");
}
}
}
- 需求:
- 秒杀活动 2023 年 11月 11日 0:0:0 (毫秒值),开始时间: 2023年 11 月 11日 0:10:0 (毫秒值),小贾下单开付款的时间为: 2023年11月11日 0:01:00,小皮下单开付款的时间为: 2023年11月11日 0:11:0,用代码说明这两位同学有没有参加上秒杀活动
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateExam {
public static void main(String[] args) {
// 1. 定义字符串表示三个时间段
String startStr = "2023年11月11日 0:0:0";
String endStr = "2023年11月11日 0:0:0";
String orderStr = "2023年11月11日 0:01:0";
// 2. 将上述三个字符串转换为 Date 类型
// 注意字符串的格式,与 SimpleDateFormat()所传参数的格式要一致不然报异常
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
Date startDate = null;
Date endDate = null;
Date orderDate = null;
try {
startDate = simpleDateFormat.parse(startStr);
endDate = simpleDateFormat.parse(endStr);
orderDate = simpleDateFormat.parse(orderStr);
} catch (ParseException e) {
e.printStackTrace();
}
// 3.得到三个设置的Date 对象的毫秒值时间戳
long startDateTime = startDate.getTime();
long endDateTime = endDate.getTime();
long orderDateTime = orderDate.getTime();
// 4. 判断
if (orderDateTime >= startDateTime && orderDateTime <= endDateTime) {
System.out.println("参加了秒杀活动成功");
} else {
System.out.println("参加秒杀活动失败");
}
}
}
10. 总结:
-
java.util.Date 包下的 转换为 java.sql.Date 包下的方式,java.sql.Date 可以强制转换为 java.util.Date包下的日期时间类型,因为 java.sql.Date extends 继承了 java.util.Date 包父类(多态性 )。但是 java.sql.Date 不可以 强制转换为 java.util.Date 包下的,因为 java.sql.Date不是器多态的性的实例对象。而是通过两者之间的 时间戳 转换。
-
JDK 8 之前的:格式: String字符串类型 ——> Date 日期时间类型,解析:Date日期时间类型 ——> String 字符串类型
-
JDK 8 之后的: 格式: String字符串类型 ——> Date 日期时间类型,解析:Date日期时间类型 ——> String 字符串类型
-
String < ———> Date日期时间类型:注意两者之间的格式必须保持一致,不然报异常。
-
java.time 包中包含很多类,你的程序可以用来表示时间和日期。这是一个非常丰富的 API。基于 ISO 日期的关键入口点如下:
- Instant 提供了时间轴的机器视图。
- LocalDate, LocalTime, and LocalDateTime 提供了日期和时间的人类视图,不包含时区。
- ZoneId, ZoneRules, and ZoneOffset 描述了时区、时区规则和时区偏移。
- ZonedDateTime 表示日期和时间与时区;OffsetDateTime和OffsetTime 类分别表示日期和时间,或者时间。这些类考虑了时区偏移量。
- Duration 测量日、时、分、秒、毫秒、纳秒的时间量
- Period 测量年、月、日的时间量
- 其他非 ISO 日历系统可以使用 java.time.chrono 包来表示。虽然 非ISO日期转换页面 提供了有关将基于 ISO 的日期转换为其他日历系统的信息,但此包不在本教程的讨论范围内 。
11. 最后:
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期 !!!