Java 操作日期/时间,往往会涉及到Calendar,Date,DateFormat这些类。

最近决定把这些内容系统的整理一下,这样以后使用的时候,会更得心应手。本章的内容是主要讲解“Java时间框架”以及“类Calendar”。

在学习Calendar类时,我们先对它有个整体认识,心中建立一个框架,然后再通过示例学习如何使用它。


Java 时间架构图

Java 的Calendar, Date和DateFormat的关系图如下:

说明

(01) milliseconds 表示毫秒。

milliseconds = “实际时间” - “1970-01-01 00:00:00”。Calendar 和 Date依赖于 milliseconds,从而表示时间。

(02) Calendar表示日期/时间。

它是一个抽象类,依赖于milliseconds。GregorianCalendar是Calendar的子类,通常我们通过Calendar.getInstance() 获取Calendar实例时,实际上返回的是 GregorianCalendar 对象。

Calendar和Locale关联,而Locale代表区域;Locale的值不同时,Calendar的日期/时间也不同。

Calendar和TimeZone关联,而TimeZone代表时区;不同的时区,Calendar的日期/时间也不同。

(03) Date 表示日期/时间。

它也依赖于 milliseconds实现。

       在 JDK 1.1 之前,通常是通过Data操作“年月日时分秒”。不过,由于Date的相关 API 不易于实现国际化。从 JDK 1.1 开始,应该使用 Calendar 类来操作“年月日时分秒”,同时可以通过 DateFormat 类来格式化和解析日期字符串。Date 中的相应方法已废弃。

(04) DateFormat是格式化/解析“日期/时间”的工具类。

它是Date的格式化工具,它能帮助我们格式化Date,进而将Date转换成我们想要的String字符串供我们使用。

它是一个抽象类。通常,我们通过getInstance(), getDateInstance()和getDateTimeInstance() 等获取DateFormat实例时;实际上是返回的SimpleDateFormat对象。


Calendar 介绍 

Calendar 定义

  1. public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {}

Calendar 是一个抽象类。

它的实现,采用了设计模式中的工厂方法。表现在:当我们获取Calendar实例时,Calendar会根据传入的参数来返回相应的Calendar对象。获取Calendar实例,有以下两种方式:
1) 当我们通过 Calendar.getInstance() 获取日历时,默认的是返回的一个GregorianCalendar对象。
    GregorianCalendar是Calendar的一个实现类,它提供了世界上大多数国家/地区使用的标准日历系统。
2) 当我们通过 Calendar.getInstance(TimeZone timezone, Locale locale) Calendar.getInstance(TimeZone timezone)Calendar.getInstance(Locale locale)获取日历时,是返回“对应时区(zone) 或 地区(local)等所使用的日历”。
    例如,若是日本,则返回JapaneseImperialCalendar对象。

参考如下代码

  1. public static Calendar getInstance()
  2. {
  3. // 调用createCalendar()创建日历
  4. Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault());
  5. cal.sharedZone = true;
  6. return cal;
  7. }
  8.  
  9. public static Calendar getInstance(TimeZone zone)
  10. {
  11. // 调用createCalendar()创建日历
  12. return createCalendar(zone, Locale.getDefault());
  13. }
  14.  
  15. public static Calendar getInstance(Locale aLocale) {
  16. // 调用createCalendar()创建日历
  17. Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
  18. cal.sharedZone = true;
  19. return cal;
  20. }
  21.  
  22. public static Calendar getInstance(TimeZone zone,
  23. Locale aLocale)
  24. {
  25. // 调用createCalendar()创建日历
  26. return createCalendar(zone, aLocale);
  27. }
  28.  
  29. private static Calendar createCalendar(TimeZone zone,
  30. Locale aLocale)
  31. {
  32. // (01) 若地区是“th”,则返回BuddhistCalendar对象
  33. // (02) 若地区是“JP”,则返回JapaneseImperialCalendar对象
  34. if ("th".equals(aLocale.getLanguage())
  35. && ("TH".equals(aLocale.getCountry()))) {
  36. return new sun.util.BuddhistCalendar(zone, aLocale);
  37. } else if ("JP".equals(aLocale.getVariant())
  38. && "JP".equals(aLocale.getCountry())
  39. && "ja".equals(aLocale.getLanguage())) {
  40. return new JapaneseImperialCalendar(zone, aLocale);
  41. }
  42.  
  43. // (03) 否则,返回GregorianCalendar对象
  44. return new GregorianCalendar(zone, aLocale);
  45. }

当我们获取Calendar实例之后,就可以通过Calendar提供的一些列方法来操作日历。


Calendar 原理和思想

我们使用Calendar,无非是操作Calendar的“年、月、日、星期、时、分、秒”这些字段。下面,我们对这些字段的的来源、定义以及计算方法进行学习。

1. Calendar 各个字段值的来源

我们使用Calendar,无非是使用“年、月、日、星期、时、分、秒”等信息。那么它是如何做到的呢?
本质上,Calendar就是保存了一个时间。如下定义:

  1. // time 是当前时间,单位是毫秒。
  2. // 它是当前时间距离“January 1, 1970, 0:00:00 GMT”的差值。
  3. protected long time;

Calendar就是根据 time 计算出 “Calendar的年、月、日、星期、时、分、秒”等等信息。

2. Calendar 各个字段的定义和初始化

Calendar 的“年、月、日、星期、时、分、秒”这些信息,一共是17个字段
我们使用Calendar,无非是就是使用这17个字段。它们的定义如下:
(字段0) public final static int ERA = 0;
说明:纪元。
取值:只能为0 或 1。0表示BC(“before Christ”,即公元前),1表示AD(拉丁语“Anno Domini”,即公元)。

(字段1) public final static int YEAR = 1;
说明:年。

(字段2) public final static int MONTH = 2;
说明:月
取值:可以为,JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER, UNDECIMBER。
         其中第一个月是 JANUARY,它为 0。

(字段3) public final static int WEEK_OF_YEAR = 3;
说明:当前日期在本年中对应第几个星期。一年中第一个星期的值为 1。

(字段4) public final static int WEEK_OF_MONTH = 4;
说明:当前日期在本月中对应第几个星期。一个月中第一个星期的值为 1。

(字段5) public final static int DATE = 5;
说明:日。一个月中第一天的值为 1。

(字段5) public final static int DAY_OF_MONTH = 5;
说明:同“DATE”,表示“日”。

(字段6) public final static int DAY_OF_YEAR = 6;
说明:当前日期在本年中对应第几天。一年中第一天的值为 1。

(字段7) public final static int DAY_OF_WEEK = 7;
说明:星期几。
取值:可以为,SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY 和 SATURDAY。
         其中,SUNDAY为1,MONDAY为2,依次类推。

(字段8) public final static int DAY_OF_WEEK_IN_MONTH = 8;
说明:当前月中的第几个星期。
取值:DAY_OF_MONTH 1 到 7 总是对应于 DAY_OF_WEEK_IN_MONTH 1;8 到 14 总是对应于 DAY_OF_WEEK_IN_MONTH 2,依此类推。

(字段9) public final static int AM_PM = 9;
说明:上午 还是 下午
取值:可以是AM 或 PM。AM为0,表示上午;PM为1,表示下午。

(字段10) public final static int HOUR = 10;
说明:指示一天中的第几小时。
         HOUR 用于 12 小时制时钟 (0 - 11)。中午和午夜用 0 表示,不用 12 表示。

(字段11) public final static int HOUR_OF_DAY = 11;
说明:指示一天中的第几小时。
         HOUR_OF_DAY 用于 24 小时制时钟。例如,在 10:04:15.250 PM 这一时刻,HOUR_OF_DAY 为 22。

(字段12) public final static int MINUTE = 12;
说明:一小时中的第几分钟。
例如,在 10:04:15.250 PM这一时刻,MINUTE 为 4。

(字段13) public final static int SECOND = 13;
说明:一分钟中的第几秒。
例如,在 10:04:15.250 PM 这一时刻,SECOND 为 15。

(字段14) public final static int MILLISECOND = 14;
说明:一秒中的第几毫秒。
例如,在 10:04:15.250 PM 这一时刻,MILLISECOND 为 250。

(字段15) public final static int ZONE_OFFSET = 15;
说明:毫秒为单位指示距 GMT 的大致偏移量。

(字段16) public final static int DST_OFFSET = 16;
说明:毫秒为单位指示夏令时的偏移量。

public final static int FIELD_COUNT = 17;

这17个字段是保存在int数组中。定义如下:

  1. // 保存这17个字段的数组
  2. protected int fields[];
  3. // 数组的定义函数
  4. protected Calendar(TimeZone zone, Locale aLocale)
  5. {
  6. // 初始化“fields数组”
  7. fields = new int[FIELD_COUNT];
  8. isSet = new boolean[FIELD_COUNT];
  9. stamp = new int[FIELD_COUNT];
  10.  
  11. this.zone = zone;
  12. setWeekCountData(aLocale);
  13. }

protected Calendar(TimeZone zone, Locale aLocale) 这是Calendar的构造函数。它会被它的子类的构造函数调用到,从而新建“保存Calendar的17个字段数据”的数组

3. Calendar 各个字段值的计算

下面以get(int field)为例,简要的说明Calendar的17个字段的计算和操作。
get(int field)是获取“field”字段的值。它的定义如下:

  1. public int get(int field) {
  2. // 计算各个字段的值
  3. complete();
  4. // 返回field字段的值
  5. return internalGet(field);
  6. }

说明
get(int field)的代码很简单。先通过 complete() 计算各个字段的值然后在通过 internalGet(field) 返回“field字段的值”

complete() 的作用就是计算Calendar各个字段的值。它定义在Calendar.java中,代码如下:

  1. protected void complete()
  2. {
  3. if (!isTimeSet)
  4. updateTime();
  5. if (!areFieldsSet || !areAllFieldsSet) {
  6. computeFields(); // fills in unset fields
  7. areAllFieldsSet = areFieldsSet = true;
  8. }
  9. }
  10. private void updateTime() {
  11. computeTime();
  12. isTimeSet = true;
  13. }

updateTime() 调用到的 computeTime() 定义在 Calendar.java的实现类中。下面,我列出GregorianCalendar.java中computeTime()的实现:

  1. protected void computeTime() {
  2. // In non-lenient mode, perform brief checking of calendar
  3. // fields which have been set externally. Through this
  4. // checking, the field values are stored in originalFields[]
  5. // to see if any of them are normalized later.
  6. if (!isLenient()) {
  7. if (originalFields == null) {
  8. originalFields = new int[FIELD_COUNT];
  9. }
  10. for (int field = 0; field < FIELD_COUNT; field++) {
  11. int value = internalGet(field);
  12. if (isExternallySet(field)) {
  13. // Quick validation for any out of range values
  14. if (value < getMinimum(field) || value > getMaximum(field)) {
  15. throw new IllegalArgumentException(getFieldName(field));
  16. }
  17. }
  18. originalFields[field] = value;
  19. }
  20. }
  21.  
  22. // Let the super class determine which calendar fields to be
  23. // used to calculate the time.
  24. int fieldMask = selectFields();
  25.  
  26. // The year defaults to the epoch start. We don't check
  27. // fieldMask for YEAR because YEAR is a mandatory field to
  28. // determine the date.
  29. int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
  30.  
  31. int era = internalGetEra();
  32. if (era == BCE) {
  33. year = 1 - year;
  34. } else if (era != CE) {
  35. // Even in lenient mode we disallow ERA values other than CE & BCE.
  36. // (The same normalization rule as add()/roll() could be
  37. // applied here in lenient mode. But this checking is kept
  38. // unchanged for compatibility as of 1.5.)
  39. throw new IllegalArgumentException("Invalid era");
  40. }
  41.  
  42. // If year is 0 or negative, we need to set the ERA value later.
  43. if (year <= 0 && !isSet(ERA)) {
  44. fieldMask |= ERA_MASK;
  45. setFieldsComputed(ERA_MASK);
  46. }
  47.  
  48. // Calculate the time of day. We rely on the convention that
  49. // an UNSET field has 0.
  50. long timeOfDay = 0;
  51. if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
  52. timeOfDay += (long) internalGet(HOUR_OF_DAY);
  53. } else {
  54. timeOfDay += internalGet(HOUR);
  55. // The default value of AM_PM is 0 which designates AM.
  56. if (isFieldSet(fieldMask, AM_PM)) {
  57. timeOfDay += 12 * internalGet(AM_PM);
  58. }
  59. }
  60. timeOfDay *= 60;
  61. timeOfDay += internalGet(MINUTE);
  62. timeOfDay *= 60;
  63. timeOfDay += internalGet(SECOND);
  64. timeOfDay *= 1000;
  65. timeOfDay += internalGet(MILLISECOND);
  66.  
  67. // Convert the time of day to the number of days and the
  68. // millisecond offset from midnight.
  69. long fixedDate = timeOfDay / ONE_DAY;
  70. timeOfDay %= ONE_DAY;
  71. while (timeOfDay < 0) {
  72. timeOfDay += ONE_DAY;
  73. --fixedDate;
  74. }
  75.  
  76. // Calculate the fixed date since January 1, 1 (Gregorian).
  77. calculateFixedDate: {
  78. long gfd, jfd;
  79. if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
  80. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  81. if (gfd >= gregorianCutoverDate) {
  82. fixedDate = gfd;
  83. break calculateFixedDate;
  84. }
  85. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  86. } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
  87. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  88. if (jfd < gregorianCutoverDate) {
  89. fixedDate = jfd;
  90. break calculateFixedDate;
  91. }
  92. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  93. } else {
  94. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  95. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  96. }
  97. // Now we have to determine which calendar date it is.
  98. if (gfd >= gregorianCutoverDate) {
  99. if (jfd >= gregorianCutoverDate) {
  100. fixedDate = gfd;
  101. } else {
  102. // The date is in an "overlapping" period. No way
  103. // to disambiguate it. Determine it using the
  104. // previous date calculation.
  105. if (calsys == gcal || calsys == null) {
  106. fixedDate = gfd;
  107. } else {
  108. fixedDate = jfd;
  109. }
  110. }
  111. } else {
  112. if (jfd < gregorianCutoverDate) {
  113. fixedDate = jfd;
  114. } else {
  115. // The date is in a "missing" period.
  116. if (!isLenient()) {
  117. throw new IllegalArgumentException("the specified date doesn't exist");
  118. }
  119. // Take the Julian date for compatibility, which
  120. // will produce a Gregorian date.
  121. fixedDate = jfd;
  122. }
  123. }
  124. }
  125.  
  126. // millis represents local wall-clock time in milliseconds.
  127. long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
  128.  
  129. // Compute the time zone offset and DST offset. There are two potential
  130. // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
  131. // for discussion purposes here.
  132. // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
  133. // can be in standard or in DST depending. However, 2:00 am is an invalid
  134. // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
  135. // We assume standard time.
  136. // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
  137. // can be in standard or DST. Both are valid representations (the rep
  138. // jumps from 1:59:59 DST to 1:00:00 Std).
  139. // Again, we assume standard time.
  140. // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  141. // or DST_OFFSET fields; then we use those fields.
  142. TimeZone zone = getZone();
  143. if (zoneOffsets == null) {
  144. zoneOffsets = new int[2];
  145. }
  146. int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
  147. if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
  148. if (zone instanceof ZoneInfo) {
  149. ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
  150. } else {
  151. int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
  152. internalGet(ZONE_OFFSET) : zone.getRawOffset();
  153. zone.getOffsets(millis - gmtOffset, zoneOffsets);
  154. }
  155. }
  156. if (tzMask != 0) {
  157. if (isFieldSet(tzMask, ZONE_OFFSET)) {
  158. zoneOffsets[0] = internalGet(ZONE_OFFSET);
  159. }
  160. if (isFieldSet(tzMask, DST_OFFSET)) {
  161. zoneOffsets[1] = internalGet(DST_OFFSET);
  162. }
  163. }
  164.  
  165. // Adjust the time zone offset values to get the UTC time.
  166. millis -= zoneOffsets[0] + zoneOffsets[1];
  167.  
  168. // Set this calendar's time in milliseconds
  169. time = millis;
  170.  
  171. int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
  172.  
  173. if (!isLenient()) {
  174. for (int field = 0; field < FIELD_COUNT; field++) {
  175. if (!isExternallySet(field)) {
  176. continue;
  177. }
  178. if (originalFields[field] != internalGet(field)) {
  179. // Restore the original field values
  180. System.arraycopy(originalFields, 0, fields, 0, fields.length);
  181. throw new IllegalArgumentException(getFieldName(field));
  182. }
  183. }
  184. }
  185. setFieldsNormalized(mask);
  186. }

下面,我们看看internalGet(field)的定义。如下:

  1. protected final int internalGet(int field) {
  2. return fields[field];
  3. }

从中,我们就看出,get(int field) 最终是通过 internalGet(int field)来返回值的。
而 internalGet(int field) ,实际上返回的是field数组中的第field个元素。这就正好和Calendar的17个元素所对应了!

总之,我们需要了解的就是:Calendar就是以一个time(毫秒)为基数,而计算出“年月日时分秒”等,从而方便我们对“年月日时分秒”等进行操作。下面,介绍以下Calendar提供的相关操作函数。


Calendar函数接口

1. Calendar的17个字段的公共接口

Calendar的这17个字段,都支持下面的公共函数接口。
这些公共接口的使用示例,请参考CalendarTest.java 示例中的 testAllCalendarSections() 函数。

1) getMaximum(int field)

作用:获取“字段的最大值”。注意“对比它和 getActualMaximum() 的区别”。
示例:以“MONTH”字段来说。使用方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 获取MONTH的最大值
  4. int max = cal.getMaximum(Calendar.MONTH);

若要获取其它字段的最大值,只需要将示例中的MONTH相应的替换成其它字段名即可。

2) getActualMaximum(int field)

作用:获取“当前日期下,该字段的最大值”。
示例:以“MONTH”字段来说。使用方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 获取当前MONTH的最大值
  4. int max = cal.getActualMaximum(Calendar.MONTH);

若要获取其它字段的最大值,只需要将示例中的MONTH相应的替换成其它字段名即可。

注意对比getActualMaximum() 和 getMaximum() 的区别。参考下面的对比示例,

(01) getMaximum() 获取的“字段最大值”,是指在综合所有的日期,在所有这些日期中得出的“字段最大值”
      例如,getMaximum(Calendar.DATE)的目的是“获取‘日的最大值’”。综合所有的日期,得出一个月最多有31天。因此,getMaximum(Calendar.DATE)的返回值是“31”!
(02) getActualMaximum() 获取的“当前日期时,该字段的最大值”。
     例如,当日期为2013-09-01时,getActualMaximum(Calendar.DATE)是获取“日的最大值”是“30”。当前日期是9月份,而9月只有30天。因此,getActualMaximum(Calendar.DATE)的返回值是“30”!

3) getMinimum(int field)

作用:获取“字段的最小值”。注意“对比它和 getActualMinimum() 的区别”。
示例:以“MONTH”字段来说。使用方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 获取MONTH的最小值
  4. int min = cal.getMinimum(Calendar.MONTH);

若要获取其它字段的最小值,只需要将示例中的MONTH相应的替换成其它字段名即可。

4) getActualMinimum(int field)

作用:获取“当前日期下,该字段的最小值”。
示例:以“MONTH”字段来说。使用方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 获取MONTH的最小值
  4. int min = cal.getMinimum(Calendar.MONTH);

若要获取其它字段的最小值,只需要将示例中的MONTH相应的替换成其它字段名即可。

注意:在Java默认的Calendar中,虽然 getMinimum() 和 getActualMinimum() 的含义不同;但是,它们的返回值是一样的。因为Calendar的默认是返回GregorianCalendar对象,而在GregorianCalendar.java中,getMinimum() 和 getActualMinimum() 返回值一样。

5) get(int field)

作用:获取“字段的当前值”。获取field字段的当前值。
示例:以“MONTH”字段来说。“获取MONTH的当前值”的方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 获取“cal日历”的当前MONTH值
  4. int MONTH = cal.get(Calendar.MONTH);

若要获取其它字段的当前值,只需要将示例中的MONTH相应的替换成其它字段名即可。

6) set(int field, int value)

作用:设置“字段的当前值”。设置field字段的当前值为value
示例:以“MONTH”字段来说。“设置MONTH的当前值”的方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 设置“cal日历”的当前MONTH值为 1988年
  4. cal.set(Calendar.MONTH, 1988);

说明
(01) 1988 是想要设置的MONTH的当前值。这个设置值必须是整数。
(02) 若要设置其它字段的当前值,只需要将示例中的MONTH相应的替换成其它字段名即可。

7) add(int field, int value)

作用:给“字段的当前值”添加值。给field字段的当前值添加value。
示例:以“MONTH”字段来说。方法如下:

  1. // 获取Calendar实例,并设置日期为“2013-09-01”
  2. Calendar cal = Calendar.getInstance();
  3. cal.set(Calendar.YEAR, 2013);
  4. cal.set(Calendar.MONTH, 8);
  5. cal.set(Calendar.DATE, 1);
  6. // 给“cal日历”的当前MONTH值 “添加-10”
  7. cal.add(Calendar.MONTH, -10);

说明
(01) -10 是添加值。
      添加值可以为正数,也可以是负数。
      正数表示将日期增加,负数表示将日期减少。

假设:现在cal的值是“2013-09-01”,现在我们将MONTH字段值增加-10。得到的结果是:“2012-10-01”。
             为什么会这样呢?“2013-09-01”增加-10,也就是将日期向前减少10个月;得到的结果就是“2012-10-01”。
(02) Calendar的17个字段中:除了回滚Calendar.ZONE_OFFSET时,会抛出IllegalArgumentException异常;其它的字段都支持该操作。
(03) 若要设置其它字段的当前值,只需要将示例中的MONTH相应的替换成其它字段名即可。

8) roll(int field, int value)

作用:回滚“字段的当前值”
示例:以“MONTH”字段来说。“回滚MONTH的当前值”的方法为:

  1. // 获取Calendar实例,并设置日期为“2013-09-01”
  2. Calendar cal = Calendar.getInstance();
  3. cal.set(Calendar.YEAR, 2013);
  4. cal.set(Calendar.MONTH, 8);
  5. cal.set(Calendar.DATE, 1);
  6. // 将“cal日历”的当前MONTH值 “向前滚动10”
  7. cal.roll(Calendar.MONTH, -10);

说明
(01) -10 是回滚值。
     当回滚值是负数时,表示将当前字段向前滚;
     当回滚值是正数时,表示将当前字段向后滚。

回滚Calendar中某一字段时,不更改更大的字段!
     这是roll()与add()的根据区别!add()可能会更改更大字段,比如“使用add()修改‘MONTH’字段,可能会引起‘YEAR’字段的改变”;但是roll()不会更改更大的字段,例如“使用roll()修改‘MONTH’字段,不回引起‘YEAR’字段的改变。”

假设:现在cal的值是“2013-09-01”,现在我们将MONTH字段值增加-10。得到的结果是:“2013-10-01”。
             为什么会这样呢?这就是因为“回滚”就是“在最小值和最大值之间来回滚动”。本例中,MONTH是9月,前回滚10,得到的值是10月,但是roll()不会改变“比MONTH”更大的字段,所以YEAR字段不会改变。所以结果是“2013-10-01”。
(02) Calendar的17个字段中:除了回滚Calendar.ZONE_OFFSET时,会抛出IllegalArgumentException异常;其它的字段都支持该操作。
(03) 若要设置其它字段的当前值,只需要将示例中的MONTH相应的替换成其它字段名即可。

9) clear(int field)

作用:清空“字段的当前值”。所谓清空,实际上是将“field”的值设置为0;若field最小值为1,则设置为1。
示例:以“MONTH”字段来说。“清空MONTH”的方法为:

  1. // 获取Calendar实例,并设置日期为“9月”
  2. Calendar cal = Calendar.getInstance();
  3. cal.set(Calendar.MONTH, 9);
  4. // 清空MONTH
  5. cal.clear(Calendar.MONTH);

若要清空其它字段,只需要将示例中的MONTH相应的替换成其它字段名即可。

10) isSet(int field)

作用:判断“字段field”是否被设置。若调用clear()清空之后,则field变为“没有设置状态”。
示例:以“MONTH”字段来说。“判断MONTH是否被设置”的方法为:

  1. // 获取Calendar实例
  2. Calendar cal = Calendar.getInstance();
  3. // 判断MONTH是否被设置
  4. boolean bset = cal.isSet(Calendar.MONTH);

若要判断其它字段,只需要将示例中的MONTH相应的替换成其它字段名即可。

2. Calendar的其它函数

1) 日期比较函数

Calendar的比较函数,主要有以下几个:

  1. // 比较“当前Calendar对象”和“calendar” 的日期、时区等内容是否相等。
  2. boolean equals(Object object)
  3. // 当前Calendar对象 是否 早于calendar
  4. boolean before(Object calendar)
  5. // 当前Calendar对象 是否 晚于calendar
  6. boolean after(Object calendar)
  7. // 比较“当前Calendar对象”和“calendar”。
  8. // 若 早于 “calendar” 则,返回-1
  9. // 若 相等, 则,返回0
  10. // 若 晚于 “calendar” 则,返回1
  11. int compareTo(Calendar anotherCalendar)

这些函数的使用示例,请参考CalendarTest.java示例中的 testComparatorAPIs() 函数。

示例:假设cal1 和 cal2 都是Calendar的两个对象。

  1. // 它们的使用方法如下
  2. boolean isEqual = cal1.equals(cal2);
  3. boolean isBefore = cal1.before(cal2);
  4. boolean isAfter = cal1.after(cal2);
  5. int icompare = cal1.compareTo(cal2);

2) “宽容”函数

  1. // 设置“Calendar的宽容度”
  2. void setLenient(boolean value)
  3. // 获取“Calendar的宽容度”
  4. boolean isLenient()

这些函数的使用示例,请参考CalendarTest.java示例中的 testLenientAPIs() 函数。
说明
Calendar 有两种解释日历字段的模式,即 lenient 和 non-lenient。
(01) 当 Calendar 处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。当 Calendar 重新计算日历字段值,以便由 get() 返回这些值时,所有日历字段都被标准化。
      例如,lenient 模式下的 GregorianCalendar 将 MONTH == JANUARY、DAY_OF_MONTH == 32 解释为 February 1。
(02) 当 Calendar 处于 non-lenient 模式时,如果其日历字段中存在任何不一致性,它都会抛出一个异常。
     例如,GregorianCalendar 总是在 1 与月份的长度之间生成 DAY_OF_MONTH 值。如果已经设置了任何超出范围的字段值,那么在计算时间或日历字段值时,处于 non-lenient 模式下的 GregorianCalendar 会抛出一个异常。
    注意:在(02)步骤中的异常,在使用set()时不会抛出,而需要在使用get()、getTimeInMillis()、getTime()、add() 和 roll() 等函数中才抛出。因为set()只是设置了一个修改标志,而get()等方法才会引起时间的重新计算,此时才会抛出异常!

3) "年月日(时分秒)"、Date、TimeZone、MilliSecond函数

  1. // 设置“年月日”
  2. final void set(int year, int month, int day)
  3. // 设置“年月日时分”
  4. final void set(int year, int month, int day, int hourOfDay, int minute, int second)
  5. // 设置“年月日时分秒”
  6. final void set(int year, int month, int day, int hourOfDay, int minute)
  7. // 获取Calendar对应的日期
  8. final Date getTime()
  9. // 设置Calendar为date
  10. final void setTime(Date date)
  11. // 获取Calendar对应的时区
  12. TimeZone getTimeZone()
  13. // 设置Calendar对应的时区
  14. void setTimeZone(TimeZone timezone)
  15. // 获取Calendar对应的milliscondes值,就是“Calendar当前日期”距离“1970-01-01 0:00:00 GMT”的毫秒数
  16. long getTimeInMillis()
  17. // 设置Calendar对应的milliscondes值
  18. void setTimeInMillis(long milliseconds)

这些函数的使用示例,请参考CalendarTest.java示例中的 testTimeAPIs() 函数。

4) 其它操作

  1. // 克隆Calendar
  2. Object clone()
  3. // 获取“每周的第一天是星期几”。例如,在美国,这一天是 SUNDAY,而在法国,这一天是 MONDAY。
  4. int getFirstDayOfWeek()
  5. // 设置“每周的第一天是星期几”。例如,在美国,这一天是 SUNDAY,而在法国,这一天是 MONDAY。
  6. void setFirstDayOfWeek(int value)
  7. // 获取一年中第一个星期所需的最少天数,例如,如果定义第一个星期包含一年第一个月的第一天,则此方法将返回 1。如果最少天数必须是一整个星期,则此方法将返回 7。
  8. int getMinimalDaysInFirstWeek()
  9. // 设置一年中第一个星期所需的最少天数,例如,如果定义第一个星期包含一年第一个月的第一天,则使用值 1 调用此方法。如果最少天数必须是一整个星期,则使用值 7 调用此方法。
  10. void setMinimalDaysInFirstWeek(int value)

这些函数的使用示例,请参考CalendarTest.java示例中的 testOtherAPIs() 函数。


Calendar 示例 

下面,我们通过示例学习使用Calendar的API。CalendarTest.java的源码如下:

  1. import java.util.Date;
  2. import java.util.Calendar;
  3. import java.util.TimeZone;
  4. import java.util.Random;
  5.  
  6. /**
  7. * Calendar的API测试程序
  8. *
  9. * @author skywang
  10. * @email kuiwu-wang@163.com
  11. */
  12. public class CalendarTest {
  13.  
  14. public static void main(String[] args) {
  15.  
  16. // 测试Calendar的“17个字段的公共函数接口”
  17. testAllCalendarSections() ;
  18.  
  19. // 测试Calendar的“比较接口”
  20. testComparatorAPIs() ;
  21.  
  22. // 测试Calendar的“比较接口”
  23. testLenientAPIs() ;
  24.  
  25. // 测试Calendar的Date、TimeZone、MilliSecond等相关函数
  26. testTimeAPIs() ;
  27.  
  28. // 测试Calendar的clone(),getFirstDayOfWeek()等接口
  29. testOtherAPIs() ;
  30.  
  31. }
  32.  
  33. /**
  34. * 测试“Calendar的字段”
  35. *
  36. * @param cal -- Calendar对象
  37. * @param field -- 要测试的“Calendar字段”。可以为以下值:
  38. * Calendar.YEAR, Calendar.MONTH, Calendar.DATE, ... 等等
  39. * @param title -- 标题
  40. * @author skywang (kuiwu-wang@163.com)
  41. */
  42. private static void testSection(Calendar cal, int field, String title) {
  43. final Random random = new Random();
  44. final Date date = cal.getTime();
  45.  
  46. final int min = cal.getMinimum(field); // 获取"字段最小值"
  47. final int max = cal.getMaximum(field); // 获取“字段最大值”
  48.  
  49. final int actualMin = cal.getActualMinimum(field); // 获取"当前日期下,该字段最小值"
  50. final int actualMax = cal.getActualMaximum(field); // 获取“当前日期下,该字段的最大值”
  51.  
  52. // 获取“字段的当前值”
  53. final int ori = cal.get(field);
  54.  
  55. // 设置“字段的当前值”, 并获取“设置之后的值”
  56. final int r1 = random.nextInt(max);
  57. cal.set(field, r1);
  58. final int set = cal.get(field);
  59. try {
  60. // 回滚“字段的当前值”:在“字段最小值”和“字段最大值”之间回滚。
  61. // “回滚值”可以为正,也可以为负。
  62. cal.roll(field, -max);
  63. } catch (IllegalArgumentException e) {
  64. // 当field == Calendar.ZONE_OFFSET时,会抛出该异常!
  65. e.printStackTrace();
  66. }
  67. final int roll = cal.get(field);
  68.  
  69. // 获取一个随机值
  70. final int sign = ( random.nextInt(2) == 1) ? 1 : -1;
  71. final int r2 = sign * random.nextInt(max);
  72. try {
  73. // 增加“字段的当前值” ,并获取“新的当前字段值”
  74. // add的“参数值”可以为正,也可以为负。
  75. cal.add(field, r2);
  76. } catch (IllegalArgumentException e) {
  77. // 当field == Calendar.ZONE_OFFSET时,会抛出该异常!
  78. e.printStackTrace();
  79. }
  80. final int add = cal.get(field);
  81.  
  82. // 打印字段信息
  83. System.out.printf("%s:\n\trange is [%d - %d] actualRange is [%d - %d]. original=%d, set(%d)=%d, roll(%d)=%d, add(%d)=%d\n",
  84. title, min, max, actualMin, actualMax, ori, r1, set, -max, roll, r2, add);
  85. }
  86.  
  87. /**
  88. * 测试Calendar的“17个字段的公共函数接口”
  89. *
  90. * @author skywang (kuiwu-wang@163.com)
  91. */
  92. private static void testAllCalendarSections() {
  93. // 00. ERA 字段
  94. testSection(Calendar.getInstance(), Calendar.ERA, "Calendar.ERA");
  95. // 01. YEAR 字段
  96. testSection(Calendar.getInstance(), Calendar.YEAR, "Calendar.YEAR");
  97. // 02. MONTH 字段
  98. testSection(Calendar.getInstance(), Calendar.MONTH, "Calendar.MONTH");
  99. // 03. WEEK_OF_YEAR 字段
  100. testSection(Calendar.getInstance(), Calendar.WEEK_OF_YEAR, "Calendar.WEEK_OF_YEAR");
  101. // 04. WEEK_OF_MONTH 字段
  102. testSection(Calendar.getInstance(), Calendar.WEEK_OF_MONTH, "Calendar.WEEK_OF_MONTH");
  103. // 05. DATE 字段
  104. testSection(Calendar.getInstance(), Calendar.DATE, "Calendar.DATE");
  105. // 06. DAY_OF_MONTH 字段
  106. testSection(Calendar.getInstance(), Calendar.DAY_OF_MONTH, "Calendar.DAY_OF_MONTH");
  107. // 07. DAY_OF_YEAR 字段
  108. testSection(Calendar.getInstance(), Calendar.DAY_OF_YEAR, "Calendar.DAY_OF_YEAR");
  109. // 08. DAY_OF_WEEK 字段
  110. testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK, "Calendar.DAY_OF_WEEK");
  111. // 09. DAY_OF_WEEK_IN_MONTH 字段
  112. testSection(Calendar.getInstance(), Calendar.DAY_OF_WEEK_IN_MONTH, "Calendar.DAY_OF_WEEK_IN_MONTH");
  113. // 10. AM_PM 字段
  114. testSection(Calendar.getInstance(), Calendar.AM_PM, "Calendar.AM_PM");
  115. // 11. HOUR 字段
  116. testSection(Calendar.getInstance(), Calendar.HOUR, "Calendar.HOUR");
  117. // 12. HOUR_OF_DAY 字段
  118. testSection(Calendar.getInstance(), Calendar.HOUR_OF_DAY, "Calendar.HOUR_OF_DAY");
  119. // 13. MINUTE 字段
  120. testSection(Calendar.getInstance(), Calendar.MINUTE, "Calendar.MINUTE");
  121. // 14. SECOND 字段
  122. testSection(Calendar.getInstance(), Calendar.SECOND, "Calendar.SECOND");
  123. // 15. MILLISECOND 字段
  124. testSection(Calendar.getInstance(), Calendar.MILLISECOND, "Calendar.MILLISECOND");
  125. // 16. ZONE_OFFSET 字段
  126. testSection(Calendar.getInstance(), Calendar.ZONE_OFFSET, "Calendar.ZONE_OFFSET");
  127. }
  128.  
  129. /**
  130. * 测试Calendar的“比较接口”
  131. *
  132. * @author skywang (kuiwu-wang@163.com)
  133. */
  134. private static void testComparatorAPIs() {
  135. // 新建cal1 ,且时间为1988年
  136. Calendar cal1 = Calendar.getInstance();
  137. cal1.set(Calendar.YEAR, 1988);
  138. // 新建cal2 ,且时间为2000年
  139. Calendar cal2 = Calendar.getInstance();
  140. cal2.set(Calendar.YEAR, 2000);
  141. // 新建cal3, 为cal1的克隆对象
  142. Calendar cal3 = (Calendar)cal1.clone();
  143.  
  144. // equals 判断 cal1和cal2的“时间、时区等”内容是否相等
  145. boolean isEqual12 = cal1.equals(cal2);
  146. // equals 判断 cal1和cal3的“时间、时区等”内容是否相等
  147. boolean isEqual13 = cal1.equals(cal3);
  148. // cal1是否比cal2早
  149. boolean isBefore = cal1.before(cal2);
  150. // cal1是否比cal2晚
  151. boolean isAfter = cal1.after(cal2);
  152. // 比较cal1和cal2
  153. // (01) 若cal1 早于 cal2,返回-1
  154. // (02) 若cal1 等于 cal2,返回0
  155. // (03) 若cal1 晚于 cal2,返回1
  156. int icompare = cal1.compareTo(cal2);
  157.  
  158. System.out.printf("\ntestComparatorAPIs: isEuqal12=%s, isEqual13=%s, isBefore=%s, isAfter=%s, icompare=%s\n",
  159. isEqual12, isEqual13, isBefore, isAfter, icompare);
  160. }
  161.  
  162. /**
  163. * 测试Calendar的“比较接口”
  164. *
  165. * @author skywang (kuiwu-wang@163.com)
  166. */
  167. private static void testLenientAPIs() {
  168. Calendar cal = Calendar.getInstance();
  169.  
  170. // 获取默认的“宽容度”。返回true
  171. boolean oriLenient = cal.isLenient();
  172. // MONTH值只能是“0-11”,这里越界。但是由于当前cal是宽容的,所以不会抛出异常
  173. cal.set(Calendar.MONTH, 50);
  174.  
  175. // 设置“宽容度”为false。
  176. cal.setLenient(false);
  177. // 获取设置后的“宽容度”
  178. boolean curLenient = cal.isLenient();
  179. try {
  180. // MONTH值只能是“0-11”,这里越界。而且当前cal是不宽容的,所以会产生异常。
  181. // 但是,异常到下次计算日期时才会抛出。即,set()中不回抛出异常,而要等到get()中才会抛出异常
  182. cal.set(Calendar.MONTH, 50);
  183. // 此时,对cal进行读取。读取会导致重新计算cal的值,所以此时抛出异常!
  184. int m2 = cal.get(Calendar.MONTH);
  185. } catch (IllegalArgumentException e) {
  186. e.printStackTrace();
  187. }
  188.  
  189. System.out.printf("\ntestLenientAPIs: oriLenient=%s, curLenient=%s\n",
  190. oriLenient, curLenient);
  191. }
  192.  
  193. /**
  194. * 测试Calendar的Date、TimeZone、MilliSecond等相关函数
  195. *
  196. * @author skywang (kuiwu-wang@163.com)
  197. */
  198. private static void testTimeAPIs() {
  199. Calendar cal = Calendar.getInstance();
  200.  
  201. // 设置cal的时区为“GMT+8”
  202. cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
  203. // 获取当前的cal时区
  204. TimeZone timezone = cal.getTimeZone();
  205.  
  206. // 设置 milliseconds
  207. cal.setTimeInMillis(1279419645742l);
  208. // 获取 milliseconds
  209. long millis = cal.getTimeInMillis();
  210. // 设置 milliseconds之后,时间也改变了。
  211. // 获取cal对应的日期
  212. Date date = cal.getTime();
  213.  
  214. // 设置时间为“1988-08-08”
  215. cal.set(1988, 08, 08);
  216. // 设置时间为“1999-09-09 09:09”
  217. cal.set(1999, 09, 09, 9, 9);
  218. // 设置时间为“2000-10-10 10:10:10”
  219. cal.set(2000, 10, 10, 10, 10, 10);
  220.  
  221. System.out.printf("\ntestTimeAPIs: date=%s, timezone=%s, millis=%s\n",
  222. date, timezone, millis);
  223. }
  224.  
  225. /**
  226. * 测试Calendar的clone(),getFirstDayOfWeek()等接口
  227. *
  228. * @author skywang (kuiwu-wang@163.com)
  229. */
  230. private static void testOtherAPIs() {
  231. Calendar cal = Calendar.getInstance();
  232. // 克隆cal
  233. Calendar clone = (Calendar)cal.clone();
  234.  
  235. // 设置 为 2013-01-10。
  236. // 注:2013-01-01 为“星期二”,2013-01-06为“星期天”,
  237. clone.set(Calendar.YEAR, 2013);
  238. clone.set(Calendar.MONTH, 0);
  239. clone.set(Calendar.DATE, 10);
  240. // 设置“本年的第一个星期最少包含1天”。
  241. // 则2013-01-10属于第2个星期
  242. clone.setMinimalDaysInFirstWeek(1);
  243. int m1 = clone.getMinimalDaysInFirstWeek();
  244. int index1 = clone.get(Calendar.WEEK_OF_YEAR);
  245.  
  246. // 设置“本年的第一个星期最少包含7天”。
  247. // 则2013-01-10属于第1个星期
  248. clone.setMinimalDaysInFirstWeek(7);
  249. int m2 = clone.getMinimalDaysInFirstWeek();
  250. int index2 = clone.get(Calendar.WEEK_OF_YEAR);
  251.  
  252. // 设置“每周的第一天是星期几”。
  253. clone.setFirstDayOfWeek(Calendar.WEDNESDAY);
  254. // 获取“每周的第一天是星期几”。
  255. int firstdayOfWeek = clone.getFirstDayOfWeek();
  256.  
  257. System.out.printf("\ntestOtherAPIs: firstdayOfWeek=%s, [minimalDay, WeekOfYear]={(%s, %s), (%s, %s)} %s\n",
  258. firstdayOfWeek, m1, index1, m2, index2, clone.getTime());
  259. }
  260. }

OK。今天先到此为止!

明天再继续总结。


更多内容

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(3) Date

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(4) DateFormat

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(5) SimpleDateFormat

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(6) Locale

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(7) TimeZone

Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar的更多相关文章

  1. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口

    本章主要是收藏一些常用的类和接口,包括:万年历(农历.阳历节日.阴历节日).自定义的Calendar接口. 万年历 源码如下(ChineseCalendar.java): package com.vi ...

  2. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(3) Date

    本章主要介绍Date类,并通过示例学习如何使用它.最后,讲解一下UTC.GMT和时区的关系. Date 介绍 Date 定义 public class Date implements java.io. ...

  3. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(4) DateFormat

    本章主要介绍DateFormat. DateFormat 介绍 DateFormat 的作用是 格式化并解析“日期/时间”.实际上,它是Date的格式化工具,它能帮助我们格式化Date,进而将Date ...

  4. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(5) SimpleDateFormat

    本章介绍SimpleDateFormat. SimpleDateFormat 介绍 SimpleDateFormat 是一个格式化Date 以及 解析日期字符串 的工具.它的最常用途是,能够按照指定的 ...

  5. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(6) Locale

    本章介绍Locale. 1 Locale 介绍 Locale 表示地区.每一个Locale对象都代表了一个特定的地理.政治和文化地区. 在操作 Date, Calendar等表示日期/时间的对象时,经 ...

  6. Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(7) TimeZone

    本章介绍TimeZone. TimeZone 简介 TimeZone 表示时区偏移量,也可以计算夏令时.在操作 Date, Calendar等表示日期/时间的对象时,经常会用到TimeZone:因为不 ...

  7. Java api 入门教程 之 JAVA的Date类与Calendar类

    在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理. 一.这里简单介绍一下Date类的使 ...

  8. JAVA的Date类与Calendar类【转】

    Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Date ...

  9. java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp区别和总结

    在web开发中,避免不了对日期的操作,就几种常见的日期操作做个总结(部分参考网络,在此表示感谢): java.util.Date.java.sql.Date.java.sql.Time.java.sq ...

随机推荐

  1. 初步认识mitmproxy(一)

    在windows机器上,经常用的最多的是fiddler工具,很强大,图形化界面,使用方便.简单:在mac上,Charles 类似fiddler工具,同样是易于操作的图形化界面,同样都是通过代理的方式实 ...

  2. 搜索引擎ElasticSearchV5.4.2系列一之ES介绍

    相关博文: 搜索引擎ElasticSearchV5.4.2系列一之ES介绍 搜索引擎ElasticSearchV5.4.2系列二之ElasticSearchV5.4.2+kibanaV5.4.2+x- ...

  3. async异步注解和aspect切面注解等注解的原理

    在我们使用spring框架的过程中,在很多时候我们会使用@async注解来异步执行某一些方法,提高系统的执行效率.今天我们来探讨下spring是如何完成这个功能的. 1.spring 在扫描bean的 ...

  4. window BIOS设置硬盘启动模式

      bios如何设置硬盘启动模式?BIOSD硬盘模试主是要针对IDE接口的硬盘和SATA接口的硬盘来设置的.以前的主板只支持一种类型.现在的智能笔记本主板支持:IDE Mode.AHCI Mode.下 ...

  5. Cap+Exceptionless实现日志消息发布订阅异常情况日志处理及Cap DashBoard授权处理

    Dashboard介绍 capOptions.UseDashboard(dashoptions => { dashoptions.AppPath = "applicationpath& ...

  6. hdu 5441 (2015长春网络赛E题 带权并查集 )

    n个结点,m条边,权值是 从u到v所花的时间 ,每次询问会给一个时间,权值比 询问值小的边就可以走 从u到v 和从v到u算不同的两次 输出有多少种不同的走法(大概是这个意思吧)先把边的权值 从小到大排 ...

  7. 如何用node.js批量给图片加水印

    上一篇我们讲了如何用node.js给图片加水印,但是只是给某一张图片加,并没有涉及到批量处理.这一篇,我们学习如果批量进行图片加水印处理. 一.准备工作: 首先,你要阅读完这篇文章:http://ww ...

  8. 001 jquery对象与dom对象的转换

    1.jQuery对象介绍 2.jQuery对象转换为Dom对象 3.Dom转换为Jquery对象 4.将jquery转换为Dom程序 <!DOCTYPE html> <html> ...

  9. P2858 [USACO06FEB]奶牛零食Treats for the Cows

    P2858 [USACO06FEB]奶牛零食Treats for the Cows区间dp,级像矩阵取数, f[i][i+l]=max(f[i+1][i+l]+a[i]*(m-l),f[i][i+l- ...

  10. 点击图片查看大图(纯js)

    $(function(){ $(".pimg").click(function(){ var _this = $(this);//将当前的pimg元素作为_this传入函数 img ...