这篇文章我试着说明以下java中的时间类API, 我们知道java8在时间API上做了很大的改动, 增加了新的类并废弃了之前使用的一些方法, 不过这里我们还是从头讲起, 即Date, Calendar, DateTime, Instant这样的顺序.
本文会忽略所有已被标记为@deprecated
的方法.
Date
public class Date implements java.io.Serializable, Cloneable, Comparable<Date>
Date的构造函数
Date() //以当前确切时间构造一个Date对象
Date(long) //传入一个毫秒为单位的1970年时间戳
Date定义的方法
- 静态方法
Date from(Instant) //Instant转换为Date, 为什么不设计为构造函数呢?
- 对象方法, 看字面意思容易理解, 略
boolean after(Date)
boolean before(Date)
int compareTo(Date) //比较大小, 返回-1,0, 或1
long getTime()
void setTime(long)
Instant toInstant()
String toString()
总结
在废弃了相当多的方法之后, Date类只剩下了上面一些简单方法, 如果只需要一些简单操作还是可以一用的.
Calendar
public abstract class Calendar
implements Serializable, Cloneable, Comparable<Calendar>
这是一个抽象类
Calendar的唯一实现类是GregorianCalendar, 即公历(格里高利历法), 虽然在java.util包中还有一个JapaneseImperialCalendar, 但是它是default class所以略去.
Calendar中存有一个时间值, 以及地区, 时区等必要信息, 我们通过在方法中传入时间单位(年月日时分秒星期等)进行操作. 实践证明这是一种差劲的做法, 所以Java8又重新设计了一些类以替代它.
Calendar定义的常量(50个)
Calendar中定义了很多常量, 足够单独提出来作为一节说明了
所有的常量都是int
类型的
- 时间单位标志(19个), 对应的值按行排分别为0-17, 因为有2个重复
ERA //*好像是表示年代, 比如康熙xx年或庆丰xx年这样?,
YEAR,
MONTH,
WEEK_OF_YEAR,
WEEK_OF_MONTH,
DATE, DAY_OF_MONTH //等于DATE,
DAY_OF_YEAR,
DAY_OF_WEEK,
DAY_OF_WEEK_IN_MONTH //不懂,
AM_PM,
HOUR //12小时制,
HOUR_OF_DAY //24小时制,
MINUTE,
SECOND,
MILLISECOND,
ZONE_OFFSET //GMT时差
DST_OFFSET //夏令时时差
FIELD_COUNT //?
//最后这三个为什么和其他常量也算是并列关系呢
- 星期几(7个), 从
SUNDAY
开始到SATURDAY
, 对应值为1-7 - 月份名(13个), 从
JANUARY
开始到DECEMBER
, 对应值为0-11, 此外还有1个UNDECEMBER
, 值为12, 表示第13个月, 文档的解释是可能其他历法会用到? - (2个)
AM
,PM
- 标志月份, 星期等单词的表示方式(9个), 是Jan还是January; M, Mon, 还是Monday, 用于
getDisplayName()
和getDisplayNames()
. 而对应值...比较奇怪, 仅对ERA, MONTH, AM_PM, DAY_OF_WEEK有作用
ALL_STYLES = 0
SHORT = SHORT_FORMAT = 1
LONG = LONG_FORMAT = 2
NARROW_FORMAT = 4
//不知道和上面的区别在哪, 测试的时候没发现结果有什么不一样
NARROW_STANDALONE = 4 | 0x0800
SHORT_STANDALONG = 1 | 0x0800
LONG_STANDALONG = 2 | 0x0800
Calendar定义的方法
- 静态方法
//获取当前系统环境下的所有Calendar类型, 我试了一下有3种: [gregory, buddhist, japanese]
Set<String> getAvailableCalendarTypes()
/*Returns an array of all locales for which the getInstance methods of this
class can return localized instances*/
Locale[] getAvailableLocales()
//默认返回公历GregorianCalendar, 等价于new GregorianCalendar(), 内部为当前确切时间
//其他重载方法没有用过不清楚, 大概就是根据时区和地区返回某个新Calendar对象
Calendar getInstance()
Calendar getInstance(Locale)
Calendar getInstance(TimeZone)
Calendar getInstance(TimeZone, Locale)
- 对象方法
//比较时间先后, 虽然参数为Object但必须是Calendar类型, 否则返回false, 为什么要这样设计?
boolean after(Object)
boolean before(Object)
int compareTo(Calendar) //根据时间先后返回-1,0或1
boolean equals(Object) //日历类型相同且表示的时间相同
//获得某种时间单位(年份, 月份等)对应的值
int get(int field)
//设置时间, 如果大于实际值则向上递增, 例set(Calendar.DATE, 32) = 下个月的1日,
//set方法还有其他重载, 见3.
void set(int field, int amount)
//见3.中的getMaximum和getMinimum
int getActuralMaximum(int field)
int getActualMinimum(int field)
String getCalendarType() //日历类型
//获得日历表示的时间对应的单词, 对ERA, MONTH, AM_PM, DAY_OF_WEEK有效, 其他值会返回null
String getDisplayName(int field, int style, Locale locale)
/*获得field(对ERA, MONTH, AM_PM, DAY_OF_WEEK有效)对应的所有单词, 存储为
Map<String, Integer>*/
/*例: getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.ALL_STYLES, Locale.US) =
{Wednesday=4, Saturday=7, Thursday=5, Tuesday=3, Friday=6, Monday=2, Sunday=1,
Fri=6, Mon=2, Sat=7, Sun=1, Thu=5, Tue=3, Wed=4} */
Map<String, Integer> getDisplayNames(int field, int style, Locale locale)
//e.g., SUNDAY in the U.S., MONDAY in France
int getFirstDayOfWeek()
//也可以手动设置
void setFirstDayOfWeek(int)
//获取"第一周"的天数, 有的地方是从1月1日开始算, 有的地方是算第一个完整的星期
int getMinimalDaysInFirstWeek()
//*这个也可以手动设置?
void setMinimalDaysInFirstWeek(int)
//1970年的时间戳, 单位为毫秒
long getTimeInMillis()
void setTimeInMillis(long)
TimeZone getTimeZone()
void setTimeZone()
/*不懂, 试了一下输出是2018, 文档写Returns the week year represented by this Calendar,
什么意思呢*/
int getWeekYear()
//返回这一年的总的星期数.
int getWeeksInWeekYear()
//*日历是否是"宽松的"(?), 不懂, 默认为true
boolean isLenient()
void setLenient(boolean)
//*这又是啥
boolean isWeekDateSupported()
void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek)
//时间计算, 和add区别在于不改变其他单位的值, 即5月31日+1天=5月1日...
void roll(int field, int amount)
String toString() //返回一大长串东西, 方便调试但不适合展示
3.final方法
void clear() //重置Calendar对象, 重置后为undefined, 不保证为1970年
void clear(int field) /把某个时间单位重置为undefined
Date getTime()
boolean isSet(int field) //某个时间单位是否是确定的(not undefined)
//如果超出范围向上递增, 注意month取值0-11
void set(int year, int month, int date)
void set(int year, int month, int date, int hourOfDay, int minute)
void set(int year, int month, int date, int hourOfDay, int minute, int second)
Instant toInstant()
- 抽象方法
//时间计算, amount可以为负数
void add(int field, int amount)
/*把getActuralMaximum和getActualMinimum也放在这里一同说明*/
/*getMaximum和getMinimum是该历法中某个时间单位(年月日)的取值范围, 所以是抽象方法,
例: getMaximum(Calendar.DATE) = 31*/
/*getActuralMaximum和getActualMinimum和当前日期有关, 例如, 当前日期为2016-2-1,
则getMaximum(Calendar.DATE) = 29*/
/*getLeastMaximum是该历法中所有可取值的最小值, 和当前日期无关, 总有
getLeastMaximum(Calendar.DATE) = 28*; 但是DAY_OF_YEAR的最小值为什么是355不是365?*/
int getGreatestMinimum(int field)
int getLeastMaximum(int field)
int getMaximum(int field)
int getMinimum(int field)
//--int getActuralMaximum(int field)
//--int getActualMinimum(int field)
//见void roll(int field, int amount)
void roll(int field, boolean up)
Calendar中的静态类
public static class Builder
这是Calendar中的一个静态类, 其中基本都是setxxx()方法, 大概是通过设置一些参数, 用来帮助开发者相对快速地实现一个简单的Calendar类. 请自行查询源码吧...
总结
简单测试了几个方法, 我就发现果然这种通过参数区分年月日的做法在写编码的时候很别扭, 而且简单的逻辑也需要写很多行代码来实现. 不过这也是Java的老毛病了.
GregorianCalendar
话虽如此, 我还是要说明一下Calendar.getInstance()
返回的这个实现类, 它在实现或重写Calendar中的方法之外还拥有自己的一些方法
What Is Gregorian Calendar?
(摘自百度百科)
格里高利历是公历的标准名称,是一种源自于西方社会的历法。它先由意大利医生、天文学家、哲学家、年代学家阿洛伊修斯·里利乌斯(Aloysius Lilius,约1519-1576)与克拉乌(Christophorus Clavius)等学者在儒略历的基础上加以改革,后由教皇格里高利十三世于1582年颁布。而公元即“公历纪元”,又称“西元”。
GregorianCalendar Is NOT Only Gregorian Calendar
October 15, 1582, 是格教皇宣布改历的日子. 在这个类中, 该时间点之后为我们现在用的公历, 而该时间点前遵守"儒略历(Julian Calendar)"规则, 据说是凯撒(Julia Ceasar)在其统治时期颁布并使用的历法
GregorianCalendar的构造函数
GregorianCalendar() //当前时间
GregorianCalendar(int year, int month, int dayOfMonth)
GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute)
GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay, int minute,
int second)
GregorianCalendar(Locale)
GregorianCalendar(TimeZone)
GregorianCalendar(TimeZone, Locale)
GregorianCalendar新增的常量和方法
int AD = 0 //公元后(Anno Domini)
int BC = 1 //公元前
Date gerGregorianChange() //返回October 15, 1582, 即教皇宣布改历的日子
//也可以手动设置, 通常设置为最大或最小值, 分别表示仅使用儒略历/仅使用格里高利历
void setGregorianChange(Date)
boolean isLeapYear(int) //判断是不是闰年, 公元前的年份要+1, 即公元前1年为0, 以此类推
ZonedDateTime toZonedDateTime() //*java8的新类, 之后(大概)会提到
为了理解明白这个类还学了一堆历史知识...
网友评论