java中的日期处理

**


java8中的日期处理


**

一、新老版本区别

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。// 可以加锁
设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
时区处理麻烦 −
日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,
但他们同样存在上述所有的问题。

二、Local(本地) − 简化了日期时间的处理,没有时区的问题。

1.LocalDate类

LocalDate类的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息。另外,它也不附带任何与时区相关的信息

 // 通过of重载的工厂方法创建
 LocalDate ofDate = LocalDate.of(2019, 3, 29);// 2019-03-29
 
 LocalTime ofTime = LocalTime.of(13, 45, 20);// 13:45:20
//使用静态方法parse来创建
 LocalDate parseDate = LocalDate.parse("2019-03-29");//2019-03-29

 LocalTime parseTime = LocalTime.parse("13:45:20");// 13:45:20 

2.读取LocalDate和LocalTime常用值的两种方式

		// 读取LocalDate和LocalTime常用值的两种方式

        //LocalDate 和 LocalTime 类提供了多种方法来 读取常用的值,比如年份、月份、星期几等
	    //小时
        int hour = ofTime.getHour(); // 13
		//分钟
        int minute = ofTime.getMinute(); // 45
		//秒
        int second = ofTime.getSecond(); // 20
		
        System.out.println(ofTime);// 13:45:20

		//年
        int year = ofDate.getYear(); // 2019
		//月份
        Month month = ofDate.getMonth(); // MARCH
		//天数
        int day = ofDate.getDayOfMonth(); // 29
		//周几
        DayOfWeek dow = ofDate.getDayOfWeek(); // TUESDAY
		//月长度
        int len = ofDate.lengthOfMonth(); // 31 (days in March)
		//判断是否为闰年
        boolean leap = ofDate.isLeapYear(); // false (判断是否为为闰年)

        System.out.println(ofDate);

        //通过传递一个TemporalField(时域)参数给get方法拿到同样的信息。

        int y = ofDate.get(ChronoField.YEAR);//2019

        int m = ofDate.get(ChronoField.MONTH_OF_YEAR);//3

        int d = ofDate.get(ChronoField.DAY_OF_MONTH);//29
		//几周
        int dow2 = ofDate.get(ChronoField.DAY_OF_WEEK);//5



        int hour2 = ofTime.get(ChronoField.HOUR_OF_DAY);//13

        int minute2 = ofTime.get(ChronoField.MINUTE_OF_HOUR);//45

        int second2 = ofTime.get(ChronoField.SECOND_OF_MINUTE);//20

3.合并日期与时间LocalDateTime

//LocalDateTime,是LocalDate和LocalTime的合体。它同时表示了日期和时间,但不带有时区信息。

//创建LocalDateTime的两种方式
 //通过重载的of工厂方法创建
//2014-03-18T13:45:20
 LocalDateTime dt1 = LocalDateTime.of(2019, Month.MARCH, 29, 13, 45, 20);
 LocalDateTime dt2 = LocalDateTime.of(ofDate, ofTime);//2019-03-29T13:45:20

 //通过合并日期和时间的方式创建

 LocalDateTime dt3 = ofDate.atTime(13, 45, 20);//2019-03-29T13:45:20

 LocalDateTime dt4 = ofDate.atTime(ofTime); //2019-03-29T13:45:20

 LocalDateTime dt5 = ofTime.atDate(ofDate);//2019-03-29T13:45:20

  // 从LocalDateTime中提取LocalDate或者LocalTime 组件

  LocalDate date1 = dt1.toLocalDate();//2019-03-29

  LocalTime time1 = dt1.toLocalTime();//13:45:20

//到目前为止,这些日期和时间都是不可修改的,这是为了更好的支持函数式编程,确保线程安全。

4.操作、解析和格式化日期

对已存在的LocalDate对象,创建它的修改版,最简单的方式是使用withAttribute方法。withAttribute方法会创建对象的一个副本, 并按照需要修改它的属性。以下所有的方法都返回了一个修改属性的对象,他们不会影响原来的对象。

 LocalDate  dd = LocalDate.of(2019,3,29); //2019-03-29
 
LocalDate dd1 = dd.withYear(2018); //2017-03-22

LocalDate dd2 = dd.withDayOfMonth(22); //2019-03-22

LocalDate dd4 = dd.withMonth(10); //2019-10-29改变月份

LocalDate dd3 = dd.with(ChronoField.MONTH_OF_YEAR,10); //2019-10-29改变月份

//除了withAttribute详细的年月日,也可以采用通用的with方法,第一个参数是TemporalField对象,第二个参数是修改的值。
它也可以操纵LocalDate对象:

 LocalDate dd5 = dd.plusWeeks(1); //加一周2019-04-05
       
 LocalDate dd6 = dd.minusYears(3); //减去三年2016-03-29
       
 LocalDate dd7 = dd.plus(6,ChronoUnit.MONTHS); //加6月2019-09-29

5.TemporalAdjuster

操纵更复杂的日期,比如将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时可以使用with的重载版本,向>其传递一个提供了更多定制化选择的TemporalAdjuster(暂时调整器)对象,更加灵活的处理日期。

LocalDate dd = LocalDate.of(2018,8,23);

 LocalDate dd1 = dd.with(dayOfWeekInMonth(2,DayOfWeek.FRIDAY)); 
 //同一个月中,第二个星期五 2019-03-8

        
LocalDate dd2 = dd.with(firstDayOfMonth());
 //当月的第一天 2019-03-01
 
LocalDate dd3 = dd.with(firstDayOfNextMonth());
 //下月的第一天 2019-04-01

LocalDate dd4 = dd.with(firstDayOfNextYear()); 
//明年的第一天 2020-01-01

LocalDate dd5 = dd.with(firstDayOfYear()); 
//当年的第一天 2019-01-01

LocalDate dd6 = dd.with(firstInMonth(DayOfWeek.MONDAY)); 
//当月第一个星期一 2019-03-04

LocalDate dd7 = dd.with(lastDayOfMonth());
 //当月的最后一天 2019-03-31

LocalDate dd8 = dd.with(lastDayOfYear());
 //当年的最后一天 2019-12-31

LocalDate dd9 = dd.with(lastInMonth(DayOfWeek.SUNDAY)); 
//当月最后一个星期日 2019-03-31


LocalDate dd10 = dd.with(previous(DayOfWeek.MONDAY)); 
//将日期向前调整到第一个符合星期一 2019-03-25

LocalDate dd11 = dd.with(next(DayOfWeek.MONDAY)); 
//将日期向后调整到第一个符合星期一 2019-04-01

LocalDate dd12 = dd.with(previousOrSame(DayOfWeek.FRIDAY)); 
//将日期向前调整第一个符合星期五,如果该日期已经符合,直接返回该对象 2019-03-29
       
LocalDate dd13 = dd.with(nextOrSame(DayOfWeek.FRIDAY)); 
//将日期向后调整第一个符合星期五,如果该日期已经符合,直接返回该对象 2019-03-29

//TemporalAdjuster可以进行复杂的日期操作,如果没有找到符合的预定义方法,可以自己创建一个,TemporalAdjuster接口只声明了一个方法所以他说一个函数式接口

@FunctionalInterface
public interface TemporalAdjuster {
    Temporal adjustInto(Temporal temporal);
}

三、机器时间处理

作为人,我们习惯于以星期几、几号、几点、几分这样的方式理解日期和时间。毫无疑问, 这种方式对于计算机而言并不容易理解。
从计算机的角度来看,建模时间最自然的格式是表示一 个持续时间段上某个点的单一大整型数。

1.java.time.Instant类对时间建模的方式

//旧版本:Timestamp
//Java 8:Instant
//基本上它是以Unix元年时间(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的 秒数进行计算。

 // 通过向静态工厂方法ofEpochSecond传递一个代表秒数的值创建一个该类的实例。

  Instant instant1 = Instant.ofEpochSecond(3);//1970-01-01T00:00:03Z

  // ofEpochSecond的重载增强版本,它接收第二个以纳秒为单位的参数值,对传入作为秒数的参数进行调整。

        // 2秒之后再加上 100万纳秒(1秒)

        Instant instant3 = Instant.ofEpochSecond(2, 1_000_000_000);
		//1970-01-01T00:00:04Z

        //4秒之前的100万纳秒(1秒)

        Instant instant4 = Instant.ofEpochSecond(4, -1_000_000_000);
		//1970-01-01T00:00:03Z

2.时间区间:Duration和Period

Duration类主要用于以秒和纳秒衡量时间的长短。

Period类以年、月或者日的方式对多个时间单位建模。
LocalTime time1 = LocalTime.of(13, 45, 20); // 13:45:20

LocalTime time2 = LocalTime.of(20, 45, 20); // 13:45:20

LocalDateTime dateTime1 = LocalDateTime.of(2019, Month.MARCH, 29, 13, 45, 20); // 2019-03-29T13:45

 LocalDateTime dateTime2 = LocalDateTime.of(2020, Month.MARCH, 29, 13, 45, 20); // 2020-03-29T13:45

 Instant instant1 = Instant.ofEpochSecond(3);//1970-01-01T00:00:03Z

 Instant instant2 = Instant.ofEpochSecond(4);//1970-01-01T00:00:04Z

 LocalDate localDate1 = LocalDate.of(2019, 3, 19);//2019-03-19

 LocalDate localDate2 = LocalDate.of(2019, 3, 28);//2019-03-19

 //Duration的创建方式

 //通过两个LocalTimes对象、两个LocalDateTimes对象、或者两个Instant对象创建duration

 Duration d1 = Duration.between(time1,time2);//PT7H(25200)


 Duration d2 = Duration.between(dateTime1, dateTime2);//PT876

 System.out.println(d1.getSeconds());//25200

 System.out.println(d2.getSeconds());//31536000

 Duration d3 = Duration.between(instant1, instant2);//PT1S

 //通过工厂类,直接创建对应的实例;

 Duration threeMinutes1 = Duration.ofMinutes(3);//PT3M(180)

 Duration threeMinutes2 = Duration.of(3, ChronoUnit.MINUTES);//PT3M(180)


 //Duration的创建方式

 //1. 通过两个LocalDate对象创建duration

 Period tenDays = Period.between(localDate1,localDate2);//P9D这两个相差多少秒 多少天

 //2. 通过工厂类,直接创建对应的实例;

 Period tenDays2 = Period.ofDays(10);//P10D

 Period threeWeeks = Period.ofWeeks(4);//P21D 几周多少天 28天

 Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);//P2Y6M1D

由于Duration类主要用于以秒和纳 秒衡量时间的长短,你不能仅向between方法传递一个LocalDate对象做参数。同样,Period以年、月或者日的方式对多个时间单位建模,所以只能传递LocalDate对象作为参数。

四、格式化日期

新的 java.time.format 包就是格式化以及解析日期、时间对象的。这个包中最重要的是DateTimeFormatter。

LocalDate date = LocalDate.of(2019, 3, 29);//2019-03-29
		//1. 从时间生成字符串

        // 使用特定不同的格式器生成字符串

   String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);//20190329

   String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);//2019-03-29


  //DateTimeFormatter类还支持静态工厂方法,它可以按 照某个特定的模式创建格式器

  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

DateTimeFormatter chinaFormatter2 =      DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);

        String s3 = date.format(formatter);//29/03/2019

        String s5 = date.format(chinaFormatter2);//2019年3月29日 星期五


        // 从字符串生成时间

        //通过解析代表日期或时间的字符串重新创建该日期对象。

        LocalDate date1 = LocalDate.parse("20190329", DateTimeFormatter.BASIC_ISO_DATE);//2019-03-29

        LocalDate date2 = LocalDate.parse("2019-03-29", DateTimeFormatter.ISO_LOCAL_DATE);//2019-03-29

        LocalDate date3 = LocalDate.parse("29/03/2019", formatter);//2019-03-29

        LocalDate date5 = LocalDate.parse("2019年3月19日 星期五", chinaFormatter2);//2019年3月29日 星期五

五、处理时区

旧版本:TimeZone
java 8:ZoneId
之前你看到的Java8中的日期和时间的种类都不包含时区信息。时区的处理是新版日期和时间API新增 加的重要功能,使用新版日期和时间API时区的处理被极大地简化了。跟其他日期和时间类一 样,ZoneId类也是无法修改的。
时区是按照一定的规则将区域划分成的标准时间相同的区间。每个特定 的ZoneId对象都由一个地区ID标识;

ZoneId romeZone = ZoneId.of("Europe/Rome");//以欧洲为标识

//地区ID都为“{区域}/{城市}”的格式,这些地区集合的设定都由英特网编号分配机构(IANA) 的时区数据库提供。java
8中支持的所有地区集合可以通过以下语句打印出来:

Set<String> zoneIds= ZoneId.getAvailableZoneIds();

        for (String zone : zoneIds) {

            //共计599个

            System.out.println(zone);

        }

1.ZoneDateTime

一旦得到一个ZoneId对象,你就可以将它与LocalDate、LocalDateTime或者是Instant对象整合起来,构造为一个ZonedDateTime
实例,它代表了相对于指定时区的时间点.

一旦得到一个ZoneId对象,你就可以将它与LocalDate、LocalDateTime或者是Instant对象整合起来,构造为一个ZonedDateTime
实例,它代表了相对于指定时区的时间点.
 		ZoneId romeZone = ZoneId.of("Europe/Rome");//以欧洲为标示

        LocalDate date = LocalDate.of(2019, Month.MARCH, 29);//2019-03-29

        ZonedDateTime zdt1 = date.atStartOfDay(romeZone);

        LocalDateTime dateTime = LocalDateTime.now();//获取现在时间2019-03-30T23:26:12.992

        ZonedDateTime zdt2 = dateTime.atZone(romeZone);

        Instant instant = Instant.now();//2019-03-30T15:25:13.136Z

        ZonedDateTime zdt3 = instant.atZone(romeZone);



        System.out.println(zdt1);//2019-03-29T00:00+01:00[Europe/Rome]

        System.out.println(zdt2);//2019-03-30T23:23:09.396+01:00[Europe/Rome]

        System.out.println(zdt3);//2019-0330T16:23:09.397+01:00[Europe/Rome]

1.2 通过ZoneId,你还可以将LocalDateTime转换为Instant:

LocalDateTime dateTime2 = LocalDateTime.of(2018,7,21,18,46,0);//2019-03-29T18:46

ZoneId romeZone2 = ZoneId.systemDefault();//Asia/Shanghai获取时区

Instant instantFromDateTime = dateTime2.atZone(romeZone2).toInstant();

   System.out.println(instantFromDateTime.getEpochSecond());//1553856360秒

总结

Instant (时间戳是一个确切的点)
提供了 比较方法 between
localtime localDate 都是依赖于clock(这是一个时钟类,就是访问日期和时间 底层是timenes 获取的是国际时间)
LocalDate 是不可变的
period(周期)比较
plus增加
minus减少
zonedDatetime(带时区的时间不可变的)
上边的那个类表示时区的类可以获取这一年的最后一天
国际时间用zonnedDateTo这还少UTC的比较符合国家标准
普通方法用localDateTime

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值