关于java:为什么建议使用你-LocalDateTime而不是-Date

48次阅读

共计 6076 个字符,预计需要花费 16 分钟才能阅读完成。

为什么倡议应用你 LocalDateTime,而不是 Date?

  • Date如果不格式化,打印出的日期可读性差
Tue Sep 10 09:34:04 CST 2019 
  • 应用 SimpleDateFormat 对工夫进行格式化,但 SimpleDateFormat 是线程不平安的 SimpleDateFormatformat办法最终调用代码:
private StringBuffer format(Date date, StringBuffer toAppendTo,  
                              FieldDelegate delegate) {  
        // Convert input date to time field list  
        calendar.setTime(date);  
        boolean useDateFormatSymbols = useDateFormatSymbols();  
        for (int i = 0; i < compiledPattern.length;) {int tag = compiledPattern[i] >>> 8;  
            int count = compiledPattern[i++] & 0xff;  
            if (count == 255) {count = compiledPattern[i++] << 16;  
                count |= compiledPattern[i++];  
            }  
            switch (tag) {  
            case TAG_QUOTE_ASCII_CHAR:  
                toAppendTo.append((char)count);  
                break;  
            case TAG_QUOTE_CHARS:  
                toAppendTo.append(compiledPattern, i, count);  
                i += count;  
                break;  
            default:  
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);  
                break;  
            }  
        }  
        return toAppendTo;  
    } 

calendar是共享变量,并且这个共享变量没有做线程安全控制。当多个线程同时应用 雷同的 SimpleDateFormat 对象 【如用static 润饰的 SimpleDateFormat】调用format 办法时,多个线程会同时调用 calendar.setTime 办法,可能一个线程刚设置好 time 值另外的一个线程马上把设置的 time 值给批改了导致返回的格式化工夫可能是谬误的。在多并发状况下应用 SimpleDateFormat 需分外留神 SimpleDateFormat 除了 format 是线程不平安以外,parse办法也是线程不平安的。parse办法理论调用 alb.establish(calendar).getTime() 办法来解析,alb.establish(calendar)办法里次要实现了

  1. 重置日期对象 cal 的属性值
  1. 应用 calb 中中属性设置 cal
  1. 返回设置好的 cal 对象

然而这三步不是原子操作

多线程并发如何保障线程平安 – 防止线程之间共享一个 SimpleDateFormat 对象,每个线程应用时都创立一次 SimpleDateFormat 对象 => 创立和销毁对象的开销大 – 对应用 formatparse办法的中央进行加锁 => 线程阻塞性能差 – 应用 ThreadLocal 保障每个线程最多只创立一次 SimpleDateFormat 对象 => 较好的办法

  • Date对工夫解决比拟麻烦,比方想获取某年、某月、某星期,以及 n 天当前的工夫,如果用 Date 来解决的话真是太难了,你可能会说 Date 类不是有 getYeargetMonth 这些办法吗,获取年月日很Easy,但都被弃用了啊

Come On 一起应用 java8 全新的日期和工夫 API

LocalDate

只会获取年月日

  • 创立LocalDate
// 获取以后年月日  
LocalDate localDate = LocalDate.now();  
// 结构指定的年月日  
LocalDate localDate1 = LocalDate.of(2019, 9, 10); 
  • 获取年、月、日、星期几
int year = localDate.getYear();  
int year1 = localDate.get(ChronoField.YEAR);  
Month month = localDate.getMonth();  
int month1 = localDate.get(ChronoField.MONTH_OF_YEAR);  
int day = localDate.getDayOfMonth();  
int day1 = localDate.get(ChronoField.DAY_OF_MONTH);  
DayOfWeek dayOfWeek = localDate.getDayOfWeek();  
int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK); 
LocalTime

只会获取几点几分几秒

  • 创立LocalTime
 LocalTime localTime = LocalTime.of(13, 51, 10);  
 LocalTime localTime1 = LocalTime.now(); 
  • 获取时分秒
// 获取小时  
int hour = localTime.getHour();  
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);  
// 获取分  
int minute = localTime.getMinute();  
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);  
// 获取秒  
int second = localTime.getSecond();  
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE); 
LocalDateTime

获取年月日时分秒,等于 LocalDate+LocalTime

  • 创立LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();  
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);  
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);  
LocalDateTime localDateTime3 = localDate.atTime(localTime);  
LocalDateTime localDateTime4 = localTime.atDate(localDate); 
  • 获取LocalDate
LocalDate localDate2 = localDateTime.toLocalDate(); 
  • 获取LocalTime
LocalTime localTime2 = localDateTime.toLocalTime(); 
Instant

获取秒数

  • 创立 Instant 对象
Instant instant = Instant.now(); 
  • 获取秒数
long currentSecond = instant.getEpochSecond(); 
  • 获取毫秒数
long currentMilli = instant.toEpochMilli(); 

集体感觉如果只是为了获取秒数或者毫秒数,应用 System.currentTimeMillis() 来得更为不便

批改 LocalDate、LocalTime、LocalDateTime、Instant

LocalDateLocalTimeLocalDateTimeInstant 不可变对象 ,批改这些对象对象会 返回一个正本

  • 减少、缩小年数、月数、天数等 以
LocalDateTime 

为例

LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,  
              14, 46, 56);  
// 减少一年  
localDateTime = localDateTime.plusYears(1);  
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);  
// 缩小一个月  
localDateTime = localDateTime.minusMonths(1);  
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS); 
  • 通过
with 

批改某些值

// 批改年为 2019  
localDateTime = localDateTime.withYear(2020);  
// 批改为 2022  
localDateTime = localDateTime.with(ChronoField.YEAR, 2022); 

还能够批改月、日

工夫计算

比方有些时候想晓得这个月的最初一天是几号、下个周末是几号,通过提供的工夫和日期 API 能够很快失去答案

LocalDate localDate = LocalDate.now();  
LocalDate localDate1 = localDate.with(firstDayOfYear()); 

比方通过 firstDayOfYear() 返回了以后日期的第一天日期,还有很多办法这里不在举例说明

格式化工夫
LocalDate localDate = LocalDate.of(2019, 9, 10);  
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);  
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);  
// 自定义格式化  
DateTimeFormatter dateTimeFormatter =   DateTimeFormatter.ofPattern("dd/MM/yyyy");  
String s3 = localDate.format(dateTimeFormatter); 

DateTimeFormatter默认提供了多种格式化形式,如果默认提供的不能满足要求,能够通过 DateTimeFormatterofPattern办法创立自定义格式化形式

解析工夫
LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);  
LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE); 

SimpleDateFormat 相比,DateTimeFormatter是线程平安的

小结

LocalDateTimeDate有的我都有,Date没有的我也有,日期抉择请Pick Me

====================== Update On 2019/09/18 =================

SpringBoot 中利用 LocalDateTime

  • 将 LocalDateTime 字段以工夫戳的形式返回给前端 增加日期转化类
public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {  
    @Override  
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());  
    }  
} 

并在

LocalDateTime 

字段上增加

@JsonSerialize(using = LocalDateTimeConverter.class) 

注解,如下:

@JsonSerialize(using = LocalDateTimeConverter.class)  
protected LocalDateTime gmtModified; 
  • 将 LocalDateTime 字段以指定格式化日期的形式返回给前端 在
LocalDateTime 

字段上增加

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss") 

注解即可,如下:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")  
protected LocalDateTime gmtModified; 
  • 对前端传入的日期进行格式化 在
LocalDateTime 

字段上增加

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 

注解即可,如下:

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  
protected LocalDateTime gmtModified; 

正文完
 0