万字博文教你搞懂java源码的日期和时间相关用法

简介: 万字博文教你搞懂java源码的日期和时间相关用法

image.png

文章目录

介绍

日期和时间的两套API

一:Date

支持版本及以上

介绍

Date类说明

date常用的用法

自定义时间格式-SimpleDateFormat

SimpleDateFormat线程不安全原因及解决方案

SimpleDateFormat线程为什么是线程不安全的呢?

验证SimpleDateFormat线程不安全

解决方案

解决方案1:不要定义为static变量,使用局部变量

解决方案2:加锁:synchronized锁和Lock锁

解决方案3:使用ThreadLocal方式

解决方案4:使用DateTimeFormatter代替SimpleDateFormat

解决方案5:使用FastDateFormat 替换SimpleDateFormat

FastDateFormat源码分析

实践

问题

二:Calendar

支持版本及以上

介绍

Calendar类说明

Calendar常用的用法

Calendar的跨年问题和解决方案

问题

分析原因

解决方案

问题

三:LocalDateTime

支持版本及以上

介绍

LocalDateTime类说明

LocalDateTime常用的用法

获取当前日期和时间

获取指定日期和时间

日期时间的加减法及修改

LocalDateTime和Date相互转化

Date转LocalDateTime

LocalDateTime转Date

线程安全

四:ZonedDateTime

支持版本及以上

介绍

ZonedDateTime类说明

ZonedDateTime常用的用法

获取当前时间+带时区+时区转换

LocalDateTime+ZoneId变ZonedDateTime

五:DateTimeFormatter

支持版本及以上

介绍

DateTimeFormatter类说明

DateTimeFormatter常用的用法

DateTimeFormatter的坑

1、在正常配置按照标准格式的字符串日期,是能够正常转换的。如果月,日,时,分,秒在不足两位的情况需要补0,否则的话会转换失败,抛出异常。

2、YYYY和DD谨慎使用

六:Instant

支持版本及以上

介绍

Instant类说明

Instant常用的用法

Instant是没有时区的,但是Instant加上时区后,可以转化为ZonedDateTime

long型时间戳转Instant

Instant的坑

推荐相关文章

hutool日期时间系列文章

其他

介绍

本篇文章主要介绍java源码中提供了哪些日期和时间的类


日期和时间的两套API

java提供了两套处理日期和时间的API


1、旧的API,放在java.util 这个包下的:比较常用的有Date和Calendar等


2、新的API是java 8新引入的,放在java.time 这个包下的:LocalDateTime,ZonedDateTime,DateTimeFormatter和Instant等


为什么会有两套日期时间API,这个是有历史原因的,旧的API是jdk刚开始就提供的,随着版本的升级,逐渐发现原先的api不满足需要,暴露了一些问题,所以在java 8 这个版本中,重新引入新API。


这两套API都要了解,为什么呢?


因为java 8 发布时间是2014年,很多之前的系统还是沿用旧的API,所以这两套API都要了解,同时还要掌握两套API相互转化的技术。


一:Date

支持版本及以上

JDK1.0


介绍

Date类说明

Date类负责时间的表示,在计算机中,时间的表示是一个较大的概念,现有的系统基本都是利用从1970.1.1 00:00:00 到当前时间的毫秒数进行计时,这个时间称为epoch(时间戳)image.pngimage.pngimage.pngimage.pngimage.pngimage.png

public class SimpleDateFormatDemoTest {
  private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) {
        //1、创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //2、为线程池分配任务
        ThreadPoolTest threadPoolTest = new ThreadPoolTest();
        for (int i = 0; i < 10; i++) {
            pool.submit(threadPoolTest);
        }
        //3、关闭线程池
        pool.shutdown();
    }
    static class  ThreadPoolTest implements Runnable{
        @Override
        public void run() {
        String dateString = simpleDateFormat.format(new Date());
        try {
          Date parseDate = simpleDateFormat.parse(dateString);
          String dateString2 = simpleDateFormat.format(parseDate);
          System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
        } catch (Exception e) {
          System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
        }
        }
    }
}

image.png

public class SimpleDateFormatDemoTest1 {
    public static void main(String[] args) {
        //1、创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //2、为线程池分配任务
        ThreadPoolTest threadPoolTest = new ThreadPoolTest();
        for (int i = 0; i < 10; i++) {
            pool.submit(threadPoolTest);
        }
        //3、关闭线程池
        pool.shutdown();
    }
    static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      String dateString = simpleDateFormat.format(new Date());
      try {
        Date parseDate = simpleDateFormat.parse(dateString);
        String dateString2 = simpleDateFormat.format(parseDate);
        System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
      } catch (Exception e) {
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }
    }
    }
}

image.png

public class SimpleDateFormatDemoTest2 {
  private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) {
        //1、创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //2、为线程池分配任务
        ThreadPoolTest threadPoolTest = new ThreadPoolTest();
        for (int i = 0; i < 10; i++) {
            pool.submit(threadPoolTest);
        }
        //3、关闭线程池
        pool.shutdown();
    }
    static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      try {
        synchronized (simpleDateFormat){
          String dateString = simpleDateFormat.format(new Date());
          Date parseDate = simpleDateFormat.parse(dateString);
          String dateString2 = simpleDateFormat.format(parseDate);
          System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
        }
      } catch (Exception e) {
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }
    }
    }
}

image.png

public class SimpleDateFormatDemoTest3 {
  private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  private static Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        //1、创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //2、为线程池分配任务
        ThreadPoolTest threadPoolTest = new ThreadPoolTest();
        for (int i = 0; i < 10; i++) {
            pool.submit(threadPoolTest);
        }
        //3、关闭线程池
        pool.shutdown();
    }
    static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      try {
        lock.lock();
          String dateString = simpleDateFormat.format(new Date());
          Date parseDate = simpleDateFormat.parse(dateString);
          String dateString2 = simpleDateFormat.format(parseDate);
          System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
      } catch (Exception e) {
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }finally {
        lock.unlock();
      }
    }
    }
}

image.png

public class SimpleDateFormatDemoTest4 {
  private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(){
    @Override
    protected DateFormat initialValue() {
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
  };
    public static void main(String[] args) {
        //1、创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //2、为线程池分配任务
        ThreadPoolTest threadPoolTest = new ThreadPoolTest();
        for (int i = 0; i < 10; i++) {
            pool.submit(threadPoolTest);
        }
        //3、关闭线程池
        pool.shutdown();
    }
    static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      try {
          String dateString = threadLocal.get().format(new Date());
          Date parseDate = threadLocal.get().parse(dateString);
          String dateString2 = threadLocal.get().format(parseDate);
          System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
      } catch (Exception e) {
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }finally {
        //避免内存泄漏,使用完threadLocal后要调用remove方法清除数据
        threadLocal.remove();
      }
    }
    }
}

image.png

public class DateTimeFormatterDemoTest5 {
  private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  public static void main(String[] args) {
    //1、创建线程池
    ExecutorService pool = Executors.newFixedThreadPool(5);
    //2、为线程池分配任务
    ThreadPoolTest threadPoolTest = new ThreadPoolTest();
    for (int i = 0; i < 10; i++) {
      pool.submit(threadPoolTest);
    }
    //3、关闭线程池
    pool.shutdown();
  }
  static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      try {
        String dateString = dateTimeFormatter.format(LocalDateTime.now());
        TemporalAccessor temporalAccessor = dateTimeFormatter.parse(dateString);
        String dateString2 = dateTimeFormatter.format(temporalAccessor);
        System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
      } catch (Exception e) {
        e.printStackTrace();
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }
    }
  }
}

image.png

public class FastDateFormatDemo6 {
  private static FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
  public static void main(String[] args) {
    //1、创建线程池
    ExecutorService pool = Executors.newFixedThreadPool(5);
    //2、为线程池分配任务
    ThreadPoolTest threadPoolTest = new ThreadPoolTest();
    for (int i = 0; i < 10; i++) {
      pool.submit(threadPoolTest);
    }
    //3、关闭线程池
    pool.shutdown();
  }
  static class  ThreadPoolTest implements Runnable{
    @Override
    public void run() {
      try {
        String dateString = fastDateFormat.format(new Date());
        Date parseDate =  fastDateFormat.parse(dateString);
        String dateString2 = fastDateFormat.format(parseDate);
        System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
      } catch (Exception e) {
        e.printStackTrace();
        System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
      }
    }
  }
}

image.pngimage.pngimage.pngimage.pngimage.pngimage.pngimage.pngimage.png在JDK中会把前一年末尾的几天判定为下一年的第一周,因此上面程序的结果是1


解决方案

使用Calendar类 get(Calendar.YEAR)获取年份


问题

1、读取月份时,要+1


2、返回的星期是从周日开始计算,周日为1,1~7表示星期


3、Calendar的跨年问题,获取年份要用c.get(Calendar.YEAR),不要用c.getWeekYear();


4、获取指定时间是一年中的第几周时,调用cl.get(Calendar.WEEK_OF_YEAR),要注意跨年问题,跨年的那一周,获取的值为1。离跨年最近的那周为52。


三:LocalDateTime

支持版本及以上

jdk8


介绍

LocalDateTime类说明

表示当前日期时间,相当于:yyyy-MM-ddTHH:mm:ss


LocalDateTime常用的用法

获取当前日期和时间

image.png

    LocalDateTime currentTime = LocalDateTime.now(); // 当前日期和时间
    System.out.println("------------------时间的加减法及修改-----------------------");
    //3.LocalDateTime的加减法包含了LocalDate和LocalTime的所有加减,上面说过,这里就只做简单介绍
    System.out.println("3.当前时间:" + currentTime);
    System.out.println("3.当前时间加5年:" + currentTime.plusYears(5));
    System.out.println("3.当前时间加2个月:" + currentTime.plusMonths(2));
    System.out.println("3.当前时间减2天:" + currentTime.minusDays(2));
    System.out.println("3.当前时间减5个小时:" + currentTime.minusHours(5));
    System.out.println("3.当前时间加5分钟:" + currentTime.plusMinutes(5));
    System.out.println("3.当前时间加20秒:" + currentTime.plusSeconds(20));
    //还可以灵活运用比如:向后加一年,向前减一天,向后加2个小时,向前减5分钟,可以进行连写
    System.out.println("3.同时修改(向后加一年,向前减一天,向后加2个小时,向前减5分钟):" + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));
    System.out.println("3.修改年为2025年:" + currentTime.withYear(2025));
    System.out.println("3.修改月为12月:" + currentTime.withMonth(12));
    System.out.println("3.修改日为27日:" + currentTime.withDayOfMonth(27));
    System.out.println("3.修改小时为12:" + currentTime.withHour(12));
    System.out.println("3.修改分钟为12:" + currentTime.withMinute(12));
    System.out.println("3.修改秒为12:" + currentTime.withSecond(12));

image.png

    System.out.println("------------------方法一:分步写-----------------------");
    //实例化一个时间对象
    Date date = new Date();
    //返回表示时间轴上同一点的瞬间作为日期对象
    Instant instant = date.toInstant();
    //获取系统默认时区
    ZoneId zoneId = ZoneId.systemDefault();
    //根据时区获取带时区的日期和时间
    ZonedDateTime zonedDateTime = instant.atZone(zoneId);
    //转化为LocalDateTime
    LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
    System.out.println("方法一:原Date = " + date);
    System.out.println("方法一:转化后的LocalDateTime = " + localDateTime);
    System.out.println("------------------方法二:一步到位(推荐使用)-----------------------");
    //实例化一个时间对象
    Date todayDate = new Date();
    //Instant.ofEpochMilli(long l)使用1970-01-01T00:00:00Z的纪元中的毫秒来获取Instant的实例
    LocalDateTime ldt = Instant.ofEpochMilli(todayDate.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    System.out.println("方法二:原Date = " + todayDate);
    System.out.println("方法二:转化后的LocalDateTime = " + ldt);

image.pngimage.pngimage.pngimage.pngimage.pngimage.png

Java’s DateTimeFormatter pattern “YYYY” gives you the week-based-year, (by default, ISO-8601 standard) the year of the Thursday of that week.

image.pngimage.pngimage.png推荐相关文章

hutool日期时间系列文章

1DateUtil(时间工具类)-当前时间和当前时间戳


2DateUtil(时间工具类)-常用的时间类型Date,DateTime,Calendar和TemporalAccessor(LocalDateTime)转换


3DateUtil(时间工具类)-获取日期的各种内容


4DateUtil(时间工具类)-格式化时间


5DateUtil(时间工具类)-解析被格式化的时间


6DateUtil(时间工具类)-时间偏移量获取


7DateUtil(时间工具类)-日期计算


8ChineseDate(农历日期工具类)


9LocalDateTimeUtil(JDK8+中的{@link LocalDateTime} 工具类封装)


10TemporalAccessorUtil{@link TemporalAccessor} 工具类封装


其他

要探索JDK的核心底层源码,那必须掌握native用法


目录
相关文章
|
3天前
|
安全 Java Unix
Java语言中的日期与时间处理技术
Java语言中的日期与时间处理技术
|
2天前
|
移动开发 JavaScript 小程序
Java版家政上门系统源码
家政预约上门服务系统支持多终端:Uniapp开发,支持APP、微信小程序、H5网页、公众号、Android、IOS。
Java版家政上门系统源码
|
2天前
|
小程序 JavaScript 安全
Java全套同城服务家政上门系统源码(APP用户端+APP服务端+PC管理端)
家政上门预约系统:该系统综合运用springboot、java1.8、vue移动支付、微信授权登录等技术,由用户小程序、站长小程序、服务员小程序和管理系统平台组成,实现用户预约、系统派单、自动结算、服务跟踪、一键分享等功能,打造线上家政服务商城。
23 7
|
4天前
|
Java 开发者
Java的三元表达式用法
Java的三元表达式用法
|
6天前
|
JavaScript Java 关系型数据库
springboot+vue点餐平台网站(java源码+文档)
一款基于SpringBoot的点餐平台网站项目,源码及部署详情可直接联系作者。项目采用Java、SpringBoot、Mybatis、Vue等技术,支持JDK1.8和MySQL 5.7+。系统包含管理员和用户模块,如用户管理、菜品分类与信息管理、订单管理和评价管理等功能。同时,用户可进行菜品评价和订单查询。项目适用于JavaWeb、SSH、SSM等框架的学习与实践。
|
6天前
|
Java 关系型数据库 MySQL
java毕业设计之酒店管理系统(源码+文档)
酒店管理系统的主要使用者分为管理员、用户;用户:首页、个人中心、客房预订管理、入住登记管理、服务费用管理、退房登记管理、我的收藏管理。管理员:首页、个人中心、用户管理、客房类型管理、客房服务管理、客房信息管理、客房预订管理、入住登记管理、服务费用管理、退房登记管理、系统管理等功能。通过这些功能模块的设计,基本上实现了整个酒店信息管理的过程。
|
7天前
|
Java
Java多线程基础-7:wait() 和 notify() 用法解析
这篇内容探讨了Java中的`wait()`和`notify()`方法在多线程编程中的使用。
15 0
|
7天前
|
Java Linux API
Java多线程基础-4:详解Thread类及其基本用法 (一)
Java 中的 `Thread` 类是用来管理线程的,每个线程都是通过 `Thread` 类的对象来描述。
28 0
|
7天前
|
供应链 安全 Java
如何挑选一个合适的HIS系统? 基于B/S架构,JAVA语言,springboot最新技术栈开发的整套云HIS系统源码 HIS源码
最近有很多人在询问,有没有最优秀的HIS系统?在这里小编是没办法回答的。为什么呢?
21 0
如何挑选一个合适的HIS系统? 基于B/S架构,JAVA语言,springboot最新技术栈开发的整套云HIS系统源码 HIS源码
|
10天前
|
Java
一文搞懂Java的时间与日期
本文是关于Java中日期和时间的处理,介绍了JDK8之前和之后的不同方法。在JDK8之前,使用`Date`、`SimpleDateFormat`和`Calendar`类,示例包括创建日期、格式化时间、解析字符串以及修改日期。JDK8引入了`LocalDate`、`LocalTime`、`LocalDateTime`、`ZoneId`、`ZonedDateTime`、`Instant`和`DateTimeFormatter`等新类,提供了更丰富的日期和时间操作,如获取时区时间、格式化与解析、计算日期间隔等。文章结尾鼓励读者点赞和支持。
18 1