时间相关类总图

  • Date是学习的核心类,表示时间
  • DateFormat用于对日期的字符串转化
  • Calendar对于日期的转化,年月日对象的转化,日期表示和运算的时候使用
  • Calendar实现类SimpleDateFormat和Calendar的GergorianCalendar

时间在计算机中的表示

  • 时间是一维的,只有前后之分
  • 计算机标准纪元,1970年1月1日 00:00:00,每走一个毫秒为一个单位 (科普:由于早期的计算机存储单位比较小,32位能表示的最长时间是68年,从1970年开始的话,加上68.1,实际最终到2038年01月19日03时14分07秒,便会到达最大时间,过了这个时间点,所有32位操作系统时间便会变为 10000000 00000000 00000000 00000000,算下来也就是1901年12月13日20时45分52秒,这样便会出现时间回归的现象,很多软件便会运行异常了。时间回归的现象相信随着64为操作系统的产生逐渐得到解决,因为用64位操作系统可以表示到 292,277,026,596年12月4日15时30分08秒,相信我们的N代子孙,哪怕地球毁灭那天都不用愁不够用了,因为这个时间已经是千亿年以后了。)
  • 获取当前时刻的毫秒值
    1  long currentTimeMillis = System.currentTimeMillis();

实战

  • 创建一个日期对象,包是java.util.Date

    1  Date date = new Date();
  • 源码解析

this(System.currentTimeMillis());相当于创建有参构造函数,并且赋值为当前毫秒值为对象的默认时间,相当于下边的构造方法

1  public Date(long date) {
2 fastTime = date;
3 }

测试

1         Date date = new Date(System.currentTimeMillis());
2
3 Date date1 = new Date();
4
5 System.out.println(date.getTime()==date1.getTime());

常用方法

  • boolean after(Date when) 测试此日期是否在指定日期之后 核心思维:由于日期存储了当前时间的毫秒数,所以比较日期前后,可以使用getTime()的结果来进行比较得出

源码解析

  • 源码

     1 /*
    2 * If cdate is null, then fastTime indicates the time in millis.
    3 * If cdate.isNormalized() is true, then fastTime and cdate are in
    4 * synch. Otherwise, fastTime is ignored, and cdate indicates the
    5 * time.
    6 */
    7 private transient BaseCalendar.Date cdate;
    8
    9 /**
    10 * Tests if this date is after the specified date.
    11 *
    12 * @param when a date.
    13 * @return <code>true</code> if and only if the instant represented
    14 * by this <tt>Date</tt> object is strictly later than the
    15 * instant represented by <tt>when</tt>;
    16 * <code>false</code> otherwise.
    17 * @exception NullPointerException if <code>when</code> is null.
    18 */
    19 public boolean after(Date when) {
    20 return getMillisOf(this) > getMillisOf(when);
    21 }
    22
    23
    24 /**
    25 * Returns the millisecond value of this <code>Date</code> object
    26 * without affecting its internal state.
    27 */
    28 static final long getMillisOf(Date date) {
    29 if (date.cdate == null || date.cdate.isNormalized()) {
    30 return date.fastTime;
    31 }
    32 BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
    33 return gcal.getTime(d);
    34 }
  • 解析

核心就是getMillisOf(Date date)这个方法之间的互相比较,getMillisOf(this) > getMillisOf(when)第一个this的对象的毫秒值是否大于when对象的毫秒追,是的话this对象的时间就晚于when的时间,即when对象的时间在this对象的时间之后.

测试

1         Date date = new Date(2000);
2
3 Date date1 = new Date();
4
5 System.out.println(date1.after(date));
  • booleanbefore(Date when) 测试此日期是否在指定日期之前。

源码解析

  • 源码

     1     /*
    2 * If cdate is null, then fastTime indicates the time in millis.
    3 * If cdate.isNormalized() is true, then fastTime and cdate are in
    4 * synch. Otherwise, fastTime is ignored, and cdate indicates the
    5 * time.
    6 */
    7 private transient BaseCalendar.Date cdate;
    8
    9 /**
    10 * Tests if this date is before the specified date.
    11 *
    12 * @param when a date.
    13 * @return <code>true</code> if and only if the instant of time
    14 * represented by this <tt>Date</tt> object is strictly
    15 * earlier than the instant represented by <tt>when</tt>;
    16 * <code>false</code> otherwise.
    17 * @exception NullPointerException if <code>when</code> is null.
    18 */
    19 public boolean before(Date when) {
    20 return getMillisOf(this) < getMillisOf(when);
    21 }
    22
    23
    24 /**
    25 * Returns the millisecond value of this <code>Date</code> object
    26 * without affecting its internal state.
    27 */
    28 static final long getMillisOf(Date date) {
    29 if (date.cdate == null || date.cdate.isNormalized()) {
    30 return date.fastTime;
    31 }
    32 BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
    33 return gcal.getTime(d);
    34 }
  • 解析

核心就是getMillisOf(Date date)这个方法之间的互相比较,getMillisOf(this) < getMillisOf(when)第一个this的对象的毫秒值是否小于when对象的毫秒追,是的话this对象的时间就早于when的时间,即when对象的时间在this对象的时间之前.

测试

1
2 Date date = new Date(2000);
3
4 Date date1 = new Date();
5
6 System.out.println(date.before(date1));
  • boolean equals(Object obj) 比较两个日期的相等性。

源码解析

  • 源码

     1      /**
    2 * Compares two dates for equality.
    3 * The result is <code>true</code> if and only if the argument is
    4 * not <code>null</code> and is a <code>Date</code> object that
    5 * represents the same point in time, to the millisecond, as this object.
    6 * <p>
    7 * Thus, two <code>Date</code> objects are equal if and only if the
    8 * <code>getTime</code> method returns the same <code>long</code>
    9 * value for both.
    10 *
    11 * @param obj the object to compare with.
    12 * @return <code>true</code> if the objects are the same;
    13 * <code>false</code> otherwise.
    14 * @see java.util.Date#getTime()
    15 */
    16 public boolean equals(Object obj) {
    17 return obj instanceof Date && getTime() == ((Date) obj).getTime();
    18 }
  • 解析

通过核心方法equals(Object obj),核心判断 obj instanceof Date && getTime() == ((Date) obj).getTime();同时满足两个对象的类型相同,获取的getTime()毫秒值相同,就判断两个日期相等

测试

1         Date date = new Date(2000);
2
3 Date date1 = new Date();
4
5 System.out.println(date.equals(date1));
  • long getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

源码解析

  • 源码

     1     // The default value of gregorianCutover.
    2 static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
    3
    4 private static final BaseCalendar gcal = CalendarSystem.getGregorianCalendar();
    5
    6 private static BaseCalendar jcal;
    7
    8 private transient long fastTime;
    9
    10 /*
    11 * If cdate is null, then fastTime indicates the time in millis.
    12 * If cdate.isNormalized() is true, then fastTime and cdate are in
    13 * synch. Otherwise, fastTime is ignored, and cdate indicates the
    14 * time.
    15 */
    16 private transient BaseCalendar.Date cdate;
    17
    18 /**
    19 * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
    20 * represented by this <tt>Date</tt> object.
    21 *
    22 * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
    23 * represented by this date.
    24 */
    25 public long getTime() {
    26 return getTimeImpl();
    27 }
    28
    29 private final long getTimeImpl() {
    30 if (cdate != null && !cdate.isNormalized()) {
    31 normalize();
    32 }
    33 return fastTime;
    34 }
    35
    36
    37 private final BaseCalendar.Date normalize() {
    38 if (cdate == null) {
    39 BaseCalendar cal = getCalendarSystem(fastTime);
    40 cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
    41 TimeZone.getDefaultRef());
    42 return cdate;
    43 }
    44
    45 // Normalize cdate with the TimeZone in cdate first. This is
    46 // required for the compatible behavior.
    47 if (!cdate.isNormalized()) {
    48 cdate = normalize(cdate);
    49 }
    50
    51 // If the default TimeZone has changed, then recalculate the
    52 // fields with the new TimeZone.
    53 TimeZone tz = TimeZone.getDefaultRef();
    54 if (tz != cdate.getZone()) {
    55 cdate.setZone(tz);
    56 CalendarSystem cal = getCalendarSystem(cdate);
    57 cal.getCalendarDate(fastTime, cdate);
    58 }
    59 return cdate;
    60 }
    61
    62 private static final BaseCalendar getCalendarSystem(long utc) {
    63 // Quickly check if the time stamp given by `utc' is the Epoch
    64 // or later. If it's before 1970, we convert the cutover to
    65 // local time to compare.
    66 if (utc >= 0
    67 || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
    68 - TimeZone.getDefaultRef().getOffset(utc)) {
    69 return gcal;
    70 }
    71 return getJulianCalendar();
    72 }
    73
    74
    75 synchronized private static final BaseCalendar getJulianCalendar() {
    76 if (jcal == null) {
    77 jcal = (BaseCalendar) CalendarSystem.forName("julian");
    78 }
    79 return jcal;
    80 }
  • 解析
    判断BaseCalendar是否为空,和它的格式是否符合设置的格式,为空和格式符合,就返回输入的毫秒值,不为空,不符合格式规范,进入normalize()方法,对BaseCalendar中的参数进行设置 GregorianCalendar.DEFAULTGREGORIANCUTOVER - TimeZone.getDefaultRef().getOffset(utc) 格里高利历默认时间减去系统时区默认的毫秒值时间
    getJulianCalendar()获取儒略历(Julian Calendar)"规则的时间
    normalize() 对象BaseCalendar为空的时候,获取 格里高利历默认时间减去系统时区默认的毫秒值时间或者儒略历(Julian Calendar)"规则的时间放入对象 再通过 cal.getCalendarDate的毫秒值和时区时间,获取对象日期,再通过对象的日期转化为毫秒值 不是标准格式(!cdate.isNormalized()),通过 cdate = normalize(cdate);,获取日期对象 tz != cdate.getZone() 当前对象是否是默认时区,判断时区是否被更改 时区更改了,改回当前的时区,然后通过对象获取日期
    目的,就是获取BaseCalendar对象,获取其相关日期的参数,然后转化为儒略历的时间计算方式

测试

1         Date date = new Date(2000);
2
3 System.out.println(date.getTime());
  • String toString() 把此 Date 对象转换为以下形式的 String:

    dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun、 Mon、Tue、Wed、 Thu、 Fri、 Sat)

源码解析

  • 源码

     1 /**
    2 * Converts this <code>Date</code> object to a <code>String</code>
    3 * of the form:
    4 * <blockquote><pre>
    5 * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
    6 * where:<ul>
    7 * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
    8 * Thu, Fri, Sat</tt>).
    9 * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
    10 * Jul, Aug, Sep, Oct, Nov, Dec</tt>).
    11 * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
    12 * <tt>31</tt>), as two decimal digits.
    13 * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
    14 * <tt>23</tt>), as two decimal digits.
    15 * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
    16 * <tt>59</tt>), as two decimal digits.
    17 * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
    18 * <tt>61</tt>, as two decimal digits.
    19 * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
    20 * time). Standard time zone abbreviations include those
    21 * recognized by the method <tt>parse</tt>. If time zone
    22 * information is not available, then <tt>zzz</tt> is empty -
    23 * that is, it consists of no characters at all.
    24 * <li><tt>yyyy</tt> is the year, as four decimal digits.
    25 * </ul>
    26 *
    27 * @return a string representation of this date.
    28 * @see java.util.Date#toLocaleString()
    29 * @see java.util.Date#toGMTString()
    30 */
    31 public String toString() {
    32 // "EEE MMM dd HH:mm:ss zzz yyyy";
    33 BaseCalendar.Date date = normalize();
    34 StringBuilder sb = new StringBuilder(28);
    35 int index = date.getDayOfWeek();
    36 if (index == BaseCalendar.SUNDAY) {
    37 index = 8;
    38 }
    39 convertToAbbr(sb, wtb[index]).append(' '); // EEE
    40 convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
    41 CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
    42
    43 CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
    44 CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
    45 CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
    46 TimeZone zi = date.getZone();
    47 if (zi != null) {
    48 sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
    49 } else {
    50 sb.append("GMT");
    51 }
    52 sb.append(' ').append(date.getYear()); // yyyy
    53 return sb.toString();
    54 }
  • 解析

拼接字符串按照格式:EEE MMM dd HH:mm:ss zzz yyyy,获取周/月/日/时分秒/时区/年

测试

1         Date date = new Date();
2
3 System.out.println(date.toString());

注:
      大部分方法已经被取代了,不推荐使用了 JDK8,已经推出了新的LocalDate系列取代的新方案,

详情查阅 https://www.cnblogs.com/liuyangfirst/p/10076612.html

JDK源码阅读-------自学笔记(十三)(java.text.DateFormat和SimpleDateFormat类)的更多相关文章

  1. JDK源码阅读-------自学笔记(一)(java.lang.Object重写toString源码)

    一.前景提要 Object类中定义有public String toString()方法,其返回值是 String 类型. 二.默认返回组成 类名+@+16进制的hashcode,当使用打印方法打印的 ...

  2. JDK源码阅读-------自学笔记(二十五)(java.util.Vector 自定义讲解)

    Vector 向量 Vector简述 1).Vector底层是用数组实现的List 2).虽然线程安全,但是效率低,所以并不是安全就是好的 3).底层大量方法添加synchronized同步标记,sy ...

  3. JDK源码阅读-------自学笔记(五)(浅析数组)

    一.数组基础 1.定义和特点 数组也可以看做是对象,数组变量属于引用类型,数组中每个元素相当于该队形的成员变量,数组对象存储在堆中. 2.初始化数组 常用类初始化 // 整型初始化 int[] int ...

  4. JDK源码阅读-------自学笔记(二十四)(java.util.LinkedList 再探 自定义讲解)

    一.实现get方法 1.一般思维实现思路 1).将对象的值放入一个中间变量中. 2).遍历索引值,将中间量的下一个元素赋值给中间量. 3).返回中间量中的元素值. 4).示意图 get(2),传入角标 ...

  5. JDK源码阅读-DirectByteBuffer

    本文转载自JDK源码阅读-DirectByteBuffer 导语 在文章JDK源码阅读-ByteBuffer中,我们学习了ByteBuffer的设计.但是他是一个抽象类,真正的实现分为两类:HeapB ...

  6. JDK源码阅读(三):ArraryList源码解析

    今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ...

  7. JDK源码阅读(一):Object源码分析

    最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...

  8. 利用IDEA搭建JDK源码阅读环境

    利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...

  9. JDK源码阅读-FileOutputStream

    本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ...

  10. JDK源码阅读-FileInputStream

    本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ...

随机推荐

  1. 开源机密计算平台:蓬莱-OpenHarmony

    演讲嘉宾 | 杜   东 回顾整理 | 廖   涛 排版校对 | 李萍萍 嘉宾简介 杜东,上海交通大学助理研究员.中国计算机学会CCF会员,ACM会员.研究兴趣为操作系统与体系结构.服务器无感知(Se ...

  2. OpenHarmony技术日圆满举行丨3.1 Release版本重磅发布,生态落地初具规模

    4 月 25 日,"共建新技术,开拓新领域"OpenAtom OpenHarmony(以下简称"OpenHarmony")技术日在深圳顺利召开.活动现场,Ope ...

  3. 7. The Singular Value Decomposition(SVD)

    7.1 Singular values and Singular vectors The SVD separates any matrix into simple pieces. A is any m ...

  4. 安装HTMLTestRunner库

    安装 HTMLTestRunner 库的方法非常简单,直接 pip 就可以了 pip install html-testRunner 在 https://pypi.org/  中可以直接搜索到,并且官 ...

  5. GPT-3的训练一次成本约为140万美元

    训练GPT模型的成本非常高昂,因为它需要大量的计算资源和时间.具体来说,GPT-3的训练成本约为140万美元,对于一些更大的LLM模型,训练成本介于200万美元至1200万美元之间.此外,OpenAI ...

  6. Native Rawfile开发指导

      场景介绍 开发者可以通过本指导了解在HarmonyOS应用中,如何使用Native Rawfile接口操作Rawfile目录和文件.功能包括遍历.打开.搜索.读取和关闭Rawfile. 接口说明 ...

  7. Native API在HarmonyOS应用工程中的使用指导

      HarmonyOS的应用必须用js来桥接native.需要使用ace_napi仓中提供的napi接口来处理js交互.napi提供的接口名与三方Node.js一致,目前支持部分接口,符号表见ace_ ...

  8. linux 性能自我学习 ———— cpu 快速定位问题 [六]

    前言 主要介绍一下cpu如何快速定位问题. 正文 cpu 的一些性能指标: 1. cpu 使用率 cpu 使用率描述了非空闲时间占总cpu时间的百分比,根据cpu上运行任务的不同,又被分为用户cpu. ...

  9. var ,let和const三者之间的区别

    var 声明变量可以被修改,可以被重复声明.有变量提升(写的位置和使用时候的位置不一样). let声明变量可以被修改,,但不能重复声明.如文件中有一个let a = 0;后面就不能在定义let a=* ...

  10. Apsara Stack 同行者专刊 | 怀同行之心,筑信任之基,践数智之行

    简介: 政企云平台处在怎样的历史阶段?数智创新的同行者们面临着怎样的挑战与机遇?在时代巨幕下,政企期待云厂商扮演怎样的角色?阿里云智能研究员.混合云平台总经理刘国华认为,云厂商不仅需要有定力与实力,也 ...