java8时间类

java8新增的语法糖除了lamda,stream,还引入了新的日期时间类,支持国际化

引入的类简单分类如下

====
时间日期类
LocalDateTime 不可变的类,该类代表不带时区的日期、时间,如:2019-02-24T10:20:09
LocalDate 不可变的类,该类代表不带时区的日期,如:2019-02-24
LocalTime 不可变的类,该类代表不带时区的时间,如:10:20:09
====
年月日
Year:该类仅代表年,如:2019
YearMonth:该类仅代表年月 如:2019-02
MonthDay:该类仅代表月日,如:09-20
Month:该类是一个枚举类,定义了一月到十二月的枚举值
DayOfWeek:该类是一个枚举类,定义了周日到周六的枚举值
====
时区
ZonedDateTime:该类代表一个时区化的日期、时间 如:2022-01-09T19:50:54.751+08:00[Asia/Shanghai]
ZonedId:该类代表一个时区 Asia/Shanghai
Instant:不可变的类,代表时间戳,精确到纳秒 2022-01-09T11:52:37.879Z
====
时间段
Period:一段日期 
Duration:一段时间
====
日期格式化
DateTimeFormatter:可以格式化日期时间,线程安全

一、旧的日期时间类存在的问题

旧类存在的问题如下

1.SimpleDateFormat 线程安全问题
2.时间加减繁琐
3.时间比较相等时繁琐
4.时区支持 Date不支持时区,引入了Calendar和TimeZone类后才支持
5.国际化问题,需要在DateFormat.getDateTimeInstance 指定Locale参数

二、与Joda-Time思想借鉴

Joda-Time常用的类如下
- Instant - 不可变的类,用来表示时间轴上一个瞬时的点(时间戳)
- DateTime - 不可变的类,用来替换JDK的Calendar类
- LocalDate - 不可变的类,表示一个本地的日期,而不包含时间部分(没有时区信息)
- LocalTime - 不可变的类,表示一个本地的时间,而不包含日期部分(没有时区信息)
- LocalDateTime - 不可变的类,表示一个本地的日期-时间(没有时区信息)

java8相当于去掉了DateTime这个不可变类,使用ZonedDateTime进行替代,增加了一些时区处理类

三、与传统的日期时间类互转问题

1.Date转LocalDateTime

  //Date转LocalDateTime 方式一
    //示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
    public LocalDateTime date2LocalDateTime(Date date) {
        //方式一
        LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        return localDateTime;
    }

    //Date转LocalDateTime 方式二
    //示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
    public LocalDateTime date2LocalDateTime2(Date date) {
        //方式二 直接使用LocalDateTime.ofInstant
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return localDateTime;
    }

2.LocalDateTime转Date

 //LocalDateTime转Date
    //示例 2022-01-09T16:53:08.717 -->Sun Jan 09 16:53:08 CST 2022
    public Date localDateTime2Date(LocalDateTime localDateTime) {
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        return date;
    }

同类方法LocalDate转Date

Date date = Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

3.Calendar转LocalDateTime

//Calendar转LocalDateTime
    //示例 Sun Jan 09 16:49:04 CST 2022 --> 2022-01-09T16:49:04.264
    public LocalDateTime calendar2LocalDateTime(Calendar calendar) {
        //方式一
        LocalDateTime localDateTime = calendar.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        //方式二
        LocalDateTime localDateTime2 = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
        return localDateTime;
    }

4.LocalDateTime转Calendar

//LocalDateTime转Calendar
    public Calendar localDateTime2Calendar(LocalDateTime localDateTime) {
        Calendar localDateTimeCalendar = GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));
        return localDateTimeCalendar;
    }

四、常用方法

1.当前时间和毫秒时间戳

  //当前时间LocalDateTime
    //示例 2022-01-09T17:26:43.537
    public LocalDateTime currentLocalDateTime(){
        LocalDateTime now = LocalDateTime.now();
        return now;
    }

    //当前时间时间戳 毫秒
    //示例 1641720403538
    public Long currentMillisecondTimestamp() {
        //获取毫秒数
        Long milliSecond = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        return milliSecond;
    }

2.年月日时分秒获取

LocalDateTime localDateTime = LocalDateTime.now();

        localDateTime.getYear(); //2022
        localDateTime.getMonth(); //JANUARY
        localDateTime.getDayOfMonth();//9
        localDateTime.getHour(); //17
        localDateTime.getMinute(); //32
        localDateTime.getSecond(); //25

3.时间加减

LocalDateTime localDateTime1 = localDateTime.plusYears(1).plusMonths(1).plusDays(1).plusHours(1).plusMinutes(1).plusSeconds(1);
        

注意调用plusXXX不会改变原来的localDateTime值,需要用变量接受加完后的值,plus负值相当于减法

4.时间比较

        localDateTime.isBefore(localDateTime1);
        localDateTime.isEqual(localDateTime1);
        localDateTime.isAfter(localDateTime1);

返回的是 boolean 类型 跟旧时间类相比,对于等于的判断不用写getTime再比较了

5.初始化指定日期时间

 LocalDateTime of = LocalDateTime.of(2022, 1, 8, 8, 01, 46);
        //结果 2022-01-08T08:01:46

使用LocalDateTime.of方法直接初始化

6.格式化日期

LocalDateTime转字符串

 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String strDate = dateTimeFormatter.format(LocalDateTime.now());
        System.out.println(strDate);
        //2022-01-09 17:54:25

先定义DateTimeFormatter,然后调用format方法

字符串转LocalDateTime

        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String strDate2 = "2022-01-09 06:54:25";
        LocalDateTime time1 = LocalDateTime.parse(strDate2, dateTimeFormatter1);
        System.out.print(time1);
        //2022-01-09T06:54:25

先定义DateTimeFormatter,然后调用parse方法

7.计算时间差

 Duration.between方法,结果为后一个减去前一个,返回结果可以转秒数,分钟数

   //localDateTime = 2022-01-09T18:13:02.750 localDateTime1=2022-03-08T08:01:46
        Duration duration = Duration.between(localDateTime, localDateTime1);
        System.out.println(duration); //PT1381H48M43.25S
        System.out.println(duration.toDays()); //转天数 57
        System.out.println(duration.toHours()); //转小时 1381
        System.out.println(duration.toMinutes()); //转分钟数 82908
        System.out.println(duration.getSeconds()); //转秒数 4974523
        System.out.println(duration.toMillis()); //转毫秒数 4974523250
        System.out.println(duration.toNanos()); //转纳秒数 4974523250000000

Period.between方法与Duration.between方法类似,只不过参数类型为LocalDate,返回值对应方法不一样,返回只是对应年月日相减,去除的是对应年月日的值

        LocalDate start = LocalDate.of(2021,3,25);
        LocalDate end = LocalDate.of(2022,5,29);
        Period period = Period.between(start, end);
        System.out.println(period); //P1Y2M4D
        System.out.println(period.getYears());  //1
        System.out.println(period.getMonths());  //2
        System.out.println(period.getDays());  //4

注意Period的方法取的是对应位置相减的值,而Duration的方法取的是纳秒值换算后的值

ChronoUnit.YEARS.between方法,返回与Duration.between类似

LocalDateTime startDate = LocalDateTime.of(2020, 2, 20, 8, 1, 46);
        LocalDateTime endDate = LocalDateTime.of(2021, 1, 15, 8, 1, 46);
        long years = ChronoUnit.YEARS.between(startDate, endDate); //0
        long months = ChronoUnit.MONTHS.between(startDate, endDate); //10
        long weeks = ChronoUnit.WEEKS.between(startDate, endDate); //47
        long days = ChronoUnit.DAYS.between(startDate, endDate); //330
        long hours = ChronoUnit.HOURS.between(startDate, endDate); //7920
        long minutes = ChronoUnit.MINUTES.between(startDate, endDate); //475200
        long seconds = ChronoUnit.SECONDS.between(startDate, endDate); //28512000
        long milis = ChronoUnit.MILLIS.between(startDate, endDate); //28512000000
        long nano = ChronoUnit.NANOS.between(startDate, endDate); //28512000000000000

ChronoUnit.YEARS.between也可用于LocalDate,但是ChronoUnit.HOURS.between不能用于LocalDate会报UnsupportedTemporalTypeException异常,网上也有个Instant不能用于ChronoUnit.YEARS的讨论,猜想应该是时区的问题,假设一个时间北京时间2000年2月29日8点东八区,此时对应美国中部时间 2000年2月28日18点(西四区),用LocalDateTime的plusYears加一年,一个实际上加365天,另一个加了366天。所以放到未确定时区的Instant(默认UTC+0),无法分辨应该是加365天还是366天

LocalDateTime的plusYears验证代码如下

        //东八区2000-02-29 08:00:00 =  西四区	2000-02-28 18:00:00
        LocalDateTime startDate = LocalDateTime.of(2000, 2, 29, 8, 0, 0);
        LocalDateTime localDateTime1 = startDate.plusYears(1);
        LocalDateTime localDateTime2 = startDate.plusDays(365);
        System.out.println(localDateTime1); //2001-02-28T08:00
        System.out.println(localDateTime2); //2001-02-28T08:00


        LocalDateTime startDate2 = LocalDateTime.of(2000, 2, 28, 18, 0, 0);
        LocalDateTime localDateTime21 = startDate2.plusYears(1);
        LocalDateTime localDateTime22 = startDate2.plusDays(366);
        System.out.println(localDateTime21); //2001-02-28T18:00
        System.out.println(localDateTime22); //2001-02-28T18:00

五、json格式转换问题

在java里常用的json工具类有下面四个

jackson
fastjson
gson
json-lib(net.sf.json) 

安卓里有个常用的org.json这里不介绍。

从序列化和反序列化调用的结果来看,fastjson最省事,其次是jackson。

1.json序列化及问题解决

下面用这四个工具类测试对时间类的转换结果

先用maven导入

 <!--fastjson包-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>



        <!--Jackson包-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>

        <!--gson包-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>


        <!--json-lib包-->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>

定义实体

package com.vvvtimes.vo;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class DateVo implements Serializable {

    private LocalDateTime localDateTime;

    private LocalDate localDate;

    private LocalTime localTime;

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }

    public LocalDate getLocalDate() {
        return localDate;
    }

    public void setLocalDate(LocalDate localDate) {
        this.localDate = localDate;
    }

    public LocalTime getLocalTime() {
        return localTime;
    }

    public void setLocalTime(LocalTime localTime) {
        this.localTime = localTime;
    }
}

使用四个json工具类转换测试

      DateVo dateVo = new DateVo();
        dateVo.setLocalDateTime(LocalDateTime.now());
        dateVo.setLocalDate(LocalDate.now());
        dateVo.setLocalTime(LocalTime.now());


        System.out.println(dateVo.getLocalDateTime());
        //2022-01-15T22:19:37.752
        System.out.println(dateVo.getLocalDate());
        //2022-01-15
        System.out.println(dateVo.getLocalTime());
        //22:19:37.752

        //jackson将对象转字符串

        //1.创建objectmappter对象
        ObjectMapper mapper=new ObjectMapper();
        //2.调用mapper的writeValueAsString()方法把一个对象或集合转为json字符串
        String jsonStr=mapper.writeValueAsString(dateVo);
        System.out.println(jsonStr);
        //结果
        //{"localDateTime":{"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"hour":22,"minute":10,"month":"JANUARY","monthValue":1,"nano":80000000,"second":48,"year":2022,"chronology":{"id":"ISO","calendarType":"iso8601"}},"localDate":{"year":2022,"month":"JANUARY","dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"monthValue":1,"chronology":{"id":"ISO","calendarType":"iso8601"},"era":"CE","leapYear":false},"localTime":{"hour":22,"minute":10,"second":48,"nano":81000000}}


        //fastjson将对象转字符串
        String str = JSON.toJSONString(dateVo);
        System.out.println(str);
        //结果
        //{"localDate":"2022-01-15","localDateTime":"2022-01-15T22:13:18.689","localTime":"22:13:18.689"}

        //gson将对象转字符串
        Gson gson = new Gson();
        String gsonStr = gson.toJson(dateVo);
        System.out.println(str);
        //结果
        //{"localDate":"2022-01-15","localDateTime":"2022-01-15T22:14:54.209","localTime":"22:14:54.210"}


        //json-lib将对象转字符串
        JSONObject obj = JSONObject.fromObject(dateVo);
        System.out.println(obj.toString());
        //结果
        //{"localDate":{"chronology":{"calendarType":"iso8601","id":"ISO"},"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"era":"CE","leapYear":false,"month":"JANUARY","monthValue":1,"year":2022},"localDateTime":{"dayOfMonth":15,"dayOfWeek":"SATURDAY","dayOfYear":15,"hour":22,"minute":17,"month":"JANUARY","monthValue":1,"nano":952000000,"second":27,"year":2022},"localTime":{"hour":22,"minute":17,"nano":952000000,"second":27}}

可以看到jackson和json-lib转换的记过出乎我们的意料,并非正常的toString结果。

(1)解决序列化报错问题

对于jackson需要增加导入jackson-datatype-jsr310,mapper注册com.fasterxml.jackson.datatype.jsr310.JavaTimeModule并禁用Date转时间戳的序列化特性

maven导入代码

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.9.10</version>
        </dependency>

jackson完整代码

        //jackson将对象转字符串

        //1.创建objectmappter对象
        ObjectMapper mapper=new ObjectMapper();
        //处理java8时间类型新增代码
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        //2.调用mapper的writeValueAsString()方法把一个对象或集合转为json字符串
        String jsonStr=mapper.writeValueAsString(dateVo);
        System.out.println(jsonStr);
        //结果
        //{"localDateTime":"2022-01-15T22:51:52.616","localDate":"2022-01-15","localTime":"22:51:52.616"}

json-lib解决方案

写三个JsonValueProcessor的实现类,调用前注册进去就OK

LocalDateJsonValueProcessor

package com.vvvtimes.util.jsonlib;

import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

//序列化 实体类LocalDate --> JSONObject
public class LocalDateJsonValueProcessor implements JsonValueProcessor {
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";

    private DateTimeFormatter formatter;


    /**
     * 构造方法.
     *
     * @param datePattern 日期格式
     */
    public LocalDateJsonValueProcessor(String datePattern) {
        try {
            formatter = DateTimeFormatter.ofPattern(datePattern);
        } catch (Exception ex) {
            formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);

        }
    }

    @Override
    public Object processArrayValue(Object value, JsonConfig jsonConfig) {
        return process(value);
    }

    @Override
    public Object processObjectValue(String key, Object value,
                                     JsonConfig jsonConfig) {
        return process(value);
    }

    private Object process(Object value) {
        return formatter.format((LocalDate) value);
    }
}

LocalDateTimeJsonValueProcessor

package com.vvvtimes.util.jsonlib;

import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;

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


//序列化 实体类LocalDateTime --> JSONObject
public class LocalDateTimeJsonValueProcessor implements JsonValueProcessor {
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";

    private DateTimeFormatter formatter;


    /**
     * 构造方法.
     *
     * @param datePattern 日期格式
     */
    public LocalDateTimeJsonValueProcessor(String datePattern) {
        try {
            formatter = DateTimeFormatter.ofPattern(datePattern);
        } catch (Exception ex) {
            formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);

        }
    }

    @Override
    public Object processArrayValue(Object value, JsonConfig jsonConfig) {
        return process(value);
    }

    @Override
    public Object processObjectValue(String key, Object value,
                                     JsonConfig jsonConfig) {
        return process(value);
    }

    private Object process(Object value) {
        return formatter.format((LocalDateTime) value);
    }
}

LocalTimeJsonValueProcessor

package com.vvvtimes.util.jsonlib;

import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;


//序列化 实体类LocalTime --> JSONObject
public class LocalTimeJsonValueProcessor implements JsonValueProcessor {
    public static final String DEFAULT_DATE_PATTERN = "HH:mm:ss.SSS";

    private DateTimeFormatter formatter;


    /**
     * 构造方法.
     *
     * @param datePattern 日期格式
     */
    public LocalTimeJsonValueProcessor(String datePattern) {
        try {
            formatter = DateTimeFormatter.ofPattern(datePattern);
        } catch (Exception ex) {
            formatter = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);

        }
    }

    @Override
    public Object processArrayValue(Object value, JsonConfig jsonConfig) {
        return process(value);
    }

    @Override
    public Object processObjectValue(String key, Object value,
                                     JsonConfig jsonConfig) {
        return process(value);
    }

    private Object process(Object value) {
        return formatter.format((LocalTime) value);
    }
}

调用结果成功

        DateVo dateVo = new DateVo();
        dateVo.setLocalDateTime(LocalDateTime.now());
        dateVo.setLocalDate(LocalDate.now());
        dateVo.setLocalTime(LocalTime.now());


        //json-lib将对象转字符串
        JsonConfig jsonConfig = new JsonConfig();

        jsonConfig.registerJsonValueProcessor(LocalDate.class, new LocalDateJsonValueProcessor(
                LocalDateJsonValueProcessor.DEFAULT_DATE_PATTERN));
        jsonConfig.registerJsonValueProcessor(LocalDateTime.class, new LocalDateTimeJsonValueProcessor(
                LocalDateTimeJsonValueProcessor.DEFAULT_DATE_PATTERN));
        jsonConfig.registerJsonValueProcessor(LocalTime.class, new LocalTimeJsonValueProcessor(
                LocalTimeJsonValueProcessor.DEFAULT_DATE_PATTERN));
        
        JSONObject obj = JSONObject.fromObject(dateVo, jsonConfig);
        System.out.println(obj.toString());
        //结果{"localDate":"2022-01-16","localDateTime":"2022-01-16T17:37:01.563","localTime":"17:37:01.563"}

2.json反序列化及问题解决

再看看反序列化的效果

为了方便打印实体,使用lombook的@Data注解改写实体toString方法

lombook的maven引入

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
            <scope>provided</scope>
        </dependency>

DateVo类,使用@Date注解,去掉原有的getter setter方法

package com.vvvtimes.vo;

import lombok.Data;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

@Data
public class DateVo implements Serializable {

    private LocalDateTime localDateTime;

    private LocalDate localDate;

    private LocalTime localTime;


}

反序列化代码

String dateVoStr = "{\"localDate\":\"2022-01-15\",\"localDateTime\":\"2022-01-15T22:51:52.616\",\"localTime\":\"22:51:52.616\"}";


        //jackson将字符串转对象
        ObjectMapper mapper = new ObjectMapper();
        //处理java8时间类型新增代码
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        DateVo dateVo1 = mapper.readValue(dateVoStr, DateVo.class);
        System.out.println(dateVo1);
        //结果
        //DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)

        //fastjson将字符串转对象
        DateVo dateVo2 = JSON.parseObject(dateVoStr, DateVo.class);
        System.out.println(dateVo2);
        //结果
        //DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)

        //gson将字符串转对象
        DateVo dateVo3 = new Gson().fromJson(dateVoStr, DateVo.class);
        System.out.println(dateVo3);
        //结果报错
        //Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 15 path $.localDate


        //json-lib将字符串转对象
        JSONObject jsonObject = JSONObject.fromObject(dateVoStr);
        DateVo dateVo4 = (DateVo) JSONObject.toBean(jsonObject, DateVo.class);
        //结果报错
        //一月 16, 2022 2:26:42 下午 net.sf.json.JSONObject morphPropertyValue
        //警告: Can't transform property 'localDate' from java.lang.String into java.time.LocalDate. Will register a default Morpher
        //Exception in thread "main" net.sf.json.JSONException: Error while setting property=localDate type class java.lang.String

可以看到,除了fastjson,其他的使用普通的反序列化都会报错,这里jackson没报错是因为序列化的时候引入jsr310的JavaTimeModule。

(1)解决反序列化报错问题

jackson报错处理

跟json序列化一样。引入jsr310,不赘述

gson报错处理

需要重写com.google.gson.JsonDeserializer<T>的反序列化方法deserialize,实现如下(这里顺带实现了com.google.gson.JsonSerializer<T>的序列化方法serialize)    

LocalDate反序列化实现LocalDateDeserializer.java

package com.vvvtimes.util;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class LocalDateDeserializer implements JsonDeserializer<LocalDate> {
    @Override
    public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        return LocalDate.parse(json.getAsString(),
                DateTimeFormatter.ofPattern("yyyy-MM-dd").withLocale(Locale.CHINESE));
    }
}

LocalDate序列化实现LocalDateSerializer.java

package com.vvvtimes.util;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateSerializer implements JsonSerializer<LocalDate> {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public JsonElement serialize(LocalDate localDate, Type srcType, JsonSerializationContext context) {
        return new JsonPrimitive(formatter.format(localDate));
    }
}

LocalDateTime反序列化实现

package com.vvvtimes.util;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        return LocalDateTime.parse(json.getAsString(),
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").withLocale(Locale.CHINESE));
    }
}

LocalDateTime序列化实现

package com.vvvtimes.util;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");

    @Override
    public JsonElement serialize(LocalDateTime localDateTime, Type srcType, JsonSerializationContext context) {
        return new JsonPrimitive(formatter.format(localDateTime));
    }
}

LocalTime反序列化实现

package com.vvvtimes.util;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class LocalTimeDeserializer implements JsonDeserializer<LocalTime> {
    @Override
    public LocalTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        return LocalTime.parse(json.getAsString(),
                DateTimeFormatter.ofPattern("HH:mm:ss.SSS").withLocale(Locale.CHINESE));
    }
}

LocalTime序列化实现

package com.vvvtimes.util;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class LocalTimeSerializer implements JsonSerializer<LocalTime> {
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");

    @Override
    public JsonElement serialize(LocalTime localTime, Type srcType, JsonSerializationContext context) {
        return new JsonPrimitive(formatter.format(localTime));
    }
}

gson中需要注册这些实现在调用反序列化方法

        //gson将字符串转对象
        GsonBuilder gsonBuilder = new GsonBuilder();
        //注册刚序列化实现
        gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
        gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer());
        gsonBuilder.registerTypeAdapter(LocalTime.class, new LocalTimeSerializer());
        //注册反序列化实现
        gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
        gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeDeserializer());
        gsonBuilder.registerTypeAdapter(LocalTime.class, new LocalTimeDeserializer());
        Gson gson = gsonBuilder.setPrettyPrinting().create();

        DateVo dateVo3 = gson.fromJson(dateVoStr, DateVo.class);
        System.out.println(dateVo3);
        //结果正常
        //DateVo(localDateTime=2022-01-15T22:51:52.616, localDate=2022-01-15, localTime=22:51:52.616)

json-lib报错处理

反序列的实现并没有序列的实现简单,不像序列化那样实现方法就行。在尝试重写Morpher类并调用JSONUtils.getMorpherRegistry().registerMorpher()后,PropertySetStrategy的setProperty方法还需要处理。暂时不弄了。

六、数据库类型适配问题

mybatis使用报错

对于mybatis3.4以下,需要引入jsr310依赖,高版本(3.4.5以上)不需要

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-typehandlers-jsr310</artifactId>
	<version>1.0.1</version>
</dependency>

mybatis-config.xml 需要添加配置

<typeHandlers>
	<typeHandler handler="org.apache.ibatis.type.InstantTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.LocalDateTimeTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.LocalDateTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.LocalTimeTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.OffsetDateTimeTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.OffsetTimeTypeHandler" />
	<typeHandler handler="org.apache.ibatis.type.ZonedDateTimeTypeHandler" />
</typeHandlers>

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值