时间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对LocalDate 和LocalDateTime的序列化上也做了友好的支持。,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);
}