java.util.Date和java.util.Calendar及相关类

Date

Date 表示特定的瞬间,精确到毫秒。在JDK1.1之前,Date有两个其他的函数。它允许把日期解释为年、月、日、小时、分钟和秒值。它也允许格式化和解析日期字符串。不过,这些函数的API不易于实现国际化。从JDK1.1开始,应该使用Calendar类实现日期和时间字段之间转换,使用DateFormat类来格式化和解析日期字符串。Date中的相应方法已废弃。

Date使用UTC时间,如Thu Jun 30 17:12:57 CST 2016,CST表示China Standard Time UT+8:00。尽管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版本。还有其他的时间和日期系统;例如,基于卫星的全球定位系统(GPS)使用的时间刻度与UTC同步,但没有针对闰秒进行调整。

大部分Date的方法都过时了,由Calendar类的方法替代,以下是几个重要的方法:

构造方法

public Date()

当前时间。

public Date(long date)

分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。

例子:

public static void main(String[] args) {
        System.out.println(new Date());//Thu Jan 01 08:00:00 CST 1970 CST表示UTC+8,所以是8点
    }

其他

public boolean after(Date when)

测试此日期是否在指定日期之后。

public boolean before(Date when)

测试此日期是否在指定日期之前。

public int compareTo(Date anotherDate)

比较两个日期的顺序。

如果参数Date等于此Date,则返回值0;如果此Date在Date参数之前,则返回小于0的值;如果此Date在Date参数之后,则返回大于0的值。

public boolean equals(Object obj)

比较两个日期的相等性。当且仅当参数不为null,并且是一个表示与此对象相同的时间点(到毫秒)的Date对象时,结果才为true。

因此,当且仅当getTime方法对于两个Date对象返回相同的long值时,这两个对象才是相等的。

public long getTime()

返回自1970 年 1 月 1 日 00:00:00 GMT以来此Date对象表示的毫秒数。

public void setTime(long time)

设置此Date对象,以表示1970 年 1 月 1 日 00:00:00 GMT以后time毫秒的时间点。

TimeZone

TimeZone表示时区偏移量,也可以计算夏令时。

通常,使用getDefault获取TimeZone,getDefault基于程序运行所在的时区创建TimeZone。例如,对于在日本运行的程序,getDefault基于日本标准时间创建TimeZone对象。

也可以用getTimeZone及时区ID获取TimeZone。例如美国太平洋时区的时区ID是"America/Los_Angeles"。因此,可以使用下面语句获得美国太平洋时间TimeZone对象:TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");

可以使用getAvailableIDs方法来对所有受支持的时区ID进行迭代。可以选择受支持的ID来获得TimeZone。

如果想要的时区无法用受支持的ID之一表示,那么可以指定自定义时区ID来生成TimeZone。自定义时区ID的语法是:

NormalizedCustomID:

GMT Sign TwoDigitHours : Minutes

Sign:下面之一

+ -

TwoDigitHours:

Digit Digit

Minutes:

Digit Digit

Digit:下面之一

0 1 2 3 4 5 6 7 8 9

例如,TimeZone.getTimeZone("GMT-8").getID()返回"GMT-08:00"。

Hours必须在0至23之间,Minutes必须在00至59之间。例如,"GMT+10"和"GMT+0010"分别意味着比GMT提前10小时和10分钟。

为了与JDK1.1.x兼容,一些三字母时区ID(比如"PST"、"CTT"、"AST")也受支持。但是,它们的使用被废弃,这是因为相同的缩写经常用于多个时区(例如"CST"可以是美国的"Central Standard Time"和"China Standard Time"),但是 Java平台只可以识别其中一种。

例子:

public static void main(String[] args) {
        TimeZone timeZone = TimeZone.getDefault();
        System.out.println(timeZone.getDisplayName(true, TimeZone.LONG));//中国夏令时
        System.out.println(timeZone.getDisplayName(false, TimeZone.LONG));//中国标准时间
        System.out.println(timeZone.getDisplayName(true, TimeZone.SHORT));//CDT
        System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));//CST
        System.out.println(timeZone.getID());//Asia/Shanghai

        TimeZone timeZone1 = TimeZone.getTimeZone("AST");
        System.out.println(timeZone1.getDisplayName(true, TimeZone.LONG));//阿拉斯加夏令时
        System.out.println(timeZone1.getDisplayName(false, TimeZone.LONG));//阿拉斯加标准时间
        System.out.println(timeZone1.getDisplayName(true, TimeZone.SHORT));//AKDT
        System.out.println(timeZone1.getDisplayName(false, TimeZone.SHORT));//AKST
        System.out.println(timeZone1.getID());//AST

        TimeZone timeZone2 = TimeZone.getTimeZone("America/Los_Angeles");
        System.out.println(timeZone2.getDisplayName(true, TimeZone.LONG));//太平洋夏令时
        System.out.println(timeZone2.getDisplayName(false, TimeZone.LONG));//太平洋标准时间
        System.out.println(timeZone2.getDisplayName(true, TimeZone.SHORT));//PDT
        System.out.println(timeZone2.getDisplayName(false, TimeZone.SHORT));//PST
        System.out.println(timeZone2.getID());//America/Los_Angeles

        TimeZone timeZone3 = TimeZone.getTimeZone("GMT+0010");
        System.out.println(timeZone3.getDisplayName(true, TimeZone.LONG));//GMT+00:10
        System.out.println(timeZone3.getDisplayName(false, TimeZone.LONG));//GMT+00:10
        System.out.println(timeZone3.getDisplayName(true, TimeZone.SHORT));//GMT+00:10
        System.out.println(timeZone3.getDisplayName(false, TimeZone.SHORT));//GMT+00:10
        System.out.println(timeZone3.getID());//GMT+00:10
    }

Calendar

Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间1970 年 1 月 1 日的00:00:00.000,格里高利历)的偏移量。由于Calendar是抽象类,它有多个子类,例如GregorianCalendar(格里高利历或称公历)、JapaneseImperialCalendar(JDK7.0增加)。与其他语言环境敏感类一样,Calendar
提供了一个类方法getInstance,以获得此类型的一个通用的对象。Calendar的getInstance方法返回一个Calendar子类的对象,其日历字段已由当前日期和时间初始化:

public static Calendar getInstance()

返回的 Calendar 基于当前时间,使用了默认时区和默认语言环境。

public static Calendar getInstance(Locale aLocale)

返回的 Calendar 基于当前时间,使用了默认时区和给定的语言环境。

public static Calendar getInstance(TimeZone zone)

返回的 Calendar 基于当前时间,使用了给定时区和默认语言环境。

public static Calendar getInstance(TimeZone zone,Locale aLocale)

返回的 Calendar 基于当前时间,使用了给定的时区和给定的语言环境。

Calendar使用两个参数定义了特定于语言环境的7天制星期:

星期的第一天(firstDayOfWeek):例如,在美国,这一天是 SUNDAY,而在法国,这一天是 MONDAY。

第一个星期中的最小一天(minimalDaysInFirstWeek,范围是1-7):一年中第一个星期所需的最少天数。

这些数字取自构造Calendar时的Locale。还可以通过为其设置值的方法来显式地指定它们。

获得并设置日历字段值

可以通过调用set方法来设置日历字段值。在需要计算时间值(距历元所经过的毫秒)或日历字段值之前,不会解释Calendar中的所有字段值设置。调用get、getTimeInMillis、getTime、add 和roll涉及此类计算。

宽松性

Calendar有两种解释日历字段的模式,即lenient和non-lenient。当Calendar处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。当Calendar重新计算日历字段值,以便由get()返回这些值时,所有日历字段都被标准化。例如,lenient模式下的GregorianCalendar将MONTH == JANUARY、DAY_OF_MONTH == 32解释为February
1。

当Calendar处于non-lenient模式时,如果其日历字段中存在任何不一致性,它都会抛出一个异常。例如,GregorianCalendar总是在1与月份的长度之间生成DAY_OF_MONTH值。如果已经设置了任何超出范围的字段值,那么在计算时间或日历字段值时,处于non-lenient模式下的GregorianCalendar会抛出一个异常。public void setLenient(boolean lenient)可以设置宽松性。

日历字段解析

在计算日历字段中的日期和时间时,可能没有足够的信息用于计算(例如只有年和月,但没有日),或者可能有不一致的信息( 例如 "Tuesday, July 15, 1996"(格林威治时间)——实际上,1996 年 7 月 15 日是星期一 )。Calendar将解析日历字段值,以便用以下方式确定日期和时间。

如果日历字段值中存在任何冲突,则Calendar将为最近设置的日历字段提供优先权。以下是日历字段的默认组合。将使用由最近设置的单个字段所确定的最近组合。

YEAR + MONTH + DAY_OF_MONTH

YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK

YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK

YEAR + DAY_OF_YEAR

YEAR + DAY_OF_WEEK + WEEK_OF_YEAR

HOUR_OF_DAY

AM_PM + HOUR

如果在选定的字段组合中,还有尚未设置值的任一日历字段,那么Calendar将使用其默认值。每个字段的默认值可能依据具体的日历系统而有所不同。例如,在GregorianCalendar中,字段的默认值与历元起始部分的字段值相同:即YEAR = 1970、MONTH = JANUARY、DAY_OF_MONTH = 1,等等。

GregorianCalendar

GregorianCalendar是Calendar最重要的一个子类,提供了世界上大多数国家/地区使用的标准日历系统。 GregorianCalendar是一种混合日历,在单一间断性的支持下同时支持儒略历和格里高利历系统。setGregorianChange(Date date)设置GregorianCalendar的更改日期。这是发生从儒略历日期切换到格里高利历日期的点。默认时间是1582 年 10
月 15 日(格里高利历)。在此之前,日期是按照儒略历计算的。 要得到纯粹的儒略历日历,可将更改日期设置为Date(Long.MAX_VALUE)。要得到一个纯粹的格里高利历日历,可将更改日期设置为Date(Long.MIN_VALUE)。 历史上,在那些首先采用格里高利历的国家/地区中,1582 年 10 月 4 日(儒略历)之后就是 1582 年 10 月 15 日(格里高利历)。此日历正确地模拟了这些变化。在开始格里高利历之前,GregorianCalendar实现的是儒略历。格里高利历和儒略历之间的唯一区别就是闰年规则。儒略历指定每
4 年就为闰年,而格里高利历则忽略不能被400整除的世纪年。在格里高利历创立以前,新年是3 月 25 日。为了避免混淆,此日历始终使用1 月 1 日为新年。如果想要格里高利历转换之前并且处于1 月 1 日和 3 月 24 日之间的日期,则可以进行手动调整。

WEEK_OF_YEAR 字段值的范围从1 到 53。一年的第一个星期始于getFirstDayOfWeek() 的最早7 天,至少包含该年的getMinimalDaysInFirstWeek()天。这取决于 getMinimalDaysInFirstWeek()、getFirstDayOfWeek()的值以及1 月 1 日是星期几。一年的第一个星期和下一年的第一个星期之间的各个星期按顺序从2到52或53(根据需要)进行编号。

例如,1998 年 1 月 1 日是星期四。如果getFirstDayOfWeek()为MONDAY,并且getMinimalDaysInFirstWeek()为4(这些值反映了ISO 8601和很多国家/地区标准),则1998 年的第一个星期开始于1997 年 12 月 29 日,结束于1998 年 1 月 4 日。但是,如果getFirstDayOfWeek()为SUNDAY,那么1998年的第一个星期开始于1998 年 1 月 4 日,结束于1998 年 1 月 10 日;1998年头三天是1997 年第53个星期的一部分。

WEEK_OF_MONTH 字段值的范围从0到6。一个月的第一个星期(WEEK_OF_MONTH = 1 的日期)是该月至少连续 getMinimalDaysInFirstWeek() 天中的最早日期,结束于 getFirstDayOfWeek() 的前一天。与一年的第一个星期不同,一个月的第一个星期可能短于7天,也不必从getFirstDayOfWeek()这一天开始,并且不包括前一个月的日期。在第一个星期之前该月日期的WEEK_OF_MONTH为0。

例如,如果getFirstDayOfWeek() 为SUNDAY,getMinimalDaysInFirstWeek()为4,那么1998 年 1 月的第一个星期是从1 月 4 日星期日到1 月 10 日星期六。这些天的 WEEK_OF_MONTH 为1。1 月 1 日星期四到1 月 3 日星期六的WEEK_OF_MONTH为0。如果getMinimalDaysInFirstWeek() 变为3,则1 月 1 日到1 月 3 日的 WEEK_OF_MONTH 为 1。

clear方法将日历字段设置为未定义。GregorianCalendar为每个日历字段使用以下默认值(如果该值未定义)。

字段 默认值
ERA AD
YEAR 1970
MONTH JANUARY
DAY_OF_MONTH 1
DAY_OF_WEEK 一个星期的第一天
WEEK_OF_MONTH 0
DAY_OF_WEEK_IN_MONTH 1
AM_PM AM
HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND 0

字段操作

set(f, value) 

将日历字段f更改为value。此外,它设置了一个内部成员变量,以指示日历字段f已经被更改。尽管日历字段f是立即更改的,但是直到下次调用get()、getTime()、getTimeInMillis()、add() 或 roll()时才会重新计算日历的时间值(以毫秒为单位)。因此,多次调用set()不会触发多次不必要的计算。使用set()更改日历字段的结果是,其他日历字段也可能发生更改,这取决于日历字段、日历字段值和日历系统。

示例:假定GregorianCalendar最初被设置为1999 年 8 月 31 日。调用set(Calendar.MONTH, Calendar.SEPTEMBER)将该日期设置为 1999 年 9 月 31 日。这是1999 年 10 月 1 日的一个暂时内部表示。此时月份按道理应该是10月,但是,在调用getTime()之前调用set(Calendar.DAY_OF_MONTH, 30) 会将该日期设置为1999
年 9 月 30 日,因为在调用set()之后没有发生重新计算。

add(f, delta)

将delta添加到f字段中。这等同于调用set(f, get(f) + delta)。与set()不同,add()强迫日历系统立即重新计算日历的毫秒数和所有字段。add()有两个规则:

1、调用后f字段的值减去调用前f字段的值等于delta,字段f字段值超出其范围时,下一个更大的字段会递增或递减,并将字段值调整回其范围内。

2、如果期望某一个更小的字段是不变的,但让它等于以前的值是不可能的,因为在字段f发生更改之后,或者在出现其他约束之后,比如时区偏移量发生更改,它的最大值和最小值也在发生更改,然后它的值被调整为尽量接近于所期望的值。更小的字段表示一个更小的时间单元,例如HOUR是一个比DAY_OF_MONTH更小的字段。对于不期望是不变字段的更小字段,无需进行任何调整。日历系统例如格里高利历等会确定期望不变的那些字段。

示例:假定GregorianCalendar最初被设置为1999 年 8 月 31 日。调用add(Calendar.MONTH, 13) 将日历设置为2000 年 9 月 30 日。Add 规则1 MONTH字段设置为September,因为向August添加13个月得出的就是下一年的September。因为在GregorianCalendar 中,DAY_OF_MONTH不可能是9 月 31 日,所以add
规则2将DAY_OF_MONTH设置为30,即最可能的值。尽管DAY_OF_WEEK是一个更小的字段,但不能根据规则2调整DAY_OF_WEEK,因为在GregorianCalendar中的月份发生变化时,该值也需要发生变化。这个例子可以理解为,月份往后增加13个月后的月份最后一天。

roll(f, delta)

将delta添加到f字段中,这等同于调用add(f, delta),但不更改更大的字段。更大的字段表示一个更大的时间单元。DAY_OF_MONTH 是一个比HOUR大的字段。

add和roll的区别

原来设置为1999 年 8 月 31 日的GregorianCalendar 。现在调用roll(Calendar.MONTH, 8) 将该日历设置为1999 年 4 月 30 日。如果使用GregorianCalendar,则4月份的DAY_OF_MONTH字段不可能为 31。将DAY_OF_MONTH设置为最可能接近的值30。YEAR字段保持为值1999,因为它是一个比MONTH 更大的字段,所以不能改变。

原来设置为1999 年 6 月 6日星期日的GregorianCalendar 。现在调用roll(Calendar.WEEK_OF_MONTH, -1) 将该日历设置为1999 年 6 月 1 日星期二,而调用add(Calendar.WEEK_OF_MONTH, -1) 则将日历设置为1999 年 5 月 30 日星期日。这是因为上升和下降规则施加了其他的约束:WEEK_OF_MONTH改变时MONTH必须不变。所得日期必定在6 月 1日星期二和6 月 5 日星期六之间。DAY_OF_WEEK(在改变WEEK_OF_MONTH时它是一个不变量)被设置为Tuesday,是最接近Sunday的可能值(其中星期日是一个星期的第一天)。

时间: 07-01

java.util.Date和java.util.Calendar及相关类的相关文章

java.sql.date与java.util.date区别以及数据库中插入带时分秒的时间

java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类(包装类). java.sql.Date是java.util.Date的子类,是一个包装了毫秒值的瘦包装器,允许 JDBC 将毫秒值标识为 SQL DATE 值.毫秒值表示自 1970 年 1 月 1 日 00:00:00 GMT 以来经过的毫秒数. 为了与 SQL DATE 的定义一致,由 java.sql.Date 实例包装的毫秒值必须通过将时间.分钟.秒和毫

JAVA 处理时间 - java.sql.Date、java.util.Date与数据库中的Date字段的转换方法[转]

1.如何将java.util.Date转化为java.sql.Date? 转化: java.sql.Date sd; java.util.Date ud; //initialize the ud such as ud = new java.util.Date(); sd = new java.sql.Date(ud.getTime()); 2.如何将获取到的java.sql.Date转换为年-月-日输出 java.sql.Date sd; String dateTime = sd.toStrin

java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp区别和联系

参考:链接 在Web开发中,避免不了对日期的操作,常用的关于时间的类有这么几个: java.util.Date.java.sql.Date.java.sql.Time.java.sql.Timestamp,这几个类在JDK的定义如下所示: java.lang.Object -.|__java.util.Date ---.|__java.sql.Date/java.sql.Timestamp/java.sql.Time -.|__java.security.Timestamp java.util.

java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp小结

final SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);//dd/MM/yyyy final Date now = new Date(); System.out.println(now); final String strDate = sdfDate.format(now); System.out.println(strDate); final Timesta

android java.util.Date和java.util.sql中Date的区别

1.将java.util.Date 转换为 java.sql.Date java.sql.Date sd; java.util.Date ud; //initialize the ud such as ud = new java.util.Date(); sd = new java.sql.Date(ud.getTime()); 2.若要插入到数据库并且相应的字段为Date类型 可使用PreparedStatement.setDate(int ,java.sql.Date)方法 其中的java.

java.util.Date和java.sql.Date的区别和相互转化

java.util.Date是在除了SQL语句的情况下面使用的.java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分它们都有getTime方法返回毫秒数,自然就可以直接构建. java.util.Date 是 java.sql.Date 的父类,前者是常用的表示时间的类,我们通常格式化或者得到当前时间都是用他,后者之后在读写数据库的时候用他,因为PreparedStament的setDate()的第2参数和ResultSet的getDate()方法的第2个参数都是java

java.util.Date与java.sql.Date

我数据库里用到了日期类型.用java编程的时候同时import了java.util.*和java.sql.*,发现直接申明Date类型 Date dt; 会报错,查了一下才发现有java.util.Date和java.sql.Date,在定义日期类型的时候要使用全名,就是像这样: java.util.Date udt; java.sql.Date sdt; 然后我就查java.util.Date和java.sql.Date的区别和用法,这方面网上资料挺全,我就不赘述了,大致区别就是java.ut

如何将java.util.Date转为java.sql.Date

以下的信息将会帮到你 1.将java.util.Date转换为 java.sql.Date java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime()); 2.若要插入到数据库并且相应的字段为Date类型 可使用PreparedStatement.setDate(int ,java.sql.Date)方法 其中的java.sql.Date可

java.sql.date和java.util.date的区别和转换

不同点:java.util.Date是在除了SQL语句的情况下面使用的.java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分java.util.Date 是 java.sql.Date 的父类,即:继承关系:java.lang.Object --> java.util.Date --> java.sql.Date共同点:都有getTime方法返回毫秒数,可以直接构建 之间的互相转换: java.sql.Date转为java.util.Date java.sql.Date

java.sql.Date和java.util.Date的不同和相互转换方式

一:前言 这是我在新的公司写的第一份博客吧,来了又一个星期了吧,但是在来的那几天我真的很迷茫的感觉这里是很不适合我的样子,而且我又是来实习的,我很不愿意啊,自己做的又是java web,最原始的servlet,代码和混乱,这让我很无奈啊,所以我在星期一的时候开始提出辞职,然后老大找我谈了谈,说这个项目是我们外包给别人的,我们只是在他们没空的时候改一改罢了,这样说至少让我感觉到还可以接受,最后我又提了下我自己不想实习,提高工资的事情也通过了,公司的干事效率还是很高的啊.虽然做的是servlet,但