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系列取代的新方案,