【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(中)

简介: 【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(中)

新的API 格式化(字符串 -><- 字符串 互转)


  public static void main(String[] args) {
        //字符串转化为日期对象
        String dateStr= "2016年10月25日";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        LocalDate date= LocalDate.parse(dateStr, formatter);
        //日期转换为字符串
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a");
        String nowStr = now .format(format);
        System.out.println(nowStr); //2018年08月07日 12:15 上午
    }


  • DateTimeFormatter预定义了一些格式,可以直接调用format方法,方便调用者使用


//2017-01-01
DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.of(2017, 1, 1))
//20170101
DateTimeFormatter.BASIC_ISO_DATE.format(LocalDate.of(2017, 1, 1));
//2017-01-01T09:10:00
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.of(2017, 1, 1, 9, 10, 0)); 

根据当前操作系统语言环境,有SHORET MEDIUM LONG FULL 四种不同的风格来格式化。


可以通过DateTimeFormatter的静态方法ofLocalizedDate ofLocalizedTime ofLocalizedDateTime


  • 使用自定义模式格式化


//2017-02-27 22:48:52
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now())

当然也可以这么搞


//使用的ISO_LOCAL_DATE格式解析  2017-01-01
LocalDate.parse("2017-01-01");
//使用自定义格式解析  2017-01-01T08:08:08
LocalDateTime.parse("2017-01-01 08:08:08", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));


在DateTimeFormatter中还有很多定义好的格式,有兴趣的可以自己去看一下

SimpleDateFormat是线程不安全的,所以在高并发环境下,建议这么搞


 private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };
    //和线程绑定 保证安全
    public static String format(Date date) {
        return threadLocal.get().format(date);


    注意:ofPattern(String pattern)和ofPattern(String pattern, Locale locale)还是有区别的。但绝大多数情况下,我们用ofPattern就够了,因为Locale对象根据用户的国家,地区文化差异格式化,不会改变系统时间,只是表达方式变而已,就是数值表示方法不同而已,也是一样的值,这个方法不常用,因为不能覆盖所有语言环境。并且和格式化模版有关,比如我们的最常用yyyy-MM-dd HH:mm:ss会没有效果。但是这种模版“GGGG yyyy/MMMM/dd HH:mm:ss EEE”,Local不同,展示方式是有很大不同的


Date类型和时间戳 转换成新的时间类型


Date在1.8之后提供了几个方法,可以很方便的转换成新的API


     //时间戳转instant就很简单了
        Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
        System.out.println(instant); //2018-08-06T16:26:08.539Z(其实已经24点了,所以直接输出是有时区问题的 需要注意)
        //Date直接转Instant
        System.out.println(new Date().toInstant()); //2018-08-06T16:26:08.539Z
        //Instant --> Date
        Date.from(Instant.now());
        //Calendar --> Instant(这个用得很少)
        Calendar.getInstance().toInstant();


理论知识就介绍到这了,接下来看一些有意思的案例实现,可以更好的了解应用场景


根据已经了解的策略模式,我们可以很好的猜到,LocalDate、LocalTime、LocalDateTime他们之前的互相转换,也是可以走from方法的,如下:


LocalDateTime localDateTime = LocalDateTime.now();
        LocalDate localDate = LocalDate.from(localDateTime);
        LocalTime localTime = LocalTime.from(localDateTime);
        System.out.println(localDate); //2018-08-13
        System.out.println(localTime); //16:04:48.356
        ///下面的会报错哟///
        //LocalTime localTime = LocalTime.now();
        //LocalDate localDate = LocalDate.from(localTime); //这样转是会报错的  因为LocalTime不含有Date元素 Unable to obtain LocalDate from TemporalAccessor: 16:01:47.541 of type java.time.LocalTime
        //LocalDateTime localDateTime = LocalDateTime.from(localTime); //这样转也是会报错的 因为不含有date元素
        //System.out.println(localTime);
        //System.out.println(localDateTime);


重要:常用:LocalDate和Date类、时间戳之间转换的坑


Date对象表示特定的日期和时间,而LocalDate(Java8)对象只包含没有任何时间信息的日期。 因此,如果我们只关心日期而不是时间信息,则可以在Date和LocalDate之间进行转换


在JDK8以前,我们经常遇到用Date类型来装载时间。有时候只表示日期,有时候是日期+时间,但是我们的选择都只能是Date类型。因此Date类型到LocalDate、LocalTime、Instant等类型的转换 显得尤为重要了。


这里面需要注意一个坑:他们转换的中间桥梁都是时间戳Instant对象,但是转换的时候如果没有考虑时区,就会报错的。


比如下面这个例子,看起来顺滑,其实异常了:


Date date = new Date();
        Instant instant = date.toInstant();
        //看起来非常顺滑 但其实 异常:Unable to obtain LocalDate from TemporalAccessor: 2018-08-31T02:41:28.076Z of type java.time.Instant
        LocalDate from = LocalDate.from(date.toInstant());


其实这个也好理解。人家Date是带有日期和时间的,然后突然来一个只需要日期的,LocalDate不知道咋处理(或者说JDK8没考虑到这一点,其实不是,因为时区没定,LocalDate自己不好自己做定论),所以不允许直接转换也可以理解。所以各位使用起一定要小心使用了


糗事Date和LocalDate、LocalTime等互相转化的的思想也很简单 借助LocalDateTime对象就万无一失了。


    Date date = new Date();
        Instant instant = date.toInstant();
        //以ZoneId.systemDefault转换成LocalDateTime后,就可以随意转换了
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        //方式一:使用LocalDate、LocalTime的from
        LocalDate fromLocalDate = LocalDate.from(localDateTime);
        LocalTime fromLocalTime = LocalTime.from(localDateTime);
        System.out.println(fromLocalDate); //2018-08-31
        System.out.println(fromLocalTime); //11:03:19.716
        //方式二:直接to的方式
        LocalDate toLocalDate = localDateTime.toLocalDate();
        LocalTime toLocalTime = localDateTime.toLocalTime();
        System.out.println(toLocalDate); //2018-08-31
        System.out.println(toLocalTime); //11:03:19.716


反向转换:借助的中间变量是Instant即可


 public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();
        Instant instant = null;
        ZoneId zone = ZoneId.systemDefault();
        //LocalDateTime转Instant转Date
        instant = localDateTime.atZone(zone).toInstant();
        System.out.println(Date.from(instant));
        //LocalDate转Instant转Date
        instant = localDate.atStartOfDay().atZone(zone).toInstant();
        System.out.println(Date.from(instant));
        //LocalTime转Instant转Date(很麻烦 一般杜绝这样使用吧)
        //必须先借助localDate转换成localDateTime 在转成instant 再转date
        LocalDateTime localDateTimeDate = LocalDateTime.of(localDate, localTime);
        instant = localDateTime.atZone(zone).toInstant();
        System.out.println(Date.from(instant));
    }



时间矫正器(TemporalAdjuster )


Java8推出了时间矫正器的概念。可以辅助我们更精准的定位到一些日期,比如写个周日,下个结婚纪念日等等。


    TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。不过它是个接口,并且是函数式接口


    TemporalAdjusters : 该类通过静态方法提供了大量的常用TemporalAdjuster 的实现。

时间矫正,用的都是with语法。可以理解成和set差不多

image.png



public static void main(String[] args) {
        LocalDateTime ldt1 = LocalDateTime.now();
        //本月第一天
        LocalDateTime ldt2 = ldt1.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println(ldt2); //2018-08-01T17:34:42.039
        //本月的第一个周五
        LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY));
        System.out.println(ldt3); //2018-08-03T17:41:07.619
    }


接下来一个场景会比较有意思点:下一个信用卡还款日是什么时候。



时间矫正器,在很多场景下,还是非常有用的。所以希望读者能够大概掌握


Java中处理日期、时间的经典案例场景


检查两个日期是否相等


LocalDate重写了equals方法来进行日期的比较,如下所示:


image.png


在java8中如何检查重复事件,比如生日


这是相对比较常用的一个场景:判断今天是否是某个人的生日。


image.png

通过列子可以看到MonthDay只存储了月日,对比两个日期的月日即可知道是否重复,而且使用了equals方法,非常的方便快捷有木有

相关文章
|
3天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
17 4
|
29天前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
87 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
12天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
15天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
26 6
|
18天前
|
Java 大数据 API
别死脑筋,赶紧学起来!Java之Steam() API 常用方法使用,让开发简单起来!
分享Java Stream API的常用方法,让开发更简单。涵盖filter、map、sorted等操作,提高代码效率与可读性。关注公众号,了解更多技术内容。
|
1月前
|
分布式计算 Java 大数据
大数据-147 Apache Kudu 常用 Java API 增删改查
大数据-147 Apache Kudu 常用 Java API 增删改查
25 1
|
25天前
|
SQL Java API
深入探索Java的持久化技术——JPA(Java Persistence API)
【10月更文挑战第10天】深入探索Java的持久化技术——JPA(Java Persistence API)
16 0
|
25天前
|
Java API 数据库
深入探索Java的持久化技术——JPA(Java Persistence API)
【10月更文挑战第10天】深入探索Java的持久化技术——JPA(Java Persistence API)
31 0
|
IDE Java 关系型数据库
Java14发布,16大新特性,代码更加简洁明快
Java14发布,16大新特性,代码更加简洁明快
319 0
Java14发布,16大新特性,代码更加简洁明快
|
10天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
下一篇
无影云桌面