一、JDK8之前的时间API
1️⃣java.lang.System类
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0分0秒之间以毫秒为单位的时间差
📌此方法适用于计算程序的运行时间 (时间戳)
public class DateTest {
@Test
public void test1(){
long start=System.currentTimeMillis();
//需要计算运行时间的程序
process();
long end=System.currentTimeMillis();
System.out.println("程序运行时间为:"+(end-start)+"毫秒");
}
public void process(){
for(int i=0;i<100;i++){
if(i%2==0) System.out.println(i);
}
}
}
2️⃣java.util.Date类
表示特定的瞬间,精确到毫秒
构造器
Date() 使用无参构造器创建的对象可以获取本地当前的时间
Date(long date) 将距离1970年1月1日0分0秒的毫秒数转化为年月日的形式
常用方法
getTime() 返回自1970年1月1日 00:00:00以来此Date对象表示的毫秒数
toString() 把此Date对象转换为以下形式的String: dow mon dd hh:mm:ss zzz yyyy(dow是一周中的某一天,zzz是时间标准)
@Test
public void test2(){
Date date=new Date();
System.out.println(date.toString());
long dateMilli=date.getTime();
System.out.println(dateMilli);
//sleep
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Date date1=new Date(dateMilli);
System.out.println(date1);
Date date2=new Date();
System.out.println(date2.toString());
}
3️⃣java.sql.Date类
是java.util.Date的子类,所以自然支持多态。java.sql.Date对应着数据库中日期类型的变量
构造器
Date(long date) 将距离1970年1月1日0分0秒的毫秒数转化为年月日的形式
常用方法
getTime() 返回自1970年1月1日 00:00:00以来此Date对象表示的毫秒数
toString() 转换成标准格式
从数据库取出的sql.Date转换为程序中要使用的util.Date 多态
将程序中的util.Date转换为数据库中的sql.Date
@Test
public void test3(){
Date date=new Date();
java.sql.Date sqlDate=new java.sql.Date(date.getTime());
System.out.println(date);
System.out.println(sqlDate);
}
4️⃣java.text.SimpleDateFormat类
Date类的API不易于国际化(格式单一且都是英文表示),大部分废弃了,java.text.SimpleDateFormat类是一个不与语言环境相关的方式来格式化和解析日期的具体类
允许进行格式化和解析
构造器
SimpleDateFormat() 默认的模式和语言环境创建对象
SimpleDateFormat(String pattern) 使用pattern指定的格式创建一个对象,可以使用API已有的,也可以自己指定格式
格式化:Date -> String
public String format(Date date) 格式化,将date变为指定pattern的字符串形式
解析:String -> Date
public Date parse(String str) 将给定的字符串(符合格式要求的)变为date形式,需要异常处理,防止没有按照要求写String
@Test
public void testSimpleDateFormat() throws ParseException {
//实例化SimpleDateFormat:使用默认的构造器
SimpleDateFormat date = new SimpleDateFormat();
Date date1=new Date();
System.out.println(date1.toString());
//格式化:date变为字符串
String format=date.format(date1);
System.out.println(format);
//解析:格式化的逆过程,字符串变为date
String str1="20-11-23 下午7:49";
Date date2=date.parse(str1);
System.out.println(date2.toString());
System.out.println("********************");
//*******调用带参的构造器按照指定的方式进行格式化*******
SimpleDateFormat date3 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa");
//也可以按照自己指定的方式进行格式化
String date3ToString = date3.format(date1);
System.out.println(date3ToString);
String str2="02020.十一月.23 公元 08:15 下午";
Date str2ToDate = date3.parse(str2);
System.out.println(str2ToDate.toString());
}
📐练习题1
将字符串"2020-09-08"转换为sql.Date类型的
@Test
/*
*
* @Description: 将字符串"2020-09-08"转换为sql.Date类型的
*
* @auther: ssy
* @date: 10:42 2020/11/24
* @param: []
* @return: void
*
*/
public void test2() throws ParseException {
String str="2020-09-08";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date=sdf.parse(str);
System.out.println(date.toString());
java.sql.Date res = new java.sql.Date(date.getTime());
System.out.println(res.toString());
}
📐练习题2
从1997-01-01开始,“三天打渔两天晒网”,到xxxx-xx-xx(键盘输入),在打渔还是筛网
两个点
① 计算两个时间之间有多少天
方法一:计算之间从1997-01-01到(xxxx-1)-12-31有几年(注意闰年),再计算剩下的月数,天数
方法二:计算两者之间的毫秒时间差,除以一天的毫秒数,得到差的天数
②总天数取余5,结果为1/2/3则打渔,否则晒网
代码采用的是方法二
public static void main(String[] args) throws ParseException {
String start="1997-01-01";
System.out.println("请按照格式输入年月日(xxxx-xx-xx),例如2020-09-01");
Scanner in=new Scanner(System.in);
String end = in.nextLine();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date startDate=sdf.parse(start);
Date endDate = sdf.parse(end);
int day=(int)(endDate.getTime()-startDate.getTime())/(24*60*60*1000)+1;
System.out.println(day);
if(day%5==0 ||day%5==4){
System.out.println("今天在晒网");
}
else{
System.out.println("今天在打渔");
}
}
5️⃣java.util.Calendar类
Calendar是一个抽象基类(不能通过new的方式直接声明一个对象),主要用于完成日期字段之间的相互操作。
获取Calendar实例的一个方法
调用它的子类GregorianCalendar的构造器
使用Calendar.getInstance()方法,实际上创建的仍为GregorianCalendar对象
常用方法
get(int field) 获取常用的一些属性信息(field属性包括,Year,Month,Day,DAY_OF_WEAK,HOUR_OF_DAY等,是static常量,使用类进行调用)
set(int field, int value) 修改Calendar的一些属性信息
append(int field, int count) 将Calendar的指定属性添加count
Date getTime() 将Calendar转换为Date类型
void serTime(Date date)将Date类型转换为Calendar类型
注意问题,获取月份(0-11)时,1月份为0,获取星期(1-7)时,周日为1
@Test
public void test5(){
Calendar cal=Calendar.getInstance();//创建当前时间的calendar实例
System.out.println(cal.getClass());
//get
int days=cal.get(Calendar.DAY_OF_YEAR);
System.out.println(days);
//set
cal.set(Calendar.DAY_OF_YEAR,266);
days=cal.get(Calendar.DAY_OF_YEAR);
System.out.println(days);
//add
cal.add(Calendar.DAY_OF_WEEK,2);
days=cal.get(Calendar.DAY_OF_WEEK);
System.out.println(days);
//getTime
Date date=cal.getTime();
System.out.println(date.toString());
//setTime
Date date1 = new Date();
cal.setTime(date1);
days=cal.get(Calendar.DAY_OF_WEEK);
System.out.println(days);
}
二、JDK8的新日期时间API
新时间API出现的背景:JDK1.0包含了一个java.util.Date类,但是它的多数方法已经在JDK1.1引入Calendar类之后被弃用,而Calendar并不比Date好多少,他们面临的问题是:
①可变性:像日期和时间这样的类应该是不可变的(对日期进行修改,例如Calendar.set(),应该保持原有对象不变,return一个改变后的对象)
②偏移性:Date中的年份是从1900年开始,而月份都是从0开始的(查看Date已经废弃的构造器Date(year,month,day)会发现year会在原有基础上加上1900)
③格式化:格式化只对Date有用,Calendar则不行
④线程不安全的:不能处理闰秒等
Java8引入的java.time API已经纠正了过去的缺陷,将来很长一段时间它都会为我们服务
Java8吸收了Joda-Time(第三方,在Java8以前的版本如果想使用java.time的东西,可以自己导入)的精华,新的java.time中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类
经常用到的java.time——包含值对象的基础包 java.time.format——格式化和解析时间和日期
6️⃣LocalDate、LocalTime、LocalDateTime类
LocalDate、LocalTime、LocalDateTime是其中比较重要的几个类,它们的实例时不可变的对象
LocalDate:代表IOS格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期
LocalTime:表示一个时间,而不是日期
LocalDateTime:用来表示日期和时间的,是最常用的一个类
对象的创建(三个类的方法相同)
now() :静态方法,根据当前时间创建对象
of():静态方法,根据指定日期/时间创建对象
@Test
public void test1(){
LocalDateTime time1=LocalDateTime.now();
LocalDateTime time2=LocalDateTime.of(2020,11,25,9,24);
System.out.println(time1);
System.out.println(time2);
}
get相关属性
getDayOfMonth()/getDayOfYear() :获取月份天数(1-31)/ 获取年份天数(1-366)
getDayOfWeek():获得星期几(返回一个DayOfWeek枚举值)
getMonth()/getMonthValue():获得月份,返回一个Month枚举值/获得月份(1-12)
getYear():获得年份
getHour()/getMinute()/getSecond:获得时/分/秒
@Test
public void test2(){
LocalDateTime time = LocalDateTime.now(); //获得当前日期时间
System.out.println(time); //2020-11-25T09:39:51.535
System.out.println(time.getDayOfMonth()); //25
System.out.println(time.getDayOfYear()); //330
System.out.println(time.getDayOfWeek()); //WEDNESDAY
System.out.println(time.getMonth()); //NOVEMBER
System.out.println(time.getMonthValue()); //11
System.out.println(time.getYear()); //2020
System.out.println(time.getHour()); //9
System.out.println(time.getMinute()); //39
System.out.println(time.getSecond()); //51
}
对日期时间的修改
withDayOfMonth()/withDayOfYear()/withMonth()/withYear():将相关属性修改为指定的值并返回新的对象
plusDays()/plusWeeks()/plusMonths: 向当前对象添加几天、几周、几月并返回新的对象
minusDays()/minusWeeks()/minusMonths: 从当前对象减去几天、几周、几月并返回新的对象
@Test
public void test3(){
LocalDateTime time = LocalDateTime.now();
System.out.println(time);
LocalDateTime time1=time.withDayOfMonth(11);
System.out.println(time1);
LocalDateTime time2=time.plusHours(3);
System.out.println(time2);
LocalDateTime time3=time.minusMonths(2);
System.out.println(time3);
}
7️⃣Instant类
时间线上的一个瞬时点,可能被用来记录应用程序中的事件时间戳,从(格林威治时间)1970年1月1日00:00:00开始,以毫秒为单位记录。Instant提供的是机器视图,不提供处理人类意义上的时间单位。Instant的精度可以达到纳秒。Instant相当于Date类
now():静态方法,返回默认UTC时区的Instant类对象
ofEpochMilli(long epochMilli):静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类对象
atOffset(ZonOffset offset):结合即时的偏移来创建一个OffsetDateTime
toEpochMilli():返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳
@Test
public void test4(){
//获取本初字符线对应的标准时间
Instant instant1=Instant.now();
System.out.println(instant1);
System.out.println(instant1.toEpochMilli());
Instant instant2=Instant.ofEpochMilli(1606269515960L);
System.out.println(instant2);
//添加时间偏移量
OffsetDateTime offsetDateTime=instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
System.out.println(offsetDateTime.toInstant().toEpochMilli());
}
8️⃣java.time.format.DateTimeFormatter
该类提供了三种格式化方法:
预定义的标准格式
ISO_LOCAL_DATE_TIME,ISO_LOCAL_TIME,ISO_LOCAL_DATE
本地化相关的格式
如:ofLocalizedDateTime(FormatStyle.LONG)
FormatStyle有多个 LONG,MEDIUM,SHORT,FULL
FULL不适用于ofLocalizedDateTime,适用于ofLocalizedDate
自定义方法
ofPattern(String pattern)
String format(TemporalAccessor t):格式化一个日期、时间,返回字符串
TemporalAccessor parse(CharSequence text):将指定格式的字符序列解析为一个日期、时间,返回一个接口
@Test
public void test5(){
//预定义格式
DateTimeFormatter formatter=DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化: 日期->String
LocalDateTime time = LocalDateTime.now();
String str=formatter.format(time); //format的参数要与formatter定义时的格式对应起来
System.out.println(time);
System.out.println(str);
//解析: String->日期
String str1="2020-11-11T10:26:07.991";
TemporalAccessor parse1 = formatter.parse(str1); //使用接口承接,因为不同的formatter的格式定义不同
System.out.println(parse1);
//本地化相关的格式
DateTimeFormatter formatter1=DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
LocalDate date=LocalDate.now();
System.out.println(formatter1.format(date));
//自定义的方式
DateTimeFormatter formatter2=DateTimeFormatter.ofPattern("yyyy-MM-dd");
String str2="2020-09-18";
System.out.println(formatter2.format(time));
System.out.println(formatter2.parse(str2));
}
💌以上只是初步了解一下基础内容,还有很多东西没有讲到,比方解析为TemporalAccessor 接口之后如何开展后续工作,具体用到的时候还需要深入学习
@Test
public void test6(){
DateTimeFormatter formatter=DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime time=LocalDateTime.parse("2020-11-11T10:26:07.991",formatter);
System.out.println(time);
}
@Test
public void test7(){
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date=LocalDate.parse("22-06-1997",formatter);
System.out.println(date);
}
@Test
public void test8(){
DateTimeFormatter formatter=DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//解析: String->日期
String str1="2020-11-11T10:26:07.991";
TemporalAccessor parse1 = formatter.parse(str1); //使用接口承接,因为不同的formatter的格式定义不同
LocalDateTime localDateTime1=LocalDateTime.from(parse1);
System.out.println(localDateTime1);
}