JDK源码阅读-------自学笔记(十三)(java.text.DateFormat和SimpleDateFormat类)
时间相关类总图
- 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类)的更多相关文章
- JDK源码阅读-------自学笔记(一)(java.lang.Object重写toString源码)
一.前景提要 Object类中定义有public String toString()方法,其返回值是 String 类型. 二.默认返回组成 类名+@+16进制的hashcode,当使用打印方法打印的 ...
- JDK源码阅读-------自学笔记(二十五)(java.util.Vector 自定义讲解)
Vector 向量 Vector简述 1).Vector底层是用数组实现的List 2).虽然线程安全,但是效率低,所以并不是安全就是好的 3).底层大量方法添加synchronized同步标记,sy ...
- JDK源码阅读-------自学笔记(五)(浅析数组)
一.数组基础 1.定义和特点 数组也可以看做是对象,数组变量属于引用类型,数组中每个元素相当于该队形的成员变量,数组对象存储在堆中. 2.初始化数组 常用类初始化 // 整型初始化 int[] int ...
- JDK源码阅读-------自学笔记(二十四)(java.util.LinkedList 再探 自定义讲解)
一.实现get方法 1.一般思维实现思路 1).将对象的值放入一个中间变量中. 2).遍历索引值,将中间量的下一个元素赋值给中间量. 3).返回中间量中的元素值. 4).示意图 get(2),传入角标 ...
- JDK源码阅读-DirectByteBuffer
本文转载自JDK源码阅读-DirectByteBuffer 导语 在文章JDK源码阅读-ByteBuffer中,我们学习了ByteBuffer的设计.但是他是一个抽象类,真正的实现分为两类:HeapB ...
- JDK源码阅读(三):ArraryList源码解析
今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ...
- JDK源码阅读(一):Object源码分析
最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...
- 利用IDEA搭建JDK源码阅读环境
利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...
- JDK源码阅读-FileOutputStream
本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ...
- JDK源码阅读-FileInputStream
本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ...
随机推荐
- #莫比乌斯反演,杜教筛#洛谷 6055 [RC-02] GCD
题目 分析 如果令 \(u=pj,v=qj\) ,那么本质上就是让 \(gcd(i,u,v)==1\) 那就是 \(\sum_{i=1}^n\sum_{u=1}^n\sum_{v=1}^n[gcd(i ...
- jemter返回结果中文乱码
如图,返回的结果,中文出现乱码 对于这个问题有两种解决方法 第一种:修改jemeter文件,需要重启jemter 在 bin 目录下,找到 jmeter.properties 这个文件,修改编码格 ...
- Maven 必备技能:MAC 系统下 JDK和Maven 安装及环境变量配置详细讲解
开发中难免因系统问题或者版本变更反复折腾JDK和Maven环境变量,干脆写个笔记备忘个,也方便小伙伴们节省时间. =================JDK安装与环境变量配置====== 1.官网下载j ...
- sql 语句系列(更新系列)[八百章之第六章]
使用另一个表更新记录 有时候我们的数据不会立即去更新,而是存在另外一张表中等待更新,这是在日常开发中常见的操作. update e set e.SAL=ns.SAL+e.SAL, e.COMM=ns. ...
- 重新点亮linux 命令树————修改网络配置[十一四]
前言 整理一下网络配置的修改. 正文 网络配置命令 ifconfig <接口> <ip地址> [netmask 子网掩码] ifup <接口> ifdown < ...
- 同义词查找,关键词扩展,使用腾讯Tencent AILAB的800万词向量,gensim,annoy
最近在做一个关键词匹配系统,为了更好的效果, 添加一个关键词扩展的功能.使用Tencent AIlab的800万词向量文件. 腾讯AILAB的800万词向量下载地址:https://ai.tencen ...
- 力扣601(MySQL)-体育馆的人的流量(困难)
题目: 表:Stadium 编写一个 SQL 查询以找出每行的人数大于或等于 100 且 id 连续的三行或更多行记录. 返回按 visit_date 升序排列 的结果表. 查询结果格式如下所示 示例 ...
- 如何做好技术 Team Leader?
简介: 作为一个技术TL(Team Leader),除了自身技能,还会面临诸多团队管理上的困难和挑战.如何定义和明确团队的目标?怎样建立优秀的工程文化?让团队长期发挥战斗力和创新能力的核心是什么?本文 ...
- Serverless Kubernetes 落地实践
简介:如何通过原生 Kubernetes 提供 Serverless 能力?如何借力丰富的云原生社区生态?本文将给大家介绍一下我们在 Serverless Kubernetes 上的落地实践. 作者 ...
- 开源自建/托管与商业化自研 Trace,如何选择?
简介: 随着微服务架构的兴起,服务端的调用依赖愈加复杂,为了快速定位异常组件与性能瓶颈,接入分布式链路追踪 Trace 已经成为 IT 运维领域的共识.但是,开源自建.开源托管或商业化自研 Trac ...