乐趣区

关于java8:JAVA8实战-日期API

JAVA8 实战 – 日期 API

前言

​ 这一节咱们来讲讲 JAVA8 的日期类,源代码的作者其实就是 Joda-Time,所以能够看到很多代码的 API 和 Joda 类比拟像。日期类始终是一个比拟难用的货色,然而 JAVA8 给日期类提供了一套新的 API 让日期类更加好用。

​ 本文代码较多,倡议亲自运行代码了解。

内容概述:

  1. 对于 JDK8 日期的三个外围类:LocalDate、LocalTime、LocalDateTime 的相干介绍
  2. 机器工夫和日期格局 Instant 等对于细粒度的工夫操作介绍
  3. TemporalAdjusters 用于更加简单的日期计算,比方计算下一个工作日的时候这个类提供了一些实现
  4. DateTimeFormatter 格式化器,十分的灵便多变,属于 SimpleDateFormat 的替代品。
  5. 日期 API 的一些集体工具封装举例,以及在应用 JDK8 的时候一些集体的踩坑

​ 最初心愿通过本文能帮你解脱new Date()

什么是 ISO-8601?

​ 日期离不开 ISO-8601,上面对 ISO-8601 简略形容一下,参考自百度百科:

  1. ISO-8601: 国际标准化组织制订的日期和工夫的示意办法,全称为《数据存储和替换模式·信息替换·日期和工夫的示意办法》,简称为 ISO-8601。
  2. 日的示意:小时、分和秒都用 2 位数示意,对 UTC 工夫最初加一个大写字母 Z,其余时区用理论工夫加时差示意。如 UTC 工夫下午 2 点 30 分 5 秒示意为 14:30:05Z 或 143005Z,过后的北京工夫示意为 22:30:05+08:00 或 223005+0800,也能够简化成 223005+08。
  3. 日期和工夫的组合示意:合并示意时,要在工夫后面加一大写字母 T,如要示意北京工夫 2004 年 5 月 3 日下午 5 点 30 分 8 秒,能够写成 2004-05-03T17:30:08+08:00 或 20040503T173008+08。

LocalDate、LocalTime、LocalDateTime

​ JDK8 把工夫拆分成了三个大部分,一个是工夫,代表了年月日的信息,一个是日期,代表了时分秒的局部,最初是这两个对象总和具体的工夫。

LocalDate

LocalDate:类示意一个具体的日期,但不蕴含具体工夫,也不蕴含时区信息。能够通过 LocalDate 的静态方法 of() 创立一个实例,LocalDate也蕴含一些办法用来获取年份,月份,天,星期几等,上面是 LocalDate 的常见应用形式:


    @Test
    public void localDateTest() throws Exception {
        // 创立一个 LocalDate:
        LocalDate of = LocalDate.of(2021, 8, 9);
        // 获取以后工夫
        LocalDate now = LocalDate.now();
        // 格式化
        LocalDate parse1 = LocalDate.parse("2021-05-11");
        // 指定日期格式化
        LocalDate parse2 = LocalDate.parse("2021-05-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        // 上面的代码会呈现格式化异样
        // java.time.format.DateTimeParseException: Text '2021-05-11 11:53:53' could not be parsed, unparsed text found at index 10
//        LocalDate parse3 = LocalDate.parse("2021-05-11 11:53:53", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 正确的格式化办法
        LocalDate parse3 = LocalDate.parse("2021-05-11 11:53:53", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        // 以后工夫
        System.out.println("now() =>"+ now);
        // 获取月份
        int dayOfMonth = parse1.getDayOfMonth();
        System.out.println("dayOfMonth =>" + dayOfMonth);
        // 获取年份
        int dayOfYear = parse1.getDayOfYear();
        System.out.println("getDayOfYear =>" + dayOfYear);
        // 获取那一周,留神这里获取的是对象
        DayOfWeek dayOfWeek = parse1.getDayOfWeek();
        System.out.println("getDayOfWeek =>" + dayOfWeek);
        // 获取月份数据
        int monthValue = parse3.getMonthValue();
        System.out.println("getMonthValue =>" + monthValue);
        // 获取年份
        int year = parse3.getYear();
        System.out.println("getYear =>" + year);
        // getChronology 获取的是以后工夫的排序,这里输入后果是 ISO
        System.out.println("getChronology =>" + parse3.getChronology());
        System.out.println("getEra =>" + parse3.getEra());


        // 应用 timeField 获取值:TemporalField 是一个接口,定义了如何拜访 TemporalField 的值,ChronnoField 实现了这个接口
        /*
        LocalDate 反对的格局如下:case DAY_OF_WEEK: return getDayOfWeek().getValue();
        case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
        case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
        case DAY_OF_MONTH: return day;
        case DAY_OF_YEAR: return getDayOfYear();
        case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field'EpochDay'for get() method, use getLong() instead");
        case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
        case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
        case MONTH_OF_YEAR: return month;
        case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field'ProlepticMonth'for get() method, use getLong() instead");
        case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
        case YEAR: return year;
        case ERA: return (year >= 1 ? 1 : 0);
        * */
        // Unsupported field: HourOfDay
//        System.out.println("ChronoField.HOUR_OF_DAY =>" + parse1.get(ChronoField.HOUR_OF_DAY));
        // Unsupported field: MinuteOfHour
//        System.out.println("ChronoField.MINUTE_OF_HOUR =>" + parse1.get(ChronoField.MINUTE_OF_HOUR));
        // Unsupported field: MinuteOfHour
//        System.out.println("ChronoField.SECOND_OF_MINUTE =>" + parse1.get(ChronoField.SECOND_OF_MINUTE));
        System.out.println("ChronoField.YEAR =>" + parse1.get(ChronoField.YEAR));
        // Unsupported field: MinuteOfHour
//        System.out.println("ChronoField.INSTANT_SECONDS =>" + parse1.get(ChronoField.INSTANT_SECONDS));

    }/* 运行后果:now() => 2021-08-08
    dayOfMonth => 11
    getDayOfYear => 131
    getDayOfWeek => TUESDAY
    getMonthValue => 5
    getYear => 2021
    getChronology => ISO
    getEra => CE
    ChronoField.YEAR => 2021
    */

TemporalField 是一个接口,定义了如何拜访 TemporalField 的值,ChronnoField 实现了这个接口

LocalTime

LocalTime:和 LocalDate 相似,区别在于蕴含具体工夫,同时领有更多操作具体工夫工夫的办法,上面是对应的办法以及测试:

 @Test
    public void localTimeTest() throws Exception {LocalTime now = LocalTime.now();
        System.out.println("LocalTime.now() =>"+  now);
        System.out.println("getHour =>"+ now.getHour());
        System.out.println("getMinute =>"+ now.getMinute());
        System.out.println("getNano =>"+ now.getNano());
        System.out.println("getSecond =>"+ now.getSecond());

        LocalTime systemDefault = LocalTime.now(Clock.systemDefaultZone());
        // ZoneName => java.time.format.ZoneName.zidMap 从这个 map 外面进行获取
        LocalTime japan = LocalTime.now(Clock.system(ZoneId.of("Japan")));
        // 或者间接更换时区
        LocalTime japan2 = LocalTime.now(ZoneId.of("Japan"));
        // 格式化工夫
        LocalTime localTime = LocalTime.of(15, 22);
        // from 从另一个工夫进行转化,只有他们接口兼容
        LocalTime from = LocalTime.from(LocalDateTime.now());
        // 范湖纳秒值
        LocalTime localTime1 = LocalTime.ofNanoOfDay(1);
        LocalTime localTime2 = LocalTime.ofSecondOfDay(1);
        // 越界异样 Invalid value for MinuteOfHour (valid values 0 - 59): 77
//        LocalTime.of(15, 77);
        // 获取本地的默认工夫
        System.out.println("LocalTime.now(Clock.systemDefaultZone()) =>"+ systemDefault);
        // 获取日本时区的工夫
        System.out.println("LocalTime.now(Clock.system(ZoneId.of(\"Japan\"))) =>"+ japan);
        System.out.println("LocalTime.now(ZoneId.of(\"Japan\")) =>"+ japan2);
        System.out.println("LocalTime.of(15, 22) =>"+ localTime);
        System.out.println("LocalTime.from(LocalDateTime.now()) =>"+ from);
        System.out.println("LocalTime.ofNanoOfDay(1) =>"+ localTime1);
        System.out.println("LocalTime.ofSecondOfDay(1) =>"+ localTime2);
    }/* 运行后果:LocalTime.now() => 12:58:13.553
    getHour => 12
    getMinute => 58
    getNano => 553000000
    getSecond => 13
    LocalTime.now(Clock.systemDefaultZone()) => 12:58:13.553
    LocalTime.now(Clock.system(ZoneId.of("Japan"))) => 13:58:13.553
    LocalTime.now(ZoneId.of("Japan")) => 13:58:13.553
    LocalTime.of(15, 22) => 15:22
    LocalTime.from(LocalDateTime.now()) => 12:58:13.553
    LocalTime.ofNanoOfDay(1) => 00:00:00.000000001
    LocalTime.ofSecondOfDay(1) => 00:00:01
    */

LocalDateTime

LocalDateTimeLocalDateTime类是 LocalDateLocalTime 结合体 ,能够通过of() 办法间接创立,也能够调用 LocalDateatTime()办法或 LocalTimeatDate()办法将 LocalDateLocalTime合并成一个LocalDateTime,上面是一些简略的办法测试,因为篇幅无限,后续会联合这些内容编写一个工具类的代码。

    @Test
    public void localDateTimeTest() throws Exception {
        //Text '2021-11-11 15:30:11' could not be parsed at index 10
//        LocalDateTime parse = LocalDateTime.parse("2021-11-11 15:30:11");
        // 默认应用的是 ISO 的工夫格局
        LocalDateTime parse1 = LocalDateTime.parse("2011-12-03T10:15:30");
        // 如果要本人的格局,须要手动格式化
        LocalDateTime parse = LocalDateTime.parse("2021-11-11 15:30:11", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("LocalDateTime.parse(....) =>"+ parse1);
        System.out.println("LocalDateTime.parse(....) =>"+ parse);

        LocalDateTime of = LocalDateTime.of(LocalDate.now(), LocalTime.now());
        LocalDateTime japan = LocalDateTime.now(ZoneId.of("Japan"));
        System.out.println("LocalDateTime.of(LocalDate.now(), LocalTime.now()) =>"+ of);
        System.out.println("LocalDateTime.now(ZoneId.of(\"Japan\")) =>"+ japan);
    }/* 运行后果:LocalDateTime.parse(....) => 2011-12-03T10:15:30
    LocalDateTime.parse(....) => 2021-11-11T15:30:11
    LocalDateTime.of(LocalDate.now(), LocalTime.now()) => 2021-08-08T13:22:59.697
    LocalDateTime.now(ZoneId.of("Japan")) => 2021-08-08T14:22:59.697
    */

细粒度机器工夫操作

​ JDK8 还对机器的工夫进行了分类,比方像上面这样

Instant

Instant用于示意一个工夫戳,它与咱们常应用的 System.currentTimeMillis() 有些相似,不过 Instant 能够准确到纳秒(Nano-Second)

留神:外部应用了两个常量,seconds示意从 1970-01-01 00:00:00 开始到当初的秒数,nanos示意纳秒局部(nanos的值不会超过999,999,999

​ 上面是一些具体的测试用例:

@Test
    public void instantTest() throws Exception {Instant now = Instant.now();
        // Unable to obtain Instant from TemporalAccessor: 2021-08-08T13:37:34.403 of type java.time.LocalDateTime
//        Instant from = Instant.from(LocalDateTime.now());
        Instant instant = Instant.ofEpochSecond(3, 0);
        Instant instant1 = Instant.ofEpochSecond(5, 1_000_000_000);
        System.out.println("Instant.now() =>"+ now);
//        System.out.println("Instant.from(LocalDateTime.now()) =>"+ from);
        System.out.println("Instant.ofEpochSecond =>"+ instant);
        System.out.println("Instant.ofEpochSecond =>"+ instant1);
        System.out.println("Instant.get(ChronoField.NANO_OF_SECOND) =>"+ now.get(ChronoField.NANO_OF_SECOND));
    }/* 运行后果:Instant.now() => 2021-08-08T05:42:42.465Z
    Instant.ofEpochSecond => 1970-01-01T00:00:03Z
    Instant.ofEpochSecond => 1970-01-01T00:00:06Z
    Instant.get(ChronoField.NANO_OF_SECOND) => 465000000

    */

Duration

Duration的外部实现与 Instant 相似,也是蕴含两局部:seconds示意秒,nanos示意纳秒。两者的区别是 Instant 用于示意一个工夫戳(或者说是一个工夫点),而 Duration 示意一个时间段,比方想要获取两个工夫的差值:

    @Test
    public void durationTest() throws Exception {
        // Text '201-08-08T10:15:30' could not be parsed at index 0
        Duration between = Duration.between(LocalDateTime.parse("2011-12-03T10:15:30"), LocalDateTime.parse("2021-08-08T10:15:30"));
        System.out.println("Duration.between(LocalDateTime.parse(\"2011-12-03T10:15:30\"), LocalDateTime.parse(\"2021-08-08T10:15:30\")) =>"+ between);

        Duration duration = Duration.ofDays(7);
        System.out.println("Duration.ofDays(7) =>"+ duration);
    }

Period

Period在概念上和 Duration 相似,区别在于 Period 是以 年月日 来掂量一个时间段(比方 2 年 3 个月 6 天),上面是对应单元测试以及相干的代码:

@Test
    public void periodTest() throws Exception {Period between = Period.between(LocalDate.parse("2011-12-03"), LocalDate.parse("2021-08-08"));
        Period period = Period.ofWeeks(53);
        Period period1 = Period.ofWeeks(22);
        System.out.println("Period.between(LocalDate.parse(\"2011-12-03\"), LocalDate.parse(\"2021-08-08\")) =>"+ between);
        System.out.println("Period.ofWeeks(53) =>"+ period);
        System.out.println("Period.ofWeeks(53) getDays =>"+ period.getDays());
        // 留神,这里如果没有对应值,会呈现 0
        System.out.println("Period.ofWeeks(53) getMonths =>"+ period.getMonths());
        System.out.println("Period.ofWeeks(22) getMonths =>"+ period1.getMonths());
        System.out.println("Period.ofWeeks(22) getYears =>"+ period1.getYears());
    }/* 运行后果:Period.between(LocalDate.parse("2011-12-03"), LocalDate.parse("2021-08-08")) => P9Y8M5D
    Period.ofWeeks(53) => P371D
    Period.ofWeeks(53) getDays => 371
    Period.ofWeeks(53) getMonths => 0
    Period.ofWeeks(22) getMonths => 0
    Period.ofWeeks(22) getYears => 0
    */

TemporalAdjusters 简单日期操作

​ 这个类能够对于工夫进行各种更加简单的操作,比方下一个工作日,本月的最初一天,这时候咱们能够借助 with 这个办法进行获取:

@Test
public void testTemporalAdjusters(){LocalDate of = LocalDate.of(2021, 8, 1);
    // 获取以后年份的第一天
    LocalDate with = of.with(TemporalAdjusters.firstDayOfYear());
    System.out.println("TemporalAdjusters.firstDayOfYear =>"+ with);
    // 获取指定日期的下一个周六
    LocalDate with1 = of.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
    System.out.println("TemporalAdjusters.next(DayOfWeek.SATURDAY) =>"+ with1);
    // 获取当月的最初一天
    LocalDate with2 = of.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println("TemporalAdjusters.lastDayOfMonth() =>"+ with2);

}

上面从网络找到一份表,对应所有的办法作用

办法名 形容
dayOfWeekInMonth 返回同一个月中每周的第几天
firstDayOfMonth 返回当月的第一天
firstDayOfNextMonth 返回下月的第一天
firstDayOfNextYear 返回下一年的第一天
firstDayOfYear 返回本年的第一天
firstInMonth 返回同一个月中第一个星期几
lastDayOfMonth 返回当月的最初一天
lastDayOfNextMonth 返回下月的最初一天
lastDayOfNextYear 返回下一年的最初一天
lastDayOfYear 返回本年的最初一天
lastInMonth 返回同一个月中最初一个星期几
next / previous 返回后一个 / 前一个给定的星期几
nextOrSame / previousOrSame 返回后一个 / 前一个给定的星期几,如果这个值满足条件,间接返回

DateTimeFormatter 格式化器

​ 这个类能够认为是用来代替 SimpleDateFormat 这个类,他领有更加弱小的定制化操作,同时他是线程平安的类,不必放心多线程拜访会呈现问题。

​ 上面是依据 DateTimeFormatter 构建一个本土化的格式化器,代码也非常的简略易懂:

private static DateTimeFormatter generateDefualtPattern(String timeFormat) {return new DateTimeFormatterBuilder().appendPattern(timeFormat)
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
        .toFormatter(Locale.CHINA);
}

时区信息

​ 时区信息个别用的比拟少,在做和国际化相干的操作时候有可能会用到,比方最近集体从苹果买了一个货色,尽管我下单是在 6 号,然而电话说订单工夫却是 5 号下单的,这里集体认为苹果的确切下单工夫是依照美国工夫算的。

​ JDK8 日期类对于时区的强相干类(留神是 JDK8 才呈现的类,不要误认为是对之前类的兼容),在之前的单元测试其实曾经用到了相干时区的办法,在 JDK8 中应用了 ZoneId这个类来示意,然而咱们有时候不晓得怎么获取地区,能够参考上面的内容:

// ZoneName => java.time.format.ZoneName.zidMap 从这个 map 外面进行获取
LocalTime japan = LocalTime.now(Clock.system(ZoneId.of("Japan")));

实战 – 封装日期工具类

​ 当然更加倡议读者本人多入手试验,最好的方法就是多给几个需要给本人,强制本人用 JDK8 的办法去实现,你会发现你把握这些 API 会特地快。

注意事项:

​ 所有的工具代码都应用了同一个本地格式化器构建办法:generateDefualtPattern()

/**
     * 生成默认的格局器
     *
     * @param timeFormat 指定格局
     * @return 默认工夫格局器
     */
    private static DateTimeFormatter generateDefualtPattern(String timeFormat) {return new DateTimeFormatterBuilder().appendPattern(timeFormat)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .toFormatter(Locale.CHINA);
    }

获取指定工夫的上一个工作日和下一个工作日

​ 留神这个版本是不会判断节假日这些内容的,当然这里是手动实现的版本。

/**
     * 获取指定工夫的上一个工作日
     *
     * @param time           指定工夫
     * @param formattPattern 格式化参数
     * @return
     */
    public static String getPreWorkDay(String time, String formattPattern) {DateTimeFormatter dateTimeFormatter = generateDefualtPattern(formattPattern);
        LocalDateTime compareTime1 = LocalDateTime.parse(time, dateTimeFormatter);
        compareTime1 = compareTime1.with(temporal -> {
            // 以后日期
            DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
            // 失常状况下,每次减去一天
            int dayToMinu = 1;
            // 如果是周日,减去 2 天
            if (dayOfWeek == DayOfWeek.SUNDAY) {dayToMinu = 2;}
            // 如果是周六,减去一天
            if (dayOfWeek == DayOfWeek.SATURDAY) {dayToMinu = 1;}
            return temporal.minus(dayToMinu, ChronoUnit.DAYS);
        });
        return compareTime1.format(dateTimeFormatter);
    }


    /**
     * 获取指定工夫的下一个工作日
     *
     * @param time           指定工夫
     * @param formattPattern 格局参数
     * @return
     */
    public static String getNextWorkDay(String time, String formattPattern) {DateTimeFormatter dateTimeFormatter = generateDefualtPattern(formattPattern);
        LocalDateTime compareTime1 = LocalDateTime.parse(time, dateTimeFormatter);
        compareTime1 = compareTime1.with(temporal -> {
            // 以后日期
            DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
            // 失常状况下,每次减少一天
            int dayToAdd = 1;
            // 如果是星期五,减少三天
            if (dayOfWeek == DayOfWeek.FRIDAY) {dayToAdd = 3;}
            // 如果是星期六,减少两天
            if (dayOfWeek == DayOfWeek.SATURDAY) {dayToAdd = 2;}
            return temporal.plus(dayToAdd, ChronoUnit.DAYS);
        });
        return compareTime1.format(dateTimeFormatter);
    }

判断以后工夫是否小于指标工夫

​ 判断以后工夫是否小于指标工夫,这里联合了之前咱们学到的一些办法,留神这里的时区应用的是以后零碎的时区,如果你切换别的时区,能够看到不同的成果。另外这里应用的是 LocalDateTime 不要混同了。

/**
     * 应用 jdk 1.8 的日期类进行比拟工夫
     * 判断以后工夫是否小于指标工夫
     *
     * @param time   工夫字符串
     * @param format 指定格局
     * @return 判断以后工夫是否小于指标工夫
     */
    public static boolean isBefore(String time, String format) {DateTimeFormatter dateTimeFormatter = generateDefualtPattern(format);
        LocalDateTime compareTime = LocalDateTime.parse(time, dateTimeFormatter);
        // getNowByNew 封装了 now()办法
        LocalDateTime current = LocalDateTime.parse(getNowByNew(format), dateTimeFormatter);
        long compare = Instant.from(compareTime.atZone(ZoneId.systemDefault())).toEpochMilli();
        long currentTimeMillis = Instant.from(current.atZone(ZoneId.systemDefault())).toEpochMilli();
        return currentTimeMillis < compare;
    }

获取指定工夫属于星期几

​ 属于对 JDK8 本身的办法进行二次封装。

/**
     * 获取指定工夫属于星期几
     * 返回枚举对象
     *
     * @param date           日期
     * @param formattPattern 格局
     * @return
     */
public static DayOfWeek getDayOfWeek(String date, String formattPattern) {DateTimeFormatter dateTimeFormatter = generateDefualtPattern(formattPattern);
    return LocalDate.parse(date, dateTimeFormatter).getDayOfWeek();}

获取开始日期和完结日期之间的日期

​ 这里须要留神不是非常的谨严,最好是在执行之前日期的判断

public static final String yyyyMMdd = "yyyy-MM-dd";

/**
     * 获取开始日期和完结日期之间的日期(返回 List<String>)*
     * @param startTime 开始日期
     * @param endTime   完结日期
     * @return 开始与完结之间的所以日期,包含起止
     */
public static List<String> getMiddleDateToString(String startTime, String endTime) {LocalDate begin = LocalDate.parse(startTime, DateTimeFormatter.ofPattern(yyyyMMdd));
    LocalDate end = LocalDate.parse(endTime, DateTimeFormatter.ofPattern(yyyyMMdd));
    List<LocalDate> localDateList = new ArrayList<>();
    long length = end.toEpochDay() - begin.toEpochDay();
    // 收集相差的天数
    for (long i = length; i >= 0; i--) {localDateList.add(end.minusDays(i));
    }
    List<String> resultList = new ArrayList<>();
    for (LocalDate temp : localDateList) {resultList.add(temp.toString());
    }
    return resultList;
}

日期 API 常见的坑:

LocalDateTime 的格式化 yyyy-MM-dd 报错:

​ 第一次应用,最容易呈现问题的 diamante 如下的模式所示,比方咱们

LocalDateTime parse2 = LocalDateTime.parse("2021-11-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));

​ 在运行的时候,会抛出如下的异样:

java.time.format.DateTimeParseException: Text '2021-11-11' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2021-11-11 of type java.time.format.Parsed

​ 上面来说一下解决办法:

​ 第一种解决办法比拟蛋疼,然而的确是一种十分稳当的解决办法。

try {LocalDate localDate = LocalDate.parse("2019-05-27", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    LocalDateTime localDateTime = localDate.atStartOfDay();
    System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
} catch (Exception ex) {ex.printStackTrace();
}

​ 另外,还有一种办法是应用上面的办法,构建一个 ” 中国化 ” 的日期格局器:

/**
     * 生成默认的格局器
     *
     * @param timeFormat 指定格局
     * @return 默认工夫格局器
     */
private static DateTimeFormatter generateDefualtPattern(String timeFormat) {return new DateTimeFormatterBuilder().appendPattern(timeFormat)
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
        .toFormatter(Locale.CHINA);
}

调用 format 呈现xx not be parsed, unparsed text found at index 10

​ 问题起因:应用谬误的格局去格局字符串,比方yyyy-MM-dd 格式化 2020-05-12 12:15:33 这种格局就会呈现溢出,解决办法:应用正确的格局即可

​ 对于下面几个问题的基本解决办法
​ 起因:因为 localdatetime 在进行格式化的时候如何 case 没有找到对应的格局,那么就会呈现相似unsupport 办法

/**
     * 生成默认的格局器
     *
     * @param timeFormat 指定格局
     * @return
     */
    private static DateTimeFormatter generateDefualtPattern(String timeFormat) {return new DateTimeFormatterBuilder().appendPattern(timeFormat)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 1)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 1)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .toFormatter(Locale.CHINA);
    }

上面是其余的问题答复:

StackFlow 地址:DateTimeParseException: Text could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor

StackFlow 地址:StackFlow 无奈解析文本:无奈从 TemporalAccessor 获取 LocalDateTime

StackFlow 地址:解析 LocalDateTime(Java 8)时,无奈从 TemporalAccessor 获取 LocalDateTime

DateTimeParseException 一些小坑

​ 参考了上面的异样日志,基本的起因是 DateTimeFormatter 格式化没有 HH 选项,这也是比拟坑的中央

java.time.format.DateTimeParseException: Text '2017-02-02 08:59:12' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MinuteOfHour=59, NanoOfSecond=0, SecondOfMinute=12, MicroOfSecond=0, MilliOfSecond=0, HourOfAmPm=8},ISO resolved to 2017-02-02 of type java.time.format.Parsed

总结:

​ 在集体编写工具类的过程中,发现的确比之前的 DateCalendar这两个类用起来好很多,同时 JDK8 的日期类都是 线程平安 的。当然 JDK8 对于国内应用不是非常敌对,这也没有方法毕竟是老外的货色,不过解决办法也有不少,习惯了将解决套路之后也能够承受。最初,有条件最好应用谷歌的搜索引擎,不仅能够帮你把坑跨过来,老外很多大神还会给你讲讲原理,非常受用。

写在最初

​ 写稿不易,求赞,求珍藏。

​ 最初举荐一下集体的微信公众号:“懒时小窝”。有什么问题能够通过公众号私信和我交换,当然评论的问题看到的也会第一工夫解答。

其余问题

  1. 对于 LocalDate 的一个坑

​ 对于 LocalDate 一些源码剖析

间接上源代码,LocalDate仅代表一个日期,而不代表 DateTime。因而在格式化时“HH:mm:ss”是毫无意义的,如果咱们的格式化参数不合乎上面的规定,此办法会抛出异样并且阐明不反对对应的格式化操作。

private int get0(TemporalField field) {switch ((ChronoField) field) {case DAY_OF_WEEK: return getDayOfWeek().getValue();
            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
            case DAY_OF_MONTH: return day;
            case DAY_OF_YEAR: return getDayOfYear();
            case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field'EpochDay'for get() method, use getLong() instead");
            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
            case MONTH_OF_YEAR: return month;
            case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field'ProlepticMonth'for get() method, use getLong() instead");
            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
            case YEAR: return year;
            case ERA: return (year >= 1 ? 1 : 0);
        }
        throw new UnsupportedTemporalTypeException("Unsupported field:" + field);
    }
  1. 格式化问题:

    调用 DateFomatter 有可能的报错,根本是因为应用谬误到格局或者应用谬误的工夫类

    Error java.time.format.DateTimeParseException: could not be parsed, unparsed text found at index 10

参考资料

侠说 java8-LocalDateTime

退出移动版