深入学习java源码之Date.before()与Date.clone()
类 Date 表示特定的瞬间,精确到毫秒。
在 JDK 1.1 之前,类 Date 有两个其他的函数。它允许把日期解释为年、月、日、小时、分钟和秒值。它也允许格式化和分析日期字符串。不过,这些函数的 API 不易于实现国际化。从 JDK 1.1 开始,应该使用 Calendar 类实现日期和时间字段之间转换,使用 DateFormat 类来格式化和分析日期字符串。Date 中的相应方法已废弃。
尽管 Date 类打算反映协调世界时 (UTC),但无法做到如此准确,这取决于 Java 虚拟机的主机环境。当前几乎所有操作系统都假定 1 天 = 24 × 60 × 60 = 86400 秒。但对于 UTC,大约每一两年出现一次额外的一秒,称为“闰秒”。闰秒始终作为当天的最后一秒增加,并且始终在 12 月 31 日或 6 月 30 日增加。例如,1995 年的最后一分钟是 61 秒,因为增加了闰秒。大多数计算机时钟不是特别的准确,因此不能反映闰秒的差别。
一些计算机标准是按照格林威治标准时 (GMT) 定义的,格林威治标准时和世界时 (UT) 是相等的。GMT 是标准的“民间”名称;UT 是相同标准的“科学”名称。UTC 和 UT 的区别是:UTC 是基于原子时钟的,UT 是基于天体观察的,两者在实际应用中难分轩轾。因为地球的旋转不是均匀的(它以复杂的方式减速和加速),所以 UT 始终不是均匀地流过。闰秒是根据需要引入 UTC 的,以便把 UTC 保持在 UT1 的 0.9 秒之内,UT1 是应用了某些更正的 UT 版本。
fastTime:当前时间的毫秒表示(从1970.1.1开始算)
Date():用当前时间的毫秒数来初始化fastTime;
public Date() {
this(System.currentTimeMillis());
}
public Date(long date) {
fastTime = date;
}
clone() :返回该Date对象的一个’副本’(虽然返回是Object,不过可以转成Date);
clone方法是用来复制一个对象。不同于“=”。
对于值类型的数据是可以通过“=”来实现复制的。但是对于引用类型的对象,“=”只能复制其内存地址,使对象的引用指向同一个对象,而不会创建新的对象。clone则可以创建与原来对象相同的对象。举个例子:
Car c1 = new Car();
Car c2 = c1;
这两句事实上只创建了一个对象。只不过c1和c2指向了同一个对象。二者指向的还是同一块内存,所以任何一个引用对内存的操作都直接反映到另一个引用上。
Car c1 = new Car();
Car c2 = c1.clone();
那么就有了两个对象,而且这两个对象的内容是一样的。(所有的属性值相同)
浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:
1、基本类型
如果变量是基本类型,则拷贝其值,比如:int、float、long等。
2、String字符串
这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。
3、对象
如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。这在Java中很疯狂,因为它突破了访问权限的定义,一个private修饰的变量,竟然可以被两个实例对象访问。
关于clone方法的浅拷贝的一个demo,可以看出虽然是两个不同的ShallowCopy对象,但是对于他们的非基本数据类型的成员变量是属于同一个引用。因此是浅拷贝
import java.util.Date;
public class ShallowCopy implements Cloneable {
private Date begin;
public Date getBegin(){
return this.begin;
}
public void setBegin(Date d){
this.begin = d;
}
public Object clone(){
Object obj = null;
try{
obj = super.clone();
}catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return obj;
}
public static void main(String[] args) {
Date date = new Date(10000L);
ShallowCopy copy = new ShallowCopy();
copy.setBegin(date);
ShallowCopy copy2 = (ShallowCopy) copy.clone();
System.out.println(copy.getBegin() + "\n"
+ copy2.getBegin() + "\n" +
(copy == copy2));
date.setTime(100000000L);;
System.out.println(copy.getBegin() + "\n"
+ copy2.getBegin() + "\n" +
(copy == copy2));
}
// Thu Jan 01 08:00:10 CST 1970
// Thu Jan 01 08:00:10 CST 1970
// false
// Fri Jan 02 11:46:40 CST 1970
// Fri Jan 02 11:46:40 CST 1970
// false
}
相比深拷贝,拷贝对象的同时,又进行了对成员对象进行了深拷贝。
import java.util.Date;
public class DeepCopy implements Cloneable{
private Date begin;
public Date getBegin(){
return this.begin;
}
public void setBegin(Date d){
this.begin = d;
}
public Object clone(){
DeepCopy obj = null;
try{
obj = (DeepCopy)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
obj.setBegin((Date)this.getBegin().clone());
return obj;
}
public static void main(String[] args) {
Date date = new Date(10000L);
DeepCopy copy = new DeepCopy();
copy.setBegin(date);
DeepCopy copy2 = (DeepCopy) copy.clone();
System.out.println(copy.getBegin() + "\n"
+ copy2.getBegin() + "\n" +
(copy == copy2));
date.setTime(100000000L);
System.out.println(copy.getBegin() + "\n"
+ copy2.getBegin() + "\n" +
(copy == copy2));
}
// Thu Jan 01 08:00:10 CST 1970
// Thu Jan 01 08:00:10 CST 1970
// false
// Fri Jan 02 11:46:40 CST 1970
// Thu Jan 01 08:00:10 CST 1970
// false
}
before(Date when)/after(Date when):与when比较是早(before)还是晚(after)(相当于小于号和大于号)。
compareTo(Date anotherDate):定义比较两个Date对象的规则(通过fastTime值的大小)
案例:计算星期几
package com.cnten.common.utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DateUtil {
public static Date getLastWeekMonday(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(getThisWeekMonday(date));
cal.add(Calendar.DATE, -7);
return cal.getTime();
}
public static Date getLastWeekFriday(Date date)
{
Calendar cal = Calendar.getInstance();
cal.setTime(getThisWeekMonday(date));
cal.add(Calendar.DATE, -3);
return cal.getTime();
}
public static String getLastWeekFridayStr(Date date)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.setTime(getThisWeekMonday(date));
cal.add(Calendar.DATE, -3);
return sdf.format(cal.getTime());
}
public static String getLastWeekMondayStr(Date date)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.setTime(getThisWeekMonday(date));
cal.add(Calendar.DATE, -7);
return sdf.format(cal.getTime());
}
public static Date getThisWeekMonday(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// 获得当前日期是一个星期的第几天
int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
if (1 == dayWeek) {
cal.add(Calendar.DAY_OF_MONTH, -1);
}
// 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
cal.setFirstDayOfWeek(Calendar.MONDAY);
// 获得当前日期是一个星期的第几天
int day = cal.get(Calendar.DAY_OF_WEEK);
// 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
return cal.getTime();
}
}
Date now = new Date();
//判断本周是星期几:1是星期日、2是星期一、3是星期二、4是星期三、5是星期四、6是星期五、7是星期六
int weekDay = DateUtil.getDayofweek(now);
//上周一日期
String lastMonday = DateUtil.getWeekDayOfDate(now, -7);
//上周二日期
String lastThuesDay = DateUtil.getWeekDayOfDate(now, -6);
//上周三
String lastWednesday = DateUtil.getWeekDayOfDate(now, -5);
//上周四日期
String lastThursDay = DateUtil.getWeekDayOfDate(now, -4);
//上周五
String lastFriDay = DateUtil.getWeekDayOfDate(now, -3);
//本周周一
String thisMonday = DateUtil.getThisWeekMondayStr(now);
//本周周二
String thisThuesDay = DateUtil.getWeekDayOfDate(now, 1);
//本周三
String thisWednesday = DateUtil.getWeekDayOfDate(now, 2);
//本周四
String thisThursDay = DateUtil.getWeekDayOfDate(now, 3);
//本周五
String thisFriDay = DateUtil.getWeekDayOfDate(now, 4);
List allDataList = new ArrayList();
java源码
Modifier and TypeMethod and Descriptionboolean
after(Date when)
测试此日期是否在指定日期之后。
boolean
before(Date when)
测试此日期是否在指定日期之前。
Object
clone()
返回此对象的副本。
int
compareTo(Date anotherDate)
比较两个日期进行订购。
boolean
equals(Object obj)
比较两个日期来平等。
static Date
from(Instant instant)
从 Instant
对象获取一个 Date
的实例。
int
getDate()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.DAY_OF_MONTH)
。
int
getDay()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.DAY_OF_WEEK)
。
int
getHours()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.HOUR_OF_DAY)
。
int
getMinutes()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.MINUTE)
取代。
int
getMonth()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.MONTH)
取代。
int
getSeconds()
已弃用 截至JDK 1.1版,由Calendar.get(Calendar.SECOND)
。
long
getTime()
返回自1970年1月1日以来,由此 Date对象表示的00:00:00 GMT的毫秒 数 。
int
getTimezoneOffset()
已弃用 自JDK 1.1版起,由-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)
取代。
int
getYear()
已弃用 从JDK 1.1版开始,由Calendar.get(Calendar.YEAR) - 1900
。
int
hashCode()
返回此对象的哈希码值。
static long
parse(String s)
已弃用 从JDK 1.1版开始,由DateFormat.parse(String s)
。
void
setDate(int date)
已弃用 从JDK 1.1版开始,由Calendar.set(Calendar.DAY_OF_MONTH, int date)
。
void
setHours(int hours)
已弃用 从JDK 1.1版开始,由Calendar.set(Calendar.HOUR_OF_DAY, int hours)
。
void
setMinutes(int minutes)
已弃用 从JDK 1.1版开始,由Calendar.set(Calendar.MINUTE, int minutes)
。
void
setMonth(int month)
已弃用 从JDK 1.1版开始,由Calendar.set(Calendar.MONTH, int month)
。
void
setSeconds(int seconds)
已弃用 从JDK 1.1版起,由Calendar.set(Calendar.SECOND, int seconds)
取代。
void
setTime(long time)
设置此 Date
对象以表示1970年1月1日00:00:00 GMT后的 time
毫秒的时间点。
void
setYear(int year)
已弃用 截至JDK 1.1版,由Calendar.set(Calendar.YEAR, year + 1900)
取代。
String
toGMTString()
已弃用 截至JDK 1.1版,由DateFormat.format(Date date)
,使用GMT TimeZone
。
Instant
toInstant()
将此 Date
对象转换为 Instant
。
String
toLocaleString()
已弃用 从JDK 1.1版开始,由DateFormat.format(Date date)
替换。
String
toString()
将此 Date
对象转换为 String
的形式:
static long
UTC(int year, int month, int date, int hrs, int min, int sec)
已弃用 截至JDK 1.1版,由Calendar.set(year + 1900, month, date, hrs, min, sec)
或GregorianCalendar(year + 1900, month, date, hrs, min, sec)
,使用UTC TimeZone
,其次是Calendar.getTime().getTime()
。
package java.util;
import java.text.DateFormat;
import java.time.LocalDate;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.lang.ref.SoftReference;
import java.time.Instant;
import sun.util.calendar.BaseCalendar;
import sun.util.calendar.CalendarDate;
import sun.util.calendar.CalendarSystem;
import sun.util.calendar.CalendarUtils;
import sun.util.calendar.Era;
import sun.util.calendar.Gregorian;
import sun.util.calendar.ZoneInfo;
public class Date
implements java.io.Serializable, Cloneable, Comparable
{
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;
public Date() {
this(System.currentTimeMillis());
}
public Date(long date) {
fastTime = date;
}
@Deprecated
public Date(int year, int month, int date) {
this(year, month, date, 0, 0, 0);
}
@Deprecated
public Date(int year, int month, int date, int hrs, int min) {
this(year, month, date, hrs, min, 0);
}
@Deprecated
public Date(int year, int month, int date, int hrs, int min, int sec) {
int y = year + 1900;
// month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
if (month >= 12) {
y += month / 12;
month %= 12;
} else if (month < 0) {
y += CalendarUtils.floorDivide(month, 12);
month = CalendarUtils.mod(month, 12);
}
BaseCalendar cal = getCalendarSystem(y);
cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
getTimeImpl();
cdate = null;
}
@Deprecated
public Date(String s) {
this(parse(s));
}
public Object clone() {
Date d = null;
try {
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
}
} catch (CloneNotSupportedException e) {} // Won't happen
return d;
}
@Deprecated
public static long UTC(int year, int month, int date,
int hrs, int min, int sec) {
int y = year + 1900;
// month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
if (month >= 12) {
y += month / 12;
month %= 12;
} else if (month < 0) {
y += CalendarUtils.floorDivide(month, 12);
month = CalendarUtils.mod(month, 12);
}
int m = month + 1;
BaseCalendar cal = getCalendarSystem(y);
BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
// Use a Date instance to perform normalization. Its fastTime
// is the UTC value after the normalization.
Date d = new Date(0);
d.normalize(udate);
return d.fastTime;
}
@Deprecated
public static long parse(String s) {
int year = Integer.MIN_VALUE;
int mon = -1;
int mday = -1;
int hour = -1;
int min = -1;
int sec = -1;
int millis = -1;
int c = -1;
int i = 0;
int n = -1;
int wst = -1;
int tzoffset = -1;
int prevc = 0;
syntax:
{
if (s == null)
break syntax;
int limit = s.length();
while (i < limit) {
c = s.charAt(i);
i++;
if (c = 0)
year = n;
else
break syntax;
prevc = 0;
} else if (c == '/' || c == ':' || c == '+' || c == '-')
prevc = c;
else {
int st = i - 1;
while (i < limit) {
c = s.charAt(i);
if (!('A' 32);
}
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;
}
@Deprecated
public String toLocaleString() {
DateFormat formatter = DateFormat.getDateTimeInstance();
return formatter.format(this);
}
@Deprecated
public String toGMTString() {
// d MMM yyyy HH:mm:ss 'GMT'
long t = getTime();
BaseCalendar cal = getCalendarSystem(t);
BaseCalendar.Date date =
(BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
StringBuilder sb = new StringBuilder(32);
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
sb.append(date.getYear()).append(' '); // yyyy
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2); // ss
sb.append(" GMT"); // ' GMT'
return sb.toString();
}
@Deprecated
public int getTimezoneOffset() {
int zoneOffset;
if (cdate == null) {
TimeZone tz = TimeZone.getDefaultRef();
if (tz instanceof ZoneInfo) {
zoneOffset = ((ZoneInfo)tz).getOffsets(fastTime, null);
} else {
zoneOffset = tz.getOffset(fastTime);
}
} else {
normalize();
zoneOffset = cdate.getZoneOffset();
}
return -zoneOffset/60000; // convert to minutes
}
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 the specified year can't be handled using a long value
// in milliseconds, GregorianCalendar is used for full
// compatibility with underflow and overflow. This is required
// by some JCK tests. The limits are based max year values -
// years that can be represented by max values of d, hh, mm,
// ss and ms. Also, let GregorianCalendar handle the default
// cutover year so that we don't need to worry about the
// transition here.
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;
}
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 getTime()
* 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();
}
public static Date from(Instant instant) {
try {
return new Date(instant.toEpochMilli());
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}
public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}
}