时间api LocaDate LocaDateTime

  • 在java8中提供了一套全新的时间api来更好的处理之前date 时间api 的问题。
  • 例如:SimpleDateFormat 并发不安全问题,时区时间转换问题。
  • 旧的时间api 存在java.util包中。新版的时间api 在java.time包中。

举个栗子:
传统时间得到当前时间为:

Date date = new Date();

打印结果为;Thu May 07 17:19:45 CST 2020
Thu代表Thursday(周四),May代表May(五月),07代表7号,CST代表China Standard Time(中国标准时间,也就是北京时间(东八区))。
如果需要修改时间就需要借助java.util.Calendar类(日历类)进行处理。时间转换上需要借助 SimpleDateFormat 类进行处理
注意:SimpleDateFormat 是一个线程不安全的类。千万不要设置成为静态属性。
关于传统时间Date的例子我就不再多举例了,相信大家都比较熟悉。
java8 新时间设计的比较友好:
例如:

/**
* 得到当前时间 不需要再去new 时间
* 这里得到的时间为:在ISO-8601日历系统中没有时区的日期时间
* 结果为:2020-05-07T17:38:58.612140200
*/
LocalDateTime time = LocalDateTime.now();
  • 传统的Date也能友好的转换为LocalDateTime
//Date 转 LocalDateTime
    public LocalDateTime dateConvertToLocalDateTime(Date date){
        //中国北京时间东八区
        OffsetDateTime offsetDateTime = date.toInstant().atOffset(ZoneOffset.of("+8"));
        LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
        return localDateTime;
    }
   
//LocalDateTime 转Date 
Instant instant =  LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
Date nowDate= Date.from(instant);

//自定义时区
Instant myselfInstant =  LocalDateTime.now().toInstant(ZoneOffset.of("+8"));
Date nowMyseDate= Date.from(myselfInstant);
  • 我们想格式化时间 就需要 DateTimeFormatter进行数据的格式化。
LocalDateTime time = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = time.format(formatter);
System.out.println(format);

这样我们就得到了格式化后的时间。

  • 每天的开始结束时间,日期的加减java8就显的更加友好
//得到明天当前时间
LocalDateTime tomorrowTime = LocalDateTime.now().plusDays(1);
//得到昨天当前时间
LocalDateTime yesterdayTime = LocalDateTime.now().plusDays(-1);

 //得到下一小时月份,月份,周,年 等 可以使用plus 方法
LocalDateTime lastWeekTime = LocalDateTime.now().plus(1, ChronoUnit.WEEKS);

//得到当天开始结束时间
LocalDateTime nowTime = LocalDateTime.now();
LocalDateTime startTime = LocalDateTime.of(nowTime.toLocalDate(), LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(nowTime.toLocalDate(), LocalTime.MAX);

LocalDateTime.of() 方法重载了许多,大家可以自行查询api 自定义 LocalDateTime 时间的返回。

  • LocalDateTime 转毫秒稍微复杂,但是可拓展性特别友好:
//传统得到时间的毫秒
long time = new Date().getTime();
//新版api 可以转换成任意时区对应的时间戳 比较方便。ZoneId.systemDefault() 为系统默认时区,也会是系统设置的时间
LocalDateTime dateTime = LocalDateTime.now();
long nowLong = dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

//例如中国在东八区   ZoneOffset.of("+8") 设置为东八区
long nowLongZone = dateTime.dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
  • 如果要把 LocalDateTime 转换为 时间戳 参考上方。
  • 如果把LocalDateTime 转换为String类型的时间 可以用DateTimeFormatter 进行转换。
  • 如果把 String时间转成时间戳 这里建议大家封装一个工具类。基本思路就是String时间类转换成 LocalDateTime再转换时间戳。
  • Long转String同理。下方转换仅供参考:
/**
 * LocalDateTime 转String
 */
public static String localDateTimeToString(LocalDateTime dateTime, String pattern) {
        DateTimeFormatter formatter = null;
        if (org.apache.commons.lang3.StringUtils.isBlank(pattern)) {
            formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        } else {
            formatter = DateTimeFormatter.ofPattern(pattern);
        }
        return dateTime.format(formatter);
    }
/**
 * Long转String 通过LocalDateTime
 */
public static String longToStringByLocalDateTime(Long time, String pattern) {
        DateTimeFormatter dateTimeFormatter;
        if (org.apache.commons.lang3.StringUtils.isBlank(pattern)) {
            dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        } else {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        }
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
        return dateTimeFormatter.format(localDateTime);
    }
  • java8还提供了一个日期类 LocalDate LocalDate的操作相对日期类型更加方便高效。
String nowDate = LocalDate.now().toString();
 //2020-05-07 打印结果
 System.out.println(nowDate);
  • 同样 plusDays() 方法,plus(),方法都适用。每天初始结束时间更加的方便。每天开始结束时间LocalDateTime 就是借助LocalDate进行格式化的。
  • LocalDate 在日期对比处理上面相对于传统的Date更加简洁。
//Birthday
        LocalDate nowDate = LocalDate.now();
        LocalDate selfDate = LocalDate.of(2019, 11, 1);
        //比较两个日期
        boolean equals = nowDate.equals(selfDate);
        System.out.println(equals);
        //返回月份和时间 两种方式
        MonthDay monthDay = MonthDay.of(nowDate.getMonth(), nowDate.getDayOfMonth());
        MonthDay selfMonthDay = MonthDay.from(selfDate);
        System.out.println(monthDay);
        System.out.println(selfMonthDay);

        //比较两个日期的MonthDay
        Period between = Period.between(selfDate, nowDate);
        int days = between.getDays();
        int months = between.getMonths();
        System.out.println(days);
        System.out.println(months);
        //年纪
        int year = (int)selfDate.until(nowDate, ChronoUnit.YEARS);
        System.out.println(year);
		//判断是否为闰年
        YearMonth of = YearMonth.of(2020, 4);
        boolean leapYear = of.isLeapYear();
        System.out.println(leapYear);
  • 具体年月日操作还需参考java8的时间api

结尾

  • 值得一提的是 Jackson对LocalDateLocalDateTime的序列化上也做了友好的支持。,Long 转String,空转“” 等可参考以下配置。同样fastJson也支持这些配置,思路大致相同。这里没有写出时间的统一转化。暂时还没有研究明白。
@Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = converter.getObjectMapper();
        // 生成JSON时,将所有Long转换成String
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);

        //Jackson 配置 null 转空字符串
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object paramT, JsonGenerator paramJsonGenerator,
                                  SerializerProvider paramSerializerProvider) throws IOException {
                //设置返回null转为 空字符串""
                paramJsonGenerator.writeString("");
            }
        });

        //设置时区 也可设置为东八区北京时间
        objectMapper.setTimeZone(TimeZone.getDefault());
        
        // 在序列化一个空对象时时不抛出异常
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // 忽略反序列化时在json字符串中存在, 但在java对象中不存在的属性
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 设置格式化内容
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
    }