Java8时间处理

因为现在公司里有大量要处理时间的业务,以前都是用Date+SimpleDateFormat来搞。从Java 8开始,推出了全新的日期时间API,用java.time包的时间处理类功能更强大,而且Date和SimpleDateFormat是可变类型,非线程安全使他们的应用非常受限,另外Date中的很多方法都已经过时了。

目录

  • 一、为什么现在不推荐用Date
    • 1.线程安全性问题
    • 2. Date中的很多方法都已经过时了
  • 二、LocalDateTime使用方法
    • 1、获取当前时间
    • 2、构造一个指定的时间
    • 3、修改时间
    • 4、格式化日期
    • 5、时间解析
    • 6、时间比较
    • 7、Date转LocalDateTime
    • 8、获取月的第一天、月的最后一天,下月的第一天
    • 9、获取上周或下周的任意一天
    • 10、获取两个时间之间的天数,进而获取两个时间之间的日期集合
  • 三、springboot中使用LocalDateTime

新API基于ISO标准日历系统,java.time包下的所有类都是不可变的:
Java8时间处理_第1张图片
因为篇幅有限,这篇只总结了LocalDateTime,这也是使用的最多的,LocalDate和LocalTime用法类似,另外LocalDateTime的toLocalDate()和toLocalTime()可以转换为LocalDate和LocalTime。

一、为什么现在不推荐用Date

1.线程安全性问题

其实Date时间类是可变类,多线程环境下对共享Date变量进行操作,需要自己保证线程安全。
而LocalDateTime是线程安全的:
Java8时间处理_第2张图片
同样日期格式化类SimpleDateFormat也不是线程安全的,而DateTimeFormatter是线程安全的:
Java8时间处理_第3张图片
Java8时间处理_第4张图片

2. Date中的很多方法都已经过时了

Java8时间处理_第5张图片

二、LocalDateTime使用方法

1、获取当前时间

可以获取当前时间的年、月、日、星期几、时、分、秒,代码如下:

package com.linyf.demo.date;

import java.time.LocalDateTime;

public class LocalDateTime1 {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now);
        System.out.println("当前年份:" + now.getYear());
        System.out.println("当前月份:" + now.getMonthValue());
        System.out.println("当前日份:" + now.getDayOfMonth());
        System.out.println("当前周几:" + now.getDayOfWeek().getValue());

        System.out.println("当前时:" + now.getHour());
        System.out.println("当前分:" + now.getMinute());
        System.out.println("当前秒:" + now.getSecond());
    }
}

运行结果:
Java8时间处理_第6张图片

2、构造一个指定的时间

比如想构造2020年2月2号12时30分30秒:

package com.linyf.demo.date;

import java.time.LocalDateTime;

public class LocalDateTime2 {
    public static void main(String[] args) {
        LocalDateTime of = LocalDateTime.of(2020, 2, 2, 12, 30, 30);
        System.out.println(of);
    }
}

执行结果:
在这里插入图片描述
另外of方法有很多重载的,可以根据需要选择:
Java8时间处理_第7张图片

3、修改时间

package com.linyf.demo.date;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class LocalDateTime3 {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now);

        now = now.plusDays(1);// 加1天
        now = now.minusHours(1);// 减一小时
        now = now.plus(1, ChronoUnit.WEEKS); //加一周

        now = now.withMinute(59); // 直接设置分钟为59
        System.out.println("修改后时间:" + now);
    }
}

执行结果:
Java8时间处理_第8张图片
另外plus是有很多重载版本的,可以根据需要选择(minute和with一样,可自行查看),另外可以结合ChronoUnit进行操作:Java8时间处理_第9张图片

4、格式化日期

可以使用基本格式,也可以自定义格式,代码如下:

package com.linyf.demo.date;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTime4 {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        String result1 = now.format(DateTimeFormatter.BASIC_ISO_DATE);
        String result2 = now.format(DateTimeFormatter.ISO_DATE);
        String result3 = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

        System.out.println("基本格式1:" + result1);
        System.out.println("基本格式2:" + result2);
        System.out.println("自定义格式:" + result3);
    }
}

执行结果:
Java8时间处理_第10张图片

5、时间解析

就是可以根据给的时间字符串解析成对应的时间对象,代码如下:

package com.linyf.demo.date;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTime5 {
    public static void main(String[] args) {
        LocalDateTime parse = LocalDateTime.parse("2020-02-01 11:11", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        System.out.println(parse);
    }
}

执行结果:
Java8时间处理_第11张图片
注意:解析的时候,不能用DateTimeFormatter.ISO_DATE或者DateTimeFormatter.BASIC_ISO_DATE,必须用自定义格式;如果只有年月日,则不能进行解析。

6、时间比较

有时候需要比较两个时间是否相等或先后,LocalDateTime提供了对应的方法:

package com.linyf.demo.date;

import java.time.LocalDateTime;

public class LocalDateTime6 {
    public static void main(String[] args) {
        LocalDateTime time1 = LocalDateTime.of(2019, 4, 1, 12, 0);
        LocalDateTime time2 = LocalDateTime.of(2020, 4, 1, 12, 0);
        System.out.println("time1 在 time2 之前:" + time1.isBefore(time2));
    }
}

执行结果:
Java8时间处理_第12张图片
主要是这三个方法进行比较:
在这里插入图片描述

7、Date转LocalDateTime

LocalDateTime有一个很大的问题,就是spring持久化不支持LocalDateTime,有时候我们接收从前端传过来的对象,里面的日期字段只能用Date,但是使用mybatis存到数据库的时候,是支持LocalDateTime的。

可以这样来操作:

package com.linyf.demo.date;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class LocalDateTime7 {
    public static void main(String[] args) {
        Date date = new Date();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        System.out.println(localDateTime);
    }
}

执行结果:
Java8时间处理_第13张图片

8、获取月的第一天、月的最后一天,下月的第一天

package com.linyf.demo.date;

import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTime8 {
    public static void main(String[] args) {
        TemporalAdjuster firstDayOfMonth = TemporalAdjusters.firstDayOfMonth();
        TemporalAdjuster firstDayOfNextMonth = TemporalAdjusters.firstDayOfNextMonth();
        TemporalAdjuster lastDayOfMonth = TemporalAdjusters.lastDayOfMonth();
        
        LocalDateTime now = LocalDateTime.now();
        now = now.with(firstDayOfMonth);
        System.out.println("本月第一天:" + now);
        now = now.with(lastDayOfMonth);
        System.out.println("本月最后一天:" + now);
        now = now.with(firstDayOfNextMonth);
        System.out.println("下月第一天:" + now);
    }
}

执行结果:
Java8时间处理_第14张图片
利用TemporalAdjuster的静态方法可以获取本月第一天、本月最后一天、下个月第一天、下个月最后一天,LocalDateTime的with方法有一个重载版本可以接收TemporalAdjuster,这是我发现的唯一的用法。

9、获取上周或下周的任意一天

package com.linyf.demo.date;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTime9 {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now);
        now = now.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
        System.out.println(now);
        now = LocalDateTime.now();
        now = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
        System.out.println(now);
    }
}

执行结果:
Java8时间处理_第15张图片
TemporalAdjusters的静态方法previous()和next() 加上DayOfWeek可以获得上周或下周任意一天

10、获取两个时间之间的天数,进而获取两个时间之间的日期集合

package com.linyf.demo.date;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class LocalDateTime10 {
    public static void main(String[] args) {
        TemporalAdjuster firstDayOfMonth = TemporalAdjusters.firstDayOfMonth();
        TemporalAdjuster lastDayOfMonth = TemporalAdjusters.lastDayOfMonth();

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startDate = now.with(firstDayOfMonth);
        System.out.println("本月第一天:" + startDate);
        LocalDateTime endDate = now.with(lastDayOfMonth);
        System.out.println("本月最后一天:" + endDate);

        long numOfDaysBetween = Duration.between(startDate, endDate).toDays();
        System.out.println("相隔天数:" + numOfDaysBetween);

        List<LocalDateTime> collect = IntStream.iterate(0, i -> i + 1)
                .limit(numOfDaysBetween)
                .mapToObj(i -> startDate.plusDays(i))
                .collect(Collectors.toList());
        collect.add(endDate);
        collect.forEach(i -> System.out.println(i));
    }
}

执行结果:
Java8时间处理_第16张图片
Java8时间处理_第17张图片

三、springboot中使用LocalDateTime

1、将LocalDateTime字段以时间戳的形式返回给前端,添加日期转换配置类:

package com.linyf.demo;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }
    
}

然后在LocalDateTime字段上添加@JsonSerialize(using = LocalDateTimeConver.class)注解

2、将LocalDateTime字段以指定格式返回给前端,在LocalDateTime字段上添加@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = “yyyy-MM-dd HH:mm:ss”)注解。

3、对前端传入的日期进行格式化:
在LocalDateTime字段上添加@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”)注解。

你可能感兴趣的:(java)