前言
- Date类表示特定的时间瞬间,精度为毫秒。
- 在JDK 1.1之前,Date类具有两个附加功能。
- 它允许将日期解释为年,月,日,小时,分钟和秒值。
- 它还允许格式化和解析日期字符串。
- 不幸的是,这些功能的API不适合国际化。
- 从JDK 1.1开始,应该使用Calendar类在日期和时间字段之间进行转换,而DateFormat类应该用于格式化和解析日期字符串。
- 不建议使用Date中的相应方法。
- 尽管Date类旨在反映协调世界时(UTC),但它可能并非完全如此,具体取决于Java虚拟机的宿主环境* 在所有情况下,几乎所有现代操作系统都假定1天= 24×60×60 = 86400秒。
- 但是,在UTC中,大约每年一到两年一次,称为“leep second”。
- leep second 秒始终被添加为一天的最后一秒,并且总是在12月31日或6月30日。
- 例如,由于增加了leap秒,1995年的最后一分钟长61秒。大多数计算机时钟不够精确,无法反映leep second 的区别。
- 某些计算机标准是按照格林威治标准时间(GMT)定义的,格林威治标准时间等于世界标准时间(UT)。
- GMT是标准的“民事”名称; UT是同一标准的“科学”名称。
- UTC与UT之间的区别在于,UTC基于原子钟,而UT基于天文观测,从所有实际目的来看,这都是很难区分的。
- 由于地球的自转不均匀(它以复杂的方式减速并加速),所以UT并不总是均匀地流动。
- 可以根据需要将秒引入UTC,以使UTC保持在UT1的0.9秒以内,UT1是UT的版本,并进行了某些校正。
- 还有其他时间和日期系统;例如,基于卫星的全球定位系统(GPS)使用的时间标度已与UTC同步,但并未针对leap秒进行调整。
- 有趣的进一步信息来源是美国海军天文台,特别是时间局,其网址为:tycho.usno.navy.mil
- 及其在以下时间对“时间系统”的定义: tycho.usno.navy.mil/systime.htm…
- 在Date类的所有接受或返回年,月,日,时,分和秒值的方法中,使用以下表示形式:
-
年y由整数y-1900表示。
-
一个月由0到11之间的整数表示; 0是一月,1是二月,依此类推;因此11月是12月。
-
日期(一个月中的一天)通常以1到31之间的整数表示。
-
一个小时用0到23的整数表示。因此,从午夜到凌晨1点是0,而从正午到下午1点则是12点。
-
分钟通常以0到59之间的整数表示。
-
秒由0到61之间的整数表示;
-
值60和61仅在leap秒出现,甚至仅在实际上正确跟踪leap秒的Java实现中才出现。
-
由于当前采用的是seconds秒,因此极不可能在同一分钟内出现两个leep second,但是此规范遵循ISO C的日期和时间约定。
- 在所有情况下,为此目的而给方法提供的参数都不必在指定的范围内;例如,日期可以指定为1月32日,并解释为2月1日。
源码
package java.util;
public class Date
implements java.io.Serializable, Cloneable, Comparable<Date>
{
private static final BaseCalendar gcal =
CalendarSystem.getGregorianCalendar();
private static BaseCalendar jcal;
private transient long fastTime;
private transient BaseCalendar.Date cdate;
private static int defaultCenturyStart;
private static final long serialVersionUID = 7523967970034938905L;
/**
* 分配一个Date对象并对其进行初始化,以便它表示分配该对象的时间(以最近的毫秒为单位)。
*
* @see java.lang.System
*/
public Date() {
this(System.currentTimeMillis());
}
/**
* 分配一个Date对象,并将其初始化为表示自标准基准时间(即epoch)以来的指定毫秒数,即标准时间1970年1月1日,格林尼治标准时间00:00:00。
*/
public Date(long date) {
fastTime = date;
}
/**
* Return a copy of this object.
* 返回一个Date对象的复制。
*/
public Object clone() {
Date d = null;
try {
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
}
} catch (CloneNotSupportedException e) {}
return d;
}
private final static String wtb[] = {
"am", "pm",
"monday", "tuesday", "wednesday", "thursday", "friday",
"saturday", "sunday",
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december",
"gmt", "ut", "utc", "est", "edt", "cst", "cdt",
"mst", "mdt", "pst", "pdt"
};
private final static int ttb[] = {
14, 1, 0, 0, 0, 0, 0, 0, 0,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
10000 + 0, 10000 + 0, 10000 + 0, // GMT/UT/UTC
10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT
10000 + 6 * 60, 10000 + 5 * 60, // CST/CDT
10000 + 7 * 60, 10000 + 6 * 60, // MST/MDT
10000 + 8 * 60, 10000 + 7 * 60 // PST/PDT
};
/**
* 返回毫秒时间
*/
public long getTime() {
return getTimeImpl();
}
private final long getTimeImpl() {
if (cdate != null && !cdate.isNormalized()) {
normalize();
}
return fastTime;
}
/**
* 设置时间,参数为1970年开始的毫秒时间
*/
public void setTime(long time) {
fastTime = time;
cdate = null;
}
/**
* 判断当前时间是否比指定的时间早。
*/
public boolean before(Date when) {
return getMillisOf(this) < getMillisOf(when);
}
/**
* 判断当前的时间是否比指定的时间晚。
*/
public boolean after(Date when) {
return getMillisOf(this) > getMillisOf(when);
}
/**
* 比较两个日期是否相等。当且仅当参数不为null且是一个Date对象,该Date对象表示与该对象相同的时间点(以毫秒为单位)时,结果为true。
* 因此,当且仅当getTime方法为两个对象返回相同的long值时,两个Date对象才相等。
*/
public boolean equals(Object obj) {
return obj instanceof Date && getTime() == ((Date) obj).getTime();
}
static final long getMillisOf(Date date) {
if (date.cdate == null || date.cdate.isNormalized()) {
return date.fastTime;
}
BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
return gcal.getTime(d);
}
/**
* 比较两个Date对象的顺序。
*/
public int compareTo(Date anotherDate) {
long thisTime = getMillisOf(this);
long anotherTime = getMillisOf(anotherDate);
return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
}
public int hashCode() {
long ht = this.getTime();
return (int) ht ^ (int) (ht >> 32);
}
/**
* Date对象转化为字符串
*/
public String toString() {
// "EEE MMM dd HH:mm:ss zzz yyyy";
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
if (index == BaseCalendar.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
sb.append(' ').append(date.getYear()); // yyyy
return sb.toString();
}
private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
sb.append(Character.toUpperCase(name.charAt(0)));
sb.append(name.charAt(1)).append(name.charAt(2));
return sb;
}
private final BaseCalendar.Date getCalendarDate() {
if (cdate == null) {
BaseCalendar cal = getCalendarSystem(fastTime);
cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
TimeZone.getDefaultRef());
}
return cdate;
}
private final BaseCalendar.Date normalize() {
if (cdate == null) {
BaseCalendar cal = getCalendarSystem(fastTime);
cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
TimeZone.getDefaultRef());
return cdate;
}
// Normalize cdate with the TimeZone in cdate first. This is
// required for the compatible behavior.
if (!cdate.isNormalized()) {
cdate = normalize(cdate);
}
// If the default TimeZone has changed, then recalculate the
// fields with the new TimeZone.
TimeZone tz = TimeZone.getDefaultRef();
if (tz != cdate.getZone()) {
cdate.setZone(tz);
CalendarSystem cal = getCalendarSystem(cdate);
cal.getCalendarDate(fastTime, cdate);
}
return cdate;
}
// fastTime and the returned data are in sync upon return.
private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
int y = date.getNormalizedYear();
int m = date.getMonth();
int d = date.getDayOfMonth();
int hh = date.getHours();
int mm = date.getMinutes();
int ss = date.getSeconds();
int ms = date.getMillis();
TimeZone tz = date.getZone();
if (y == 1582 || y > 280000000 || y < -280000000) {
if (tz == null) {
tz = TimeZone.getTimeZone("GMT");
}
GregorianCalendar gc = new GregorianCalendar(tz);
gc.clear();
gc.set(GregorianCalendar.MILLISECOND, ms);
gc.set(y, m-1, d, hh, mm, ss);
fastTime = gc.getTimeInMillis();
BaseCalendar cal = getCalendarSystem(fastTime);
date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
return date;
}
BaseCalendar cal = getCalendarSystem(y);
if (cal != getCalendarSystem(date)) {
date = (BaseCalendar.Date) cal.newCalendarDate(tz);
date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
}
// Perform the GregorianCalendar-style normalization.
fastTime = cal.getTime(date);
// In case the normalized date requires the other calendar
// system, we need to recalculate it using the other one.
BaseCalendar ncal = getCalendarSystem(fastTime);
if (ncal != cal) {
date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
fastTime = ncal.getTime(date);
}
return date;
}
/**
* Returns the Gregorian or Julian calendar system to use with the
* given date. Use Gregorian from October 15, 1582.
*
* @param year normalized calendar year (not -1900)
* @return the CalendarSystem to use for the specified date
*/
private static final BaseCalendar getCalendarSystem(int year) {
if (year >= 1582) {
return gcal;
}
return getJulianCalendar();
}
private static final BaseCalendar getCalendarSystem(long utc) {
// Quickly check if the time stamp given by `utc' is the Epoch
// or later. If it's before 1970, we convert the cutover to
// local time to compare.
if (utc >= 0
|| utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
- TimeZone.getDefaultRef().getOffset(utc)) {
return gcal;
}
return getJulianCalendar();
}
private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
if (jcal == null) {
return gcal;
}
if (cdate.getEra() != null) {
return jcal;
}
return gcal;
}
synchronized private static final BaseCalendar getJulianCalendar() {
if (jcal == null) {
jcal = (BaseCalendar) CalendarSystem.forName("julian");
}
return jcal;
}
/**
* Save the state of this object to a stream (i.e., serialize it).
*
* @serialData The value returned by <code>getTime()</code>
* is emitted (long). This represents the offset from
* January 1, 1970, 00:00:00 GMT in milliseconds.
*/
private void writeObject(ObjectOutputStream s)
throws IOException
{
s.writeLong(getTimeImpl());
}
/**
* Reconstitute this object from a stream (i.e., deserialize it).
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
fastTime = s.readLong();
}
/**
* 从{@code Instant}对象获取{@code Date}的实例。
* {@code Instant}使用纳秒级的精度,而{@code Date}使用毫秒级的精度。
* 转换将转换任何多余的精度信息,就好像纳秒的数量要被整数除以一百万。
* {@code Instant}可以在时间轴上比{@code Date}更远和过去存储点。在这种情况下,此方法将引发异常。
*/
public static Date from(Instant instant) {
try {
return new Date(instant.toEpochMilli());
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}
/**
* 当前Date对象转化为Instant对象。
*/
public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}
}
问题记录
- Date Calendar Instant 区别
- 各时区的意思区别。