一、java时间类为什么这么复杂?
java的时间类非常复杂,这是由于jdk1.0到jdk1.1的时间类设计存在缺陷,导致使用不方便,线程不安全等问题,所以在jdk1.8,java又重新加入了一些时间类替换之前的时间类,但是jdk1.8为了兼容已经使用了老版本时间类的项目,并没有将老版时间类移除,只是将其中大部分方法标注为过时的,不推荐使用。
老版时间类这里主要介绍:
- java.util.Date;
- java.text.SimpleDateFormat,;
- java.util.Calendar;
新版本的时间类主要介绍:
- java.time.LocalDate;
- java.time.LocalTime;
- java.time.LocalDateTime;
- java.time.ZoneId;
- java.time.ZonedDateTime;
- java.time.instant;
二、老版本的时间类
既然已经过时为什么还要学习这些老版时间类?
这是因为还有大量的老项目中可能使用这些时间类,为了在碰见这些老项目时不至于两眼抓瞎,还是需要了解一下这些老版时间类。
- java.util.date
date类通过获取从1970年1月1日 00:00:00至今的毫秒数来记录时间,这个毫秒值用long类型的值来保存。
-
实例化date类的方法有两种:
//获取当前时间 Date date = new Date(); //通过long类型的值来实例化 long time=1000l; Date date1 = new Date(time); //结果:Wed Nov 15 12:01:17 CST 2023 System.out.println(date); //Thu Jan 01 08:00:01 CST 1970 System.out.println(date1);
-
实例化date后,可以调用date的getTime方法,获取long类型的毫秒数
//获取当前毫秒数 long time = date.getTime();//Wed Nov 15 12:01:17 CST 2023 long time1 = date1.getTime();//Thu Jan 01 08:00:01 CST 1970 //1700021140846 System.out.println(time); //1000 System.out.println(time1);
-
date的值可以被修改,使用setTime方法
//设置当前时间 date.setTime(time1); date1.setTime(time); System.out.println(date.getTime());//1000 System.out.println(date1.getTime());//1700023634184
这也是date被人诟病的地方,date存储的时间可以被改变,一旦被改变原数据就找不回来了。
Date类型虽然存储了时间,但是输出形式只有long的毫秒数和固定的格式(Wed Nov 15 12:01:17 CST 2023),为了满足不同格式的输出,就有SimpleDateFormat类来将Date以预设的格式输出成字符串。
-
java.util.SimpleDateFormat
-
SimpleDateFormat的实例化也有两种形式,无参实例化和将格式字符串传入后实例化。
无参实例化出的SimpleDateFormat使用的是默认格式,有参就是用的是参数的格式。//实例化SimpleDateFormat SimpleDateFormat simpleDateFormat = new SimpleDateFormat();//默认格式的字符串 yyyy/MM/dd 上/下午hh:mm SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
SimpleDateFormat是如何识别参数格式的呢?
第一列字母就是SimpleDateFormat能识别的关键字符,常用的y表示年,M表示月份,m表示分,H表示小时,s表示秒,d表示月份的天数。
SimpleDateFormat在格式化输出时,会将格式参数中能识别的关键字符替换成相应的日期,不能识别的就原封不动。 -
SimpleDateFormat将date格式化输出的方法是format()方法,参数是date对象
//实例化SimpleDateFormat SimpleDateFormat simpleDateFormat = new SimpleDateFormat();//默认格式的字符串 yyyy/MM/dd 上/下午hh:mm SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //格式化输出 String s = simpleDateFormat.format(date1); System.out.println(s);//23-11-15 下午12:47 s = simpleDateFormat1.format(date1); System.out.println(s);//2023-11-15 12:48:46
-
SimpleDateFormat还能将格式化的时间字符串创建为一个date变量,使用parse()方法,参数就是字符串时间。 SimpleDateFormat的格式必须和字符串时间的格式一样。
//将格式化字符串时间还原成date String str = "2023-11-15 12:48:46"; Date date2 = simpleDateFormat1.parse(str);
-
SimpleDateTime是线程不安全的,多个线程同时使用一个SimpleDateTime解析格式会发生问题。
-
-
java.util.Calendar
Calendar内部维护了很多字段,从起点至今的秒数,时区,年月日分秒,周数,天数等都是通过字段来维护的。
-
Calendar是一个接口,它的不能直接实例化。
实例化之后Calendar对象获取的实例化时的瞬时时间。//实例化Calendar Calendar calendar = Calendar.getInstance();
-
获取某个字段的信息,使用get()方法,int值(Calendar内部维护了表示所有字段的静态变量)
//获取内部字段值 int year = calendar.get(Calendar.YEAR);
这也显示了Calendar使用不便的地方,获取字段一般都是get字段名()方法来获取某一个字段,但是Calendar只有一个get()方法,需要传入不同的参数来获取不同的字段,这些参数又不好记,使用起来非常不便。
-
Calendar也可以被修改,set()方法第一个参数是静态变量值,第二个是修改后的值。
//修改内部字段值 calendar.set(Calendar.YEAR,2010);//将年份修改为2010年
-
总结:为什么calendar,date,simpleDateFormat被淘汰了
1.设计不合理使用不方便
2.可变的,修改之后会丢失原本信息
3.可被修改,又没有线程安全机制,所以是线程不安全的
4.只能精确到毫秒
三、新版本的时间类
- 用来代替Calendar的时间类
- java.time.LocalDate
- java.time.LocalTime
- java.time.LocalDateTime
获取三个时间类的方法
三者的使用方法风格都差不多
获取参数就是用get~
修改日期就是用with~
加日期就是plus~
减日期就是minus~
获取指定日期的对象就调用静态方法of~
判断相等,在前,在后equal,isbefore,isafter - java.time.ZoneId
- java.time.ZoneDateTime
ZoneId就用用来管理时区的,用获取默认时区也就是当前系统时区(systemDefault),还能获取指定时区用of(时区字符串)
Zonedatetime就是用来获取时区时间的,它的方法和localDatetime几乎相同,不同的是可以根据时区来实例化,以此来获取对应时区的时间
Zoneid和zonedatetime配合使用 - java.time.Instant
instant获取当前的时间戳(代替date)
通过instant对象到的时间由两部分组成,总秒数+不够一秒的纳秒数
Instant能获取纳秒但是localdatetime也能获取纳秒,为啥还要用instant?
Instant有一个获取从1970 -01-01 00:00:00到现在的秒数的方法,localdatetime中只有获取这一分钟内秒数的方法。
- java.time.DateTimeFormatter
DatetiemForMatter使用方法:
1.创建格式化器;DatetiemForMatter静态方法ofPattern创建了格式化器,传入字符串参数作为格式
2.将时间对象格式化成字符串;使用format方法来将传入的时间对象格式化成字符串。
3.时间对象也可以调用本身的format方法并传入时间格式器对象来生成格式化后的时间字符串。
4.将格式字符串转换成时间对象;时间类调用静态parse方法传入字符串和格式化器创建时间对象。
总结:jdk1.8引入的时间类的优势:
1.设计更合理,使用方便
2.不可变的,要修改的话,会直接创建一个新的对象返回,不会修改原本对象
3.线程安全的,有线程安全机制
4.精确到纳秒