万字博文教你搞懂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用法


目录
相关文章
|
14天前
|
数据采集 运维 前端开发
【Java】全套云HIS源码包含EMR、LIS (医院信息化建设)
系统技术特点:采用前后端分离架构,前端由Angular、JavaScript开发;后端使用Java语言开发。
36 5
|
2月前
|
Kubernetes jenkins 持续交付
从代码到k8s部署应有尽有系列-java源码之String详解
本文详细介绍了一个基于 `gitlab + jenkins + harbor + k8s` 的自动化部署环境搭建流程。其中,`gitlab` 用于代码托管和 CI,`jenkins` 负责 CD 发布,`harbor` 作为镜像仓库,而 `k8s` 则用于运行服务。文章具体介绍了每项工具的部署步骤,并提供了详细的配置信息和示例代码。此外,还特别指出中间件(如 MySQL、Redis 等)应部署在 K8s 之外,以确保服务稳定性和独立性。通过本文,读者可以学习如何在本地环境中搭建一套完整的自动化部署系统。
60 0
|
2天前
|
Java Apache Maven
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
15 6
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
|
2天前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
18 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
26天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
219 37
|
9天前
|
Java API
Java的日期类都是怎么用的
【10月更文挑战第1天】本文介绍了 Java 中处理日期和时间的三个主要类:`java.util.Date`、`java.util.Calendar` 和 `java.time` 包下的新 API。`Date` 类用于表示精确到毫秒的瞬间,可通过时间戳创建或获取当前日期;`Calendar` 抽象类提供丰富的日期操作方法,如获取年月日及时区转换;`java.time` 包中的 `LocalDate`、`LocalTime`、`LocalDateTime` 和 `ZonedDateTime` 等类则提供了更为现代和灵活的日期时间处理方式,支持时区和复杂的时间计算。
29 14
|
1天前
|
存储 前端开发 Java
Java后端如何进行文件上传和下载 —— 本地版(文末配绝对能用的源码,超详细,超好用,一看就懂,博主在线解答) 文件如何预览和下载?(超简单教程)
本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。
36 1
|
12天前
|
传感器 监控 数据可视化
【Java】智慧工地解决方案源码和所需关键技术
智慧工地解决方案是一种新的工程全生命周期管理理念。它通过使用各种传感器、数传终端等物联网手段获取工程施工过程信息,并上传到云平台,以保障数据安全。
44 7
|
11天前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
24 3
|
13天前
|
安全 Java API
时间日期API(Date,SimpleDateFormat,Calendar)+java8新增日期API (LocalTime,LocalDate,LocalDateTime)
这篇文章介绍了Java中处理日期和时间的API,包括旧的日期API(Date、SimpleDateFormat、Calendar)和Java 8引入的新日期API(LocalTime、LocalDate、LocalDateTime)。文章详细解释了这些类/接口的方法和用途,并通过代码示例展示了如何使用它们。此外,还讨论了新旧API的区别,新API的不可变性和线程安全性,以及它们提供的操作日期时间的灵活性和简洁性。