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
trueif and only if the instant represented 14 * by this Date object is strictly later than the 15 * instant represented by when; 16 *falseotherwise. 17 * @exception NullPointerException ifwhenis null. 18 */ 19 public boolean after(Date when) { 20 return getMillisOf(this) > getMillisOf(when); 21 } 22 23 24 /** 25 * Returns the millisecond value of thisDateobject 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
trueif and only if the instant of time 14 * represented by this Date object is strictly 15 * earlier than the instant represented by when; 16 *falseotherwise. 17 * @exception NullPointerException ifwhenis null. 18 */ 19 public boolean before(Date when) { 20 return getMillisOf(this) < getMillisOf(when); 21 } 22 23 24 /** 25 * Returns the millisecond value of thisDateobject 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
trueif and only if the argument is 4 * notnulland is aDateobject that 5 * represents the same point in time, to the millisecond, as this object. 6 *
7 * Thus, twoDateobjects are equal if and only if the 8 *getTimemethod returns the samelong9 * value for both. 10 * 11 * @param obj the object to compare with. 12 * @returntrueif the objects are the same; 13 *falseotherwise. 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 Date 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
6 * where:Dateobject to aString3 * of the form: 4 *
5 * dow mon dd hh:mm:ss zzz yyyy- dow is the day of the week (Sun, Mon, Tue, Wed,
8 * Thu, Fri, Sat). 9 *- mon is the month (Jan, Feb, Mar, Apr, May, Jun,
10 * Jul, Aug, Sep, Oct, Nov, Dec). 11 *- dd is the day of the month (01 through
12 * 31), as two decimal digits. 13 *- hh is the hour of the day (00 through
14 * 23), as two decimal digits. 15 *- mm is the minute within the hour (00 through
16 * 59), as two decimal digits. 17 *- ss is the second within the minute (00 through
18 * 61, as two decimal digits. 19 *- zzz is the time zone (and may reflect daylight saving
20 * time). Standard time zone abbreviations include those 21 * recognized by the method parse. If time zone 22 * information is not available, then zzz is empty - 23 * that is, it consists of no characters at all. 24 *- yyyy is the year, as four decimal digits.
25 *
- 解析
拼接字符串按照格式:EEE MMM dd HH:mm:ss zzz yyyy,获取周/月/日/时分秒/时区/年
测试
1 Date date = new Date(); 2 3 System.out.println(date.toString());
注:
大部分方法已经被取代了,不推荐使用了 JDK8,已经推出了新的LocalDate系列取代的新方案,
详情查阅