1. /*
  2. * @(#)GregorianCalendar.java 1.84 04/04/25
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
  9. * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
  10. *
  11. * The original version of this source code and documentation is copyrighted
  12. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  13. * materials are provided under terms of a License Agreement between Taligent
  14. * and Sun. This technology is protected by multiple US and International
  15. * patents. This notice and attribution to Taligent may not be removed.
  16. * Taligent is a registered trademark of Taligent, Inc.
  17. *
  18. */
  19. package java.util;
  20. import java.io.IOException;
  21. import java.io.ObjectInputStream;
  22. import sun.util.calendar.BaseCalendar;
  23. import sun.util.calendar.CalendarDate;
  24. import sun.util.calendar.CalendarSystem;
  25. import sun.util.calendar.CalendarUtils;
  26. import sun.util.calendar.Era;
  27. import sun.util.calendar.Gregorian;
  28. import sun.util.calendar.JulianCalendar;
  29. import sun.util.calendar.ZoneInfo;
  30. /**
  31. * <code>GregorianCalendar</code> is a concrete subclass of
  32. * <code>Calendar</code> and provides the standard calendar system
  33. * used by most of the world.
  34. *
  35. * <p> <code>GregorianCalendar</code> is a hybrid calendar that
  36. * supports both the Julian and Gregorian calendar systems with the
  37. * support of a single discontinuity, which corresponds by default to
  38. * the Gregorian date when the Gregorian calendar was instituted
  39. * (October 15, 1582 in some countries, later in others). The cutover
  40. * date may be changed by the caller by calling {@link
  41. * #setGregorianChange(Date) setGregorianChange()}.
  42. *
  43. * <p>
  44. * Historically, in those countries which adopted the Gregorian calendar first,
  45. * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
  46. * this correctly. Before the Gregorian cutover, <code>GregorianCalendar</code>
  47. * implements the Julian calendar. The only difference between the Gregorian
  48. * and the Julian calendar is the leap year rule. The Julian calendar specifies
  49. * leap years every four years, whereas the Gregorian calendar omits century
  50. * years which are not divisible by 400.
  51. *
  52. * <p>
  53. * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
  54. * Julian calendars. That is, dates are computed by extrapolating the current
  55. * rules indefinitely far backward and forward in time. As a result,
  56. * <code>GregorianCalendar</code> may be used for all years to generate
  57. * meaningful and consistent results. However, dates obtained using
  58. * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
  59. * AD onward, when modern Julian calendar rules were adopted. Before this date,
  60. * leap year rules were applied irregularly, and before 45 BC the Julian
  61. * calendar did not even exist.
  62. *
  63. * <p>
  64. * Prior to the institution of the Gregorian calendar, New Year's Day was
  65. * March 25. To avoid confusion, this calendar always uses January 1. A manual
  66. * adjustment may be made if desired for dates that are prior to the Gregorian
  67. * changeover and which fall between January 1 and March 24.
  68. *
  69. * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
  70. * 53. Week 1 for a year is the earliest seven day period starting on
  71. * <code>getFirstDayOfWeek()</code> that contains at least
  72. * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
  73. * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
  74. * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
  75. * Weeks between week 1 of one year and week 1 of the following year are
  76. * numbered sequentially from 2 to 52 or 53 (as needed).
  77. * <p>For example, January 1, 1998 was a Thursday. If
  78. * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
  79. * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
  80. * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
  81. * on December 29, 1997, and ends on January 4, 1998. If, however,
  82. * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
  83. * starts on January 4, 1998, and ends on January 10, 1998; the first three days
  84. * of 1998 then are part of week 53 of 1997.
  85. *
  86. * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
  87. * to 6. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
  88. * 1</code>) is the earliest set of at least
  89. * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
  90. * ending on the day before <code>getFirstDayOfWeek()</code>. Unlike
  91. * week 1 of a year, week 1 of a month may be shorter than 7 days, need
  92. * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
  93. * the previous month. Days of a month before week 1 have a
  94. * <code>WEEK_OF_MONTH</code> of 0.
  95. *
  96. * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
  97. * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
  98. * January 1998 is Sunday, January 4 through Saturday, January 10. These days
  99. * have a <code>WEEK_OF_MONTH</code> of 1. Thursday, January 1 through
  100. * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If
  101. * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
  102. * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
  103. *
  104. * <p>The <code>clear</code> methods set calendar field(s)
  105. * undefined. <code>GregorianCalendar</code> uses the following
  106. * default value for each calendar field if its value is undefined.
  107. *
  108. * <table cellpadding="0" cellspacing="3" border="0"
  109. * summary="GregorianCalendar default field values"
  110. * style="text-align: left; width: 66%;">
  111. * <tbody>
  112. * <tr>
  113. * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
  114. * text-align: center;">Field<br>
  115. * </th>
  116. * <th style="vertical-align: top; background-color: rgb(204, 204, 255);
  117. * text-align: center;">Default Value<br>
  118. * </th>
  119. * </tr>
  120. * <tr>
  121. * <td style="vertical-align: middle;">
  122. * <code>ERA<br></code>
  123. * </td>
  124. * <td style="vertical-align: middle;">
  125. * <code>AD<br></code>
  126. * </td>
  127. * </tr>
  128. * <tr>
  129. * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
  130. * <code>YEAR<br></code>
  131. * </td>
  132. * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
  133. * <code>1970<br></code>
  134. * </td>
  135. * </tr>
  136. * <tr>
  137. * <td style="vertical-align: middle;">
  138. * <code>MONTH<br></code>
  139. * </td>
  140. * <td style="vertical-align: middle;">
  141. * <code>JANUARY<br></code>
  142. * </td>
  143. * </tr>
  144. * <tr>
  145. * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
  146. * <code>DAY_OF_MONTH<br></code>
  147. * </td>
  148. * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
  149. * <code>1<br></code>
  150. * </td>
  151. * </tr>
  152. * <tr>
  153. * <td style="vertical-align: middle;">
  154. * <code>DAY_OF_WEEK<br></code>
  155. * </td>
  156. * <td style="vertical-align: middle;">
  157. * <code>the first day of week<br></code>
  158. * </td>
  159. * </tr>
  160. * <tr>
  161. * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
  162. * <code>WEEK_OF_MONTH<br></code>
  163. * </td>
  164. * <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
  165. * <code>0<br></code>
  166. * </td>
  167. * </tr>
  168. * <tr>
  169. * <td style="vertical-align: top;">
  170. * <code>DAY_OF_WEEK_IN_MONTH<br></code>
  171. * </td>
  172. * <td style="vertical-align: top;">
  173. * <code>1<br></code>
  174. * </td>
  175. * </tr>
  176. * <tr>
  177. * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
  178. * <code>AM_PM<br></code>
  179. * </td>
  180. * <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
  181. * <code>AM<br></code>
  182. * </td>
  183. * </tr>
  184. * <tr>
  185. * <td style="vertical-align: middle;">
  186. * <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
  187. * </td>
  188. * <td style="vertical-align: middle;">
  189. * <code>0<br></code>
  190. * </td>
  191. * </tr>
  192. * </tbody>
  193. * </table>
  194. * <br>Default values are not applicable for the fields not listed above.
  195. *
  196. * <p>
  197. * <strong>Example:</strong>
  198. * <blockquote>
  199. * <pre>
  200. * // get the supported ids for GMT-08:00 (Pacific Standard Time)
  201. * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
  202. * // if no ids were returned, something is wrong. get out.
  203. * if (ids.length == 0)
  204. * System.exit(0);
  205. *
  206. * // begin output
  207. * System.out.println("Current Time");
  208. *
  209. * // create a Pacific Standard Time time zone
  210. * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
  211. *
  212. * // set up rules for daylight savings time
  213. * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  214. * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  215. *
  216. * // create a GregorianCalendar with the Pacific Daylight time zone
  217. * // and the current date and time
  218. * Calendar calendar = new GregorianCalendar(pdt);
  219. * Date trialTime = new Date();
  220. * calendar.setTime(trialTime);
  221. *
  222. * // print out a bunch of interesting things
  223. * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  224. * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  225. * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  226. * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  227. * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  228. * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  229. * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  230. * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  231. * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  232. * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  233. * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  234. * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  235. * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  236. * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  237. * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  238. * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  239. * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  240. * System.out.println("ZONE_OFFSET: "
  241. * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
  242. * System.out.println("DST_OFFSET: "
  243. * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
  244. * System.out.println("Current Time, with hour reset to 3");
  245. * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
  246. * calendar.set(Calendar.HOUR, 3);
  247. * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  248. * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  249. * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  250. * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  251. * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  252. * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  253. * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  254. * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  255. * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  256. * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  257. * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  258. * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  259. * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  260. * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  261. * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  262. * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  263. * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  264. * System.out.println("ZONE_OFFSET: "
  265. * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
  266. * System.out.println("DST_OFFSET: "
  267. * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
  268. * </pre>
  269. * </blockquote>
  270. *
  271. * @see TimeZone
  272. * @version 1.84
  273. * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
  274. * @since JDK1.1
  275. */
  276. public class GregorianCalendar extends Calendar {
  277. /*
  278. * Implementation Notes
  279. *
  280. * The epoch is the number of days or milliseconds from some defined
  281. * starting point. The epoch for java.util.Date is used here; that is,
  282. * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other
  283. * epochs which are used are January 1, year 1 (Gregorian), which is day 1
  284. * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
  285. * day 1 of the Julian calendar.
  286. *
  287. * We implement the proleptic Julian and Gregorian calendars. This means we
  288. * implement the modern definition of the calendar even though the
  289. * historical usage differs. For example, if the Gregorian change is set
  290. * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
  291. * labels dates preceding the invention of the Gregorian calendar in 1582 as
  292. * if the calendar existed then.
  293. *
  294. * Likewise, with the Julian calendar, we assume a consistent
  295. * 4-year leap year rule, even though the historical pattern of
  296. * leap years is irregular, being every 3 years from 45 BCE
  297. * through 9 BCE, then every 4 years from 8 CE onwards, with no
  298. * leap years in-between. Thus date computations and functions
  299. * such as isLeapYear() are not intended to be historically
  300. * accurate.
  301. */
  302. //////////////////
  303. // Class Variables
  304. //////////////////
  305. /**
  306. * Value of the <code>ERA</code> field indicating
  307. * the period before the common era (before Christ), also known as BCE.
  308. * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
  309. * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
  310. *
  311. * @see #ERA
  312. */
  313. public static final int BC = 0;
  314. /**
  315. * Value of the {@link #ERA} field indicating
  316. * the period before the common era, the same value as {@link #BC}.
  317. *
  318. * @see #CE
  319. */
  320. static final int BCE = 0;
  321. /**
  322. * Value of the <code>ERA</code> field indicating
  323. * the common era (Anno Domini), also known as CE.
  324. * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
  325. * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
  326. *
  327. * @see #ERA
  328. */
  329. public static final int AD = 1;
  330. /**
  331. * Value of the {@link #ERA} field indicating
  332. * the common era, the same value as {@link #AD}.
  333. *
  334. * @see #BCE
  335. */
  336. static final int CE = 1;
  337. private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
  338. private static final int EPOCH_YEAR = 1970;
  339. static final int MONTH_LENGTH[]
  340. = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
  341. static final int LEAP_MONTH_LENGTH[]
  342. = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
  343. // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit
  344. // into ints, they must be longs in order to prevent arithmetic overflow
  345. // when performing (bug 4173516).
  346. private static final int ONE_SECOND = 1000;
  347. private static final int ONE_MINUTE = 60*ONE_SECOND;
  348. private static final int ONE_HOUR = 60*ONE_MINUTE;
  349. private static final long ONE_DAY = 24*ONE_HOUR;
  350. private static final long ONE_WEEK = 7*ONE_DAY;
  351. /*
  352. * <pre>
  353. * Greatest Least
  354. * Field name Minimum Minimum Maximum Maximum
  355. * ---------- ------- ------- ------- -------
  356. * ERA 0 0 1 1
  357. * YEAR 1 1 292269054 292278994
  358. * MONTH 0 0 11 11
  359. * WEEK_OF_YEAR 1 1 52* 53
  360. * WEEK_OF_MONTH 0 0 4* 6
  361. * DAY_OF_MONTH 1 1 28* 31
  362. * DAY_OF_YEAR 1 1 365* 366
  363. * DAY_OF_WEEK 1 1 7 7
  364. * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6
  365. * AM_PM 0 0 1 1
  366. * HOUR 0 0 11 11
  367. * HOUR_OF_DAY 0 0 23 23
  368. * MINUTE 0 0 59 59
  369. * SECOND 0 0 59 59
  370. * MILLISECOND 0 0 999 999
  371. * ZONE_OFFSET -13:00 -13:00 14:00 14:00
  372. * DST_OFFSET 0:00 0:00 0:20 2:00
  373. * </pre>
  374. * *: depends on the Gregorian change date
  375. */
  376. static final int MIN_VALUES[] = {
  377. BCE, // ERA
  378. 1, // YEAR
  379. JANUARY, // MONTH
  380. 1, // WEEK_OF_YEAR
  381. 0, // WEEK_OF_MONTH
  382. 1, // DAY_OF_MONTH
  383. 1, // DAY_OF_YEAR
  384. SUNDAY, // DAY_OF_WEEK
  385. 1, // DAY_OF_WEEK_IN_MONTH
  386. AM, // AM_PM
  387. 0, // HOUR
  388. 0, // HOUR_OF_DAY
  389. 0, // MINUTE
  390. 0, // SECOND
  391. 0, // MILLISECOND
  392. -13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
  393. 0 // DST_OFFSET
  394. };
  395. static final int LEAST_MAX_VALUES[] = {
  396. CE, // ERA
  397. 292269054, // YEAR
  398. DECEMBER, // MONTH
  399. 52, // WEEK_OF_YEAR
  400. 4, // WEEK_OF_MONTH
  401. 28, // DAY_OF_MONTH
  402. 365, // DAY_OF_YEAR
  403. SATURDAY, // DAY_OF_WEEK
  404. 4, // DAY_OF_WEEK_IN
  405. PM, // AM_PM
  406. 11, // HOUR
  407. 23, // HOUR_OF_DAY
  408. 59, // MINUTE
  409. 59, // SECOND
  410. 999, // MILLISECOND
  411. 14*ONE_HOUR, // ZONE_OFFSET
  412. 20*ONE_MINUTE // DST_OFFSET (historical least maximum)
  413. };
  414. static final int MAX_VALUES[] = {
  415. CE, // ERA
  416. 292278994, // YEAR
  417. DECEMBER, // MONTH
  418. 53, // WEEK_OF_YEAR
  419. 6, // WEEK_OF_MONTH
  420. 31, // DAY_OF_MONTH
  421. 366, // DAY_OF_YEAR
  422. SATURDAY, // DAY_OF_WEEK
  423. 6, // DAY_OF_WEEK_IN
  424. PM, // AM_PM
  425. 11, // HOUR
  426. 23, // HOUR_OF_DAY
  427. 59, // MINUTE
  428. 59, // SECOND
  429. 999, // MILLISECOND
  430. 14*ONE_HOUR, // ZONE_OFFSET
  431. 2*ONE_HOUR // DST_OFFSET (double summer time)
  432. };
  433. // Proclaim serialization compatibility with JDK 1.1
  434. static final long serialVersionUID = -8125100834729963327L;
  435. // Reference to the sun.util.calendar.Gregorian instance (singleton).
  436. private static final Gregorian gcal =
  437. CalendarSystem.getGregorianCalendar();
  438. // Reference to the JulianCalendar instance (singleton), set as needed. See
  439. // getJulianCalendarSystem().
  440. private static JulianCalendar jcal;
  441. // JulianCalendar eras. See getJulianCalendarSystem().
  442. private static Era[] jeras;
  443. // The default value of gregorianCutover.
  444. static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
  445. /////////////////////
  446. // Instance Variables
  447. /////////////////////
  448. /**
  449. * The point at which the Gregorian calendar rules are used, measured in
  450. * milliseconds from the standard epoch. Default is October 15, 1582
  451. * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
  452. * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
  453. * corresponds to Julian day number 2299161.
  454. * @serial
  455. */
  456. private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
  457. /**
  458. * The fixed date of the gregorianCutover.
  459. */
  460. private transient long gregorianCutoverDate =
  461. (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
  462. /**
  463. * The normalized year of the gregorianCutover in Gregorian, with
  464. * 0 representing 1 BCE, -1 representing 2 BCE, etc.
  465. */
  466. private transient int gregorianCutoverYear = 1582;
  467. /**
  468. * The normalized year of the gregorianCutover in Julian, with 0
  469. * representing 1 BCE, -1 representing 2 BCE, etc.
  470. */
  471. private transient int gregorianCutoverYearJulian = 1582;
  472. /**
  473. * gdate always has a sun.util.calendar.Gregorian.Date instance to
  474. * avoid overhead of creating it. The assumption is that most
  475. * applications will need only Gregorian calendar calculations.
  476. */
  477. private transient BaseCalendar.Date gdate;
  478. /**
  479. * Reference to either gdate or a JulianCalendar.Date
  480. * instance. After calling complete(), this value is guaranteed to
  481. * be set.
  482. */
  483. private transient BaseCalendar.Date cdate;
  484. /**
  485. * The CalendarSystem used to calculate the date in cdate. After
  486. * calling complete(), this value is guaranteed to be set and
  487. * consistent with the cdate value.
  488. */
  489. private transient BaseCalendar calsys;
  490. /**
  491. * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
  492. * the GMT offset value and zoneOffsets[1] gets the DST saving
  493. * value.
  494. */
  495. private transient int[] zoneOffsets;
  496. /**
  497. * Temporary storage for saving original fields[] values in
  498. * non-lenient mode.
  499. */
  500. private transient int[] originalFields;
  501. ///////////////
  502. // Constructors
  503. ///////////////
  504. /**
  505. * Constructs a default <code>GregorianCalendar</code> using the current time
  506. * in the default time zone with the default locale.
  507. */
  508. public GregorianCalendar() {
  509. this(TimeZone.getDefaultRef(), Locale.getDefault());
  510. setZoneShared(true);
  511. }
  512. /**
  513. * Constructs a <code>GregorianCalendar</code> based on the current time
  514. * in the given time zone with the default locale.
  515. *
  516. * @param zone the given time zone.
  517. */
  518. public GregorianCalendar(TimeZone zone) {
  519. this(zone, Locale.getDefault());
  520. }
  521. /**
  522. * Constructs a <code>GregorianCalendar</code> based on the current time
  523. * in the default time zone with the given locale.
  524. *
  525. * @param aLocale the given locale.
  526. */
  527. public GregorianCalendar(Locale aLocale) {
  528. this(TimeZone.getDefaultRef(), aLocale);
  529. setZoneShared(true);
  530. }
  531. /**
  532. * Constructs a <code>GregorianCalendar</code> based on the current time
  533. * in the given time zone with the given locale.
  534. *
  535. * @param zone the given time zone.
  536. * @param aLocale the given locale.
  537. */
  538. public GregorianCalendar(TimeZone zone, Locale aLocale) {
  539. super(zone, aLocale);
  540. gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
  541. setTimeInMillis(System.currentTimeMillis());
  542. }
  543. /**
  544. * Constructs a <code>GregorianCalendar</code> with the given date set
  545. * in the default time zone with the default locale.
  546. *
  547. * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
  548. * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
  549. * Month value is 0-based. e.g., 0 for January.
  550. * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
  551. */
  552. public GregorianCalendar(int year, int month, int dayOfMonth) {
  553. this(year, month, dayOfMonth, 0, 0, 0, 0);
  554. }
  555. /**
  556. * Constructs a <code>GregorianCalendar</code> with the given date
  557. * and time set for the default time zone with the default locale.
  558. *
  559. * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
  560. * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
  561. * Month value is 0-based. e.g., 0 for January.
  562. * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
  563. * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
  564. * in the calendar.
  565. * @param minute the value used to set the <code>MINUTE</code> calendar field
  566. * in the calendar.
  567. */
  568. public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
  569. int minute) {
  570. this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
  571. }
  572. /**
  573. * Constructs a GregorianCalendar with the given date
  574. * and time set for the default time zone with the default locale.
  575. *
  576. * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
  577. * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
  578. * Month value is 0-based. e.g., 0 for January.
  579. * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
  580. * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
  581. * in the calendar.
  582. * @param minute the value used to set the <code>MINUTE</code> calendar field
  583. * in the calendar.
  584. * @param second the value used to set the <code>SECOND</code> calendar field
  585. * in the calendar.
  586. */
  587. public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
  588. int minute, int second) {
  589. this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
  590. }
  591. /**
  592. * Constructs a <code>GregorianCalendar</code> with the given date
  593. * and time set for the default time zone with the default locale.
  594. *
  595. * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
  596. * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
  597. * Month value is 0-based. e.g., 0 for January.
  598. * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
  599. * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
  600. * in the calendar.
  601. * @param minute the value used to set the <code>MINUTE</code> calendar field
  602. * in the calendar.
  603. * @param second the value used to set the <code>SECOND</code> calendar field
  604. * in the calendar.
  605. * @param millis the value used to set the <code>MILLISECOND</code> calendar field
  606. */
  607. GregorianCalendar(int year, int month, int dayOfMonth,
  608. int hourOfDay, int minute, int second, int millis) {
  609. super();
  610. gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
  611. this.set(YEAR, year);
  612. this.set(MONTH, month);
  613. this.set(DAY_OF_MONTH, dayOfMonth);
  614. this.set(HOUR_OF_DAY, hourOfDay);
  615. this.set(MINUTE, minute);
  616. this.set(SECOND, second);
  617. // should be changed to set() when this constructor is made
  618. // public.
  619. this.internalSet(MILLISECOND, millis);
  620. }
  621. /////////////////
  622. // Public methods
  623. /////////////////
  624. /**
  625. * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
  626. * from Julian dates to Gregorian dates occurred. Default is October 15,
  627. * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
  628. * <p>
  629. * To obtain a pure Julian calendar, set the change date to
  630. * <code>Date(Long.MAX_VALUE)</code>. To obtain a pure Gregorian calendar,
  631. * set the change date to <code>Date(Long.MIN_VALUE)</code>.
  632. *
  633. * @param date the given Gregorian cutover date.
  634. */
  635. public void setGregorianChange(Date date) {
  636. long cutoverTime = date.getTime();
  637. if (cutoverTime == gregorianCutover) {
  638. return;
  639. }
  640. // Before changing the cutover date, make sure to have the
  641. // time of this calendar.
  642. complete();
  643. setGregorianChange(cutoverTime);
  644. }
  645. private void setGregorianChange(long cutoverTime) {
  646. gregorianCutover = cutoverTime;
  647. gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
  648. + EPOCH_OFFSET;
  649. // To provide the "pure" Julian calendar as advertised.
  650. // Strictly speaking, the last millisecond should be a
  651. // Gregorian date. However, the API doc specifies that setting
  652. // the cutover date to Long.MAX_VALUE will make this calendar
  653. // a pure Julian calendar. (See 4167995)
  654. if (cutoverTime == Long.MAX_VALUE) {
  655. gregorianCutoverDate++;
  656. }
  657. BaseCalendar.Date d = getGregorianCutoverDate();
  658. // Set the cutover year (in the Gregorian year numbering)
  659. gregorianCutoverYear = d.getYear();
  660. BaseCalendar jcal = getJulianCalendarSystem();
  661. d = (BaseCalendar.Date) jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
  662. jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
  663. gregorianCutoverYearJulian = d.getNormalizedYear();
  664. if (time < gregorianCutover) {
  665. // The field values are no longer valid under the new
  666. // cutover date.
  667. setUnnormalized();
  668. }
  669. }
  670. /**
  671. * Gets the Gregorian Calendar change date. This is the point when the
  672. * switch from Julian dates to Gregorian dates occurred. Default is
  673. * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
  674. * calendar.
  675. *
  676. * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
  677. */
  678. public final Date getGregorianChange() {
  679. return new Date(gregorianCutover);
  680. }
  681. /**
  682. * Determines if the given year is a leap year. Returns <code>true</code> if
  683. * the given year is a leap year. To specify BC year numbers,
  684. * <code>1 - year number</code> must be given. For example, year BC 4 is
  685. * specified as -3.
  686. *
  687. * @param year the given year.
  688. * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
  689. */
  690. public boolean isLeapYear(int year) {
  691. if ((year & 3) != 0) {
  692. return false;
  693. }
  694. if (year > gregorianCutoverYear) {
  695. return (year%100 != 0) || (year%400 == 0); // Gregorian
  696. }
  697. if (year < gregorianCutoverYearJulian) {
  698. return true; // Julian
  699. }
  700. boolean gregorian;
  701. // If the given year is the Gregorian cutover year, we need to
  702. // determine which calendar system to be applied to February in the year.
  703. if (gregorianCutoverYear == gregorianCutoverYearJulian) {
  704. BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
  705. gregorian = d.getMonth() < BaseCalendar.MARCH;
  706. } else {
  707. gregorian = year == gregorianCutoverYear;
  708. }
  709. return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
  710. }
  711. /**
  712. * Compares this <code>GregorianCalendar</code> to the specified
  713. * <code>Object</code>. The result is <code>true</code> if and
  714. * only if the argument is a <code>GregorianCalendar</code> object
  715. * that represents the same time value (millisecond offset from
  716. * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
  717. * <code>Calendar</code> parameters and Gregorian change date as
  718. * this object.
  719. *
  720. * @param obj the object to compare with.
  721. * @return <code>true</code> if this object is equal to <code>obj</code>
  722. * <code>false</code> otherwise.
  723. * @see Calendar#compareTo(Calendar)
  724. */
  725. public boolean equals(Object obj) {
  726. return obj instanceof GregorianCalendar &&
  727. super.equals(obj) &&
  728. gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
  729. }
  730. /**
  731. * Generates the hash code for this <code>GregorianCalendar</code> object.
  732. */
  733. public int hashCode() {
  734. return super.hashCode() ^ (int)gregorianCutoverDate;
  735. }
  736. /**
  737. * Adds the specified (signed) amount of time to the given calendar field,
  738. * based on the calendar's rules.
  739. *
  740. * <p><em>Add rule 1</em>. The value of <code>field</code>
  741. * after the call minus the value of <code>field</code> before the
  742. * call is <code>amount</code>, modulo any overflow that has occurred in
  743. * <code>field</code>. Overflow occurs when a field value exceeds its
  744. * range and, as a result, the next larger field is incremented or
  745. * decremented and the field value is adjusted back into its range.</p>
  746. *
  747. * <p><em>Add rule 2</em>. If a smaller field is expected to be
  748. * invariant, but it is impossible for it to be equal to its
  749. * prior value because of changes in its minimum or maximum after
  750. * <code>field</code> is changed, then its value is adjusted to be as close
  751. * as possible to its expected value. A smaller field represents a
  752. * smaller unit of time. <code>HOUR</code> is a smaller field than
  753. * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
  754. * that are not expected to be invariant. The calendar system
  755. * determines what fields are expected to be invariant.</p>
  756. *
  757. * @param field the calendar field.
  758. * @param amount the amount of date or time to be added to the field.
  759. * @exception IllegalArgumentException if <code>field</code> is
  760. * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
  761. * or if any calendar fields have out-of-range values in
  762. * non-lenient mode.
  763. */
  764. public void add(int field, int amount) {
  765. // If amount == 0, do nothing even the given field is out of
  766. // range. This is tested by JCK.
  767. if (amount == 0) {
  768. return; // Do nothing!
  769. }
  770. if (field < 0 || field >= ZONE_OFFSET) {
  771. throw new IllegalArgumentException();
  772. }
  773. // Sync the time and calendar fields.
  774. complete();
  775. if (field == YEAR) {
  776. int year = internalGet(YEAR);
  777. if (internalGetEra() == CE) {
  778. year += amount;
  779. if (year > 0) {
  780. set(YEAR, year);
  781. } else { // year <= 0
  782. set(YEAR, 1 - year);
  783. // if year == 0, you get 1 BCE.
  784. set(ERA, BCE);
  785. }
  786. }
  787. else { // era == BCE
  788. year -= amount;
  789. if (year > 0) {
  790. set(YEAR, year);
  791. } else { // year <= 0
  792. set(YEAR, 1 - year);
  793. // if year == 0, you get 1 CE
  794. set(ERA, CE);
  795. }
  796. }
  797. pinDayOfMonth();
  798. } else if (field == MONTH) {
  799. int month = internalGet(MONTH) + amount;
  800. int year = internalGet(YEAR);
  801. int y_amount;
  802. if (month >= 0) {
  803. y_amount = month12;
  804. } else {
  805. y_amount = (month+1)/12 - 1;
  806. }
  807. if (y_amount != 0) {
  808. if (internalGetEra() == CE) {
  809. year += y_amount;
  810. if (year > 0) {
  811. set(YEAR, year);
  812. } else { // year <= 0
  813. set(YEAR, 1 - year);
  814. // if year == 0, you get 1 BCE
  815. set(ERA, BCE);
  816. }
  817. }
  818. else { // era == BCE
  819. year -= y_amount;
  820. if (year > 0) {
  821. set(YEAR, year);
  822. } else { // year <= 0
  823. set(YEAR, 1 - year);
  824. // if year == 0, you get 1 CE
  825. set(ERA, CE);
  826. }
  827. }
  828. }
  829. if (month >= 0) {
  830. set(MONTH, (int) (month % 12));
  831. } else {
  832. // month < 0
  833. month %= 12;
  834. if (month < 0) {
  835. month += 12;
  836. }
  837. set(MONTH, JANUARY + month);
  838. }
  839. pinDayOfMonth();
  840. } else if (field == ERA) {
  841. int era = internalGet(ERA) + amount;
  842. if (era < 0) {
  843. era = 0;
  844. }
  845. if (era > 1) {
  846. era = 1;
  847. }
  848. set(ERA, era);
  849. } else {
  850. long delta = amount;
  851. long timeOfDay = 0;
  852. switch (field) {
  853. // Handle the time fields here. Convert the given
  854. // amount to milliseconds and call setTimeInMillis.
  855. case HOUR:
  856. case HOUR_OF_DAY:
  857. delta *= 60 * 60 * 1000; // hours to minutes
  858. break;
  859. case MINUTE:
  860. delta *= 60 * 1000; // minutes to seconds
  861. break;
  862. case SECOND:
  863. delta *= 1000; // seconds to milliseconds
  864. break;
  865. case MILLISECOND:
  866. break;
  867. // Handle week, day and AM_PM fields which involves
  868. // time zone offset change adjustment. Convert the
  869. // given amount to the number of days.
  870. case WEEK_OF_YEAR:
  871. case WEEK_OF_MONTH:
  872. case DAY_OF_WEEK_IN_MONTH:
  873. delta *= 7;
  874. break;
  875. case DAY_OF_MONTH: // synonym of DATE
  876. case DAY_OF_YEAR:
  877. case DAY_OF_WEEK:
  878. break;
  879. case AM_PM:
  880. // Convert the amount to the number of days (delta)
  881. // and +12 or -12 hours (timeOfDay).
  882. delta = amount / 2;
  883. timeOfDay = 12 * (amount % 2);
  884. break;
  885. }
  886. // The time fields don't require time zone offset change
  887. // adjustment.
  888. if (field >= HOUR) {
  889. setTimeInMillis(time + delta);
  890. return;
  891. }
  892. // The rest of the fields (week, day or AM_PM fields)
  893. // require time zone offset (both GMT and DST) change
  894. // adjustment.
  895. // Translate the current time to the fixed date and time
  896. // of the day.
  897. long fd = getCurrentFixedDate();
  898. timeOfDay += internalGet(HOUR_OF_DAY);
  899. timeOfDay *= 60;
  900. timeOfDay += internalGet(MINUTE);
  901. timeOfDay *= 60;
  902. timeOfDay += internalGet(SECOND);
  903. timeOfDay *= 1000;
  904. timeOfDay += internalGet(MILLISECOND);
  905. if (timeOfDay >= ONE_DAY) {
  906. fd++;
  907. timeOfDay -= ONE_DAY;
  908. } else if (timeOfDay < 0) {
  909. fd--;
  910. timeOfDay += ONE_DAY;
  911. }
  912. fd += delta; // fd is the expected fixed date after the calculation
  913. int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
  914. setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
  915. zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
  916. // If the time zone offset has changed, then adjust the difference.
  917. if (zoneOffset != 0) {
  918. setTimeInMillis(time + zoneOffset);
  919. long fd2 = getCurrentFixedDate();
  920. // If the adjustment has changed the date, then take
  921. // the previous one.
  922. if (fd2 != fd) {
  923. setTimeInMillis(time - zoneOffset);
  924. }
  925. }
  926. }
  927. }
  928. /**
  929. * Adds or subtracts (up/down) a single unit of time on the given time
  930. * field without changing larger fields.
  931. * <p>
  932. * <em>Example</em>: Consider a <code>GregorianCalendar</code>
  933. * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
  934. * sets the calendar to January 31, 1999. The <code>YEAR</code> field is unchanged
  935. * because it is a larger field than <code>MONTH</code>.</p>
  936. *
  937. * @param up indicates if the value of the specified calendar field is to be
  938. * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
  939. * @exception IllegalArgumentException if <code>field</code> is
  940. * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
  941. * or if any calendar fields have out-of-range values in
  942. * non-lenient mode.
  943. * @see #add(int,int)
  944. * @see #set(int,int)
  945. */
  946. public void roll(int field, boolean up) {
  947. roll(field, up ? +1 : -1);
  948. }
  949. /**
  950. * Adds a signed amount to the specified calendar field without changing larger fields.
  951. * A negative roll amount means to subtract from field without changing
  952. * larger fields. If the specified amount is 0, this method performs nothing.
  953. *
  954. * <p>This method calls {@link #complete()} before adding the
  955. * amount so that all the calendar fields are normalized. If there
  956. * is any calendar field having an out-of-range value in non-lenient mode, then an
  957. * <code>IllegalArgumentException</code> is thrown.
  958. *
  959. * <p>
  960. * <em>Example</em>: Consider a <code>GregorianCalendar</code>
  961. * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
  962. * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
  963. * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
  964. * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
  965. * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
  966. * is a larger field than <code>MONTH</code>.
  967. * <p>
  968. * <em>Example</em>: Consider a <code>GregorianCalendar</code>
  969. * originally set to Sunday June 6, 1999. Calling
  970. * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
  971. * Tuesday June 1, 1999, whereas calling
  972. * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
  973. * Sunday May 30, 1999. This is because the roll rule imposes an
  974. * additional constraint: The <code>MONTH</code> must not change when the
  975. * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
  976. * the resultant date must be between Tuesday June 1 and Saturday June
  977. * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
  978. * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
  979. * closest possible value to Sunday (where Sunday is the first day of the
  980. * week).</p>
  981. *
  982. * @param field the calendar field.
  983. * @param amount the signed amount to add to <code>field</code>.
  984. * @exception IllegalArgumentException if <code>field</code> is
  985. * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
  986. * or if any calendar fields have out-of-range values in
  987. * non-lenient mode.
  988. * @see #roll(int,boolean)
  989. * @see #add(int,int)
  990. * @see #set(int,int)
  991. * @since 1.2
  992. */
  993. public void roll(int field, int amount) {
  994. // If amount == 0, do nothing even the given field is out of
  995. // range. This is tested by JCK.
  996. if (amount == 0) {
  997. return;
  998. }
  999. if (field < 0 || field >= ZONE_OFFSET) {
  1000. throw new IllegalArgumentException();
  1001. }
  1002. // Sync the time and calendar fields.
  1003. complete();
  1004. int min = getMinimum(field);
  1005. int max = getMaximum(field);
  1006. switch (field) {
  1007. case AM_PM:
  1008. case ERA:
  1009. case YEAR:
  1010. case MINUTE:
  1011. case SECOND:
  1012. case MILLISECOND:
  1013. // These fields are handled simply, since they have fixed minima
  1014. // and maxima. The field DAY_OF_MONTH is almost as simple. Other
  1015. // fields are complicated, since the range within they must roll
  1016. // varies depending on the date.
  1017. break;
  1018. case HOUR:
  1019. case HOUR_OF_DAY:
  1020. {
  1021. int unit = max + 1; // 12 or 24 hours
  1022. int h = internalGet(field);
  1023. int nh = (h + amount) % unit;
  1024. if (nh < 0) {
  1025. nh += unit;
  1026. }
  1027. time += ONE_HOUR * (nh - h);
  1028. // The day might have changed, which could happen if
  1029. // the daylight saving time transition brings it to
  1030. // the next day, although it's very unlikely. But we
  1031. // have to make sure not to change the larger fields.
  1032. CalendarDate d = calsys.getCalendarDate(time, getZone());
  1033. if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
  1034. d.setDate(internalGet(YEAR),
  1035. internalGet(MONTH) + 1,
  1036. internalGet(DAY_OF_MONTH));
  1037. if (field == HOUR) {
  1038. assert (internalGet(AM_PM) == PM);
  1039. d.addHours(+12); // restore PM
  1040. }
  1041. time = calsys.getTime(d);
  1042. }
  1043. internalSet(field, d.getHours() % unit);
  1044. // Time zone offset and/or daylight saving might have changed.
  1045. int zoneOffset = d.getZoneOffset();
  1046. int saving = d.getDaylightSaving();
  1047. internalSet(ZONE_OFFSET, zoneOffset - saving);
  1048. internalSet(DST_OFFSET, saving);
  1049. return;
  1050. }
  1051. case MONTH:
  1052. // Rolling the month involves both pinning the final value to [0, 11]
  1053. // and adjusting the DAY_OF_MONTH if necessary. We only adjust the
  1054. // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
  1055. // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
  1056. {
  1057. if (!isCutoverYear(cdate.getNormalizedYear())) {
  1058. int mon = (internalGet(MONTH) + amount) % 12;
  1059. if (mon < 0) {
  1060. mon += 12;
  1061. }
  1062. set(MONTH, mon);
  1063. // Keep the day of month in the range. We don't want to spill over
  1064. // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
  1065. // mar3.
  1066. int monthLen = monthLength(mon);
  1067. if (internalGet(DAY_OF_MONTH) > monthLen) {
  1068. set(DAY_OF_MONTH, monthLen);
  1069. }
  1070. } else {
  1071. // We need to take care of different lengths in
  1072. // year and month due to the cutover.
  1073. int yearLength = getActualMaximum(MONTH) + 1;
  1074. int mon = (internalGet(MONTH) + amount) % yearLength;
  1075. if (mon < 0) {
  1076. mon += yearLength;
  1077. }
  1078. set(MONTH, mon);
  1079. int monthLen = getActualMaximum(DAY_OF_MONTH);
  1080. if (internalGet(DAY_OF_MONTH) > monthLen) {
  1081. set(DAY_OF_MONTH, monthLen);
  1082. }
  1083. }
  1084. return;
  1085. }
  1086. case WEEK_OF_YEAR:
  1087. {
  1088. int y = cdate.getNormalizedYear();
  1089. max = getActualMaximum(WEEK_OF_YEAR);
  1090. set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
  1091. int woy = internalGet(WEEK_OF_YEAR);
  1092. int value = woy + amount;
  1093. if (!isCutoverYear(y)) {
  1094. // If the new value is in between min and max
  1095. // (exclusive), then we can use the value.
  1096. if (value > min && value < max) {
  1097. set(WEEK_OF_YEAR, value);
  1098. return;
  1099. }
  1100. long fd = getCurrentFixedDate();
  1101. // Make sure that the min week has the current DAY_OF_WEEK
  1102. long day1 = fd - (7 * (woy - min));
  1103. if (calsys.getYearFromFixedDate(day1) != y) {
  1104. min++;
  1105. }
  1106. // Make sure the same thing for the max week
  1107. fd += 7 * (max - internalGet(WEEK_OF_YEAR));
  1108. if (calsys.getYearFromFixedDate(fd) != y) {
  1109. max--;
  1110. }
  1111. break;
  1112. }
  1113. // Handle cutover here.
  1114. long fd = getCurrentFixedDate();
  1115. BaseCalendar cal;
  1116. if (gregorianCutoverYear == gregorianCutoverYearJulian) {
  1117. cal = getCutoverCalendarSystem();
  1118. } else if (y == gregorianCutoverYear) {
  1119. cal = gcal;
  1120. } else {
  1121. cal = getJulianCalendarSystem();
  1122. }
  1123. long day1 = fd - (7 * (woy - min));
  1124. // Make sure that the min week has the current DAY_OF_WEEK
  1125. if (cal.getYearFromFixedDate(day1) != y) {
  1126. min++;
  1127. }
  1128. // Make sure the same thing for the max week
  1129. fd += 7 * (max - woy);
  1130. cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
  1131. if (cal.getYearFromFixedDate(fd) != y) {
  1132. max--;
  1133. }
  1134. // value: the new WEEK_OF_YEAR which must be converted
  1135. // to month and day of month.
  1136. value = getRolledValue(woy, amount, min, max) - 1;
  1137. BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
  1138. set(MONTH, d.getMonth() - 1);
  1139. set(DAY_OF_MONTH, d.getDayOfMonth());
  1140. return;
  1141. }
  1142. case WEEK_OF_MONTH:
  1143. {
  1144. boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
  1145. // dow: relative day of week from first day of week
  1146. int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1147. if (dow < 0) {
  1148. dow += 7;
  1149. }
  1150. long fd = getCurrentFixedDate();
  1151. long month1; // fixed date of the first day (usually 1) of the month
  1152. int monthLength; // actual month length
  1153. if (isCutoverYear) {
  1154. month1 = getFixedDateMonth1(cdate, fd);
  1155. monthLength = actualMonthLength();
  1156. } else {
  1157. month1 = fd - internalGet(DAY_OF_MONTH) + 1;
  1158. monthLength = calsys.getMonthLength(cdate);
  1159. }
  1160. // the first day of week of the month.
  1161. long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(month1 + 6,
  1162. getFirstDayOfWeek());
  1163. // if the week has enough days to form a week, the
  1164. // week starts from the previous month.
  1165. if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
  1166. monthDay1st -= 7;
  1167. }
  1168. max = getActualMaximum(field);
  1169. // value: the new WEEK_OF_MONTH value
  1170. int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
  1171. // nfd: fixed date of the rolled date
  1172. long nfd = monthDay1st + value * 7 + dow;
  1173. // Unlike WEEK_OF_YEAR, we need to change day of week if the
  1174. // nfd is out of the month.
  1175. if (nfd < month1) {
  1176. nfd = month1;
  1177. } else if (nfd >= (month1 + monthLength)) {
  1178. nfd = month1 + monthLength - 1;
  1179. }
  1180. int dayOfMonth;
  1181. if (isCutoverYear) {
  1182. // If we are in the cutover year, convert nfd to
  1183. // its calendar date and use dayOfMonth.
  1184. BaseCalendar.Date d = getCalendarDate(nfd);
  1185. dayOfMonth = d.getDayOfMonth();
  1186. } else {
  1187. dayOfMonth = (int)(nfd - month1) + 1;
  1188. }
  1189. set(DAY_OF_MONTH, dayOfMonth);
  1190. return;
  1191. }
  1192. case DAY_OF_MONTH:
  1193. {
  1194. if (!isCutoverYear(cdate.getNormalizedYear())) {
  1195. max = calsys.getMonthLength(cdate);
  1196. break;
  1197. }
  1198. // Cutover year handling
  1199. long fd = getCurrentFixedDate();
  1200. long month1 = getFixedDateMonth1(cdate, fd);
  1201. // It may not be a regular month. Convert the date and range to
  1202. // the relative values, perform the roll, and
  1203. // convert the result back to the rolled date.
  1204. int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
  1205. BaseCalendar.Date d = getCalendarDate(month1 + value);
  1206. assert d.getMonth()-1 == internalGet(MONTH);
  1207. set(DAY_OF_MONTH, d.getDayOfMonth());
  1208. return;
  1209. }
  1210. case DAY_OF_YEAR:
  1211. {
  1212. max = getActualMaximum(field);
  1213. if (!isCutoverYear(cdate.getNormalizedYear())) {
  1214. break;
  1215. }
  1216. // Handle cutover here.
  1217. long fd = getCurrentFixedDate();
  1218. long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
  1219. int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
  1220. BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
  1221. set(MONTH, d.getMonth() - 1);
  1222. set(DAY_OF_MONTH, d.getDayOfMonth());
  1223. return;
  1224. }
  1225. case DAY_OF_WEEK:
  1226. set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
  1227. max = SATURDAY;
  1228. break;
  1229. case DAY_OF_WEEK_IN_MONTH:
  1230. {
  1231. min = 1; // after normalized, min should be 1.
  1232. if (!isCutoverYear(cdate.getNormalizedYear())) {
  1233. int dom = internalGet(DAY_OF_MONTH);
  1234. int monthLength = calsys.getMonthLength(cdate);
  1235. int lastDays = monthLength % 7;
  1236. max = monthLength / 7;
  1237. int x = (dom - 1) % 7;
  1238. if (x < lastDays) {
  1239. max++;
  1240. }
  1241. set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
  1242. break;
  1243. }
  1244. // Cutover year handling
  1245. long fd = getCurrentFixedDate();
  1246. long month1 = getFixedDateMonth1(cdate, fd);
  1247. int monthLength = actualMonthLength();
  1248. int lastDays = monthLength % 7;
  1249. max = monthLength / 7;
  1250. int x = (int)(fd - month1) % 7;
  1251. if (x < lastDays) {
  1252. max++;
  1253. }
  1254. int value = getRolledValue(internalGet(field), amount, min, max) - 1;
  1255. fd = month1 + value * 7 + x;
  1256. BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
  1257. BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  1258. cal.getCalendarDateFromFixedDate(d, fd);
  1259. set(DAY_OF_MONTH, d.getDayOfMonth());
  1260. return;
  1261. }
  1262. }
  1263. set(field, getRolledValue(internalGet(field), amount, min, max));
  1264. }
  1265. /**
  1266. * Returns the minimum value for the given calendar field of this
  1267. * <code>GregorianCalendar</code> instance. The minimum value is
  1268. * defined as the smallest value returned by the {@link
  1269. * Calendar#get(int) get} method for any possible time value,
  1270. * taking into consideration the current values of the
  1271. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1272. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1273. * {@link #getGregorianChange(Date) getGregorianChange} and
  1274. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1275. *
  1276. * @param field the calendar field.
  1277. * @return the minimum value for the given calendar field.
  1278. * @see #getMaximum(int)
  1279. * @see #getGreatestMinimum(int)
  1280. * @see #getLeastMaximum(int)
  1281. * @see #getActualMinimum(int)
  1282. * @see #getActualMaximum(int)
  1283. */
  1284. public int getMinimum(int field) {
  1285. return MIN_VALUES[field];
  1286. }
  1287. /**
  1288. * Returns the maximum value for the given calendar field of this
  1289. * <code>GregorianCalendar</code> instance. The maximum value is
  1290. * defined as the largest value returned by the {@link
  1291. * Calendar#get(int) get} method for any possible time value,
  1292. * taking into consideration the current values of the
  1293. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1294. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1295. * {@link #getGregorianChange(Date) getGregorianChange} and
  1296. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1297. *
  1298. * @param field the calendar field.
  1299. * @return the maximum value for the given calendar field.
  1300. * @see #getMinimum(int)
  1301. * @see #getGreatestMinimum(int)
  1302. * @see #getLeastMaximum(int)
  1303. * @see #getActualMinimum(int)
  1304. * @see #getActualMaximum(int)
  1305. */
  1306. public int getMaximum(int field) {
  1307. switch (field) {
  1308. case MONTH:
  1309. case DAY_OF_MONTH:
  1310. case DAY_OF_YEAR:
  1311. case WEEK_OF_YEAR:
  1312. case WEEK_OF_MONTH:
  1313. case DAY_OF_WEEK_IN_MONTH:
  1314. case YEAR:
  1315. {
  1316. // On or after Gregorian 200-3-1, Julian and Gregorian
  1317. // calendar dates are the same or Gregorian dates are
  1318. // larger (i.e., there is a "gap") after 300-3-1.
  1319. if (gregorianCutoverYear > 200) {
  1320. break;
  1321. }
  1322. // There might be "overlapping" dates.
  1323. GregorianCalendar gc = (GregorianCalendar) clone();
  1324. gc.setLenient(true);
  1325. gc.setTimeInMillis(gregorianCutover);
  1326. int v1 = gc.getActualMaximum(field);
  1327. gc.setTimeInMillis(gregorianCutover-1);
  1328. int v2 = gc.getActualMaximum(field);
  1329. return Math.max(MAX_VALUES[field], Math.max(v1, v2));
  1330. }
  1331. }
  1332. return MAX_VALUES[field];
  1333. }
  1334. /**
  1335. * Returns the highest minimum value for the given calendar field
  1336. * of this <code>GregorianCalendar</code> instance. The highest
  1337. * minimum value is defined as the largest value returned by
  1338. * {@link #getActualMinimum(int)} for any possible time value,
  1339. * taking into consideration the current values of the
  1340. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1341. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1342. * {@link #getGregorianChange(Date) getGregorianChange} and
  1343. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1344. *
  1345. * @param field the calendar field.
  1346. * @return the highest minimum value for the given calendar field.
  1347. * @see #getMinimum(int)
  1348. * @see #getMaximum(int)
  1349. * @see #getLeastMaximum(int)
  1350. * @see #getActualMinimum(int)
  1351. * @see #getActualMaximum(int)
  1352. */
  1353. public int getGreatestMinimum(int field) {
  1354. if (field == DAY_OF_MONTH) {
  1355. BaseCalendar.Date d = getGregorianCutoverDate();
  1356. long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
  1357. d = getCalendarDate(mon1);
  1358. return Math.max(MIN_VALUES[field], d.getDayOfMonth());
  1359. }
  1360. return MIN_VALUES[field];
  1361. }
  1362. /**
  1363. * Returns the lowest maximum value for the given calendar field
  1364. * of this <code>GregorianCalendar</code> instance. The lowest
  1365. * maximum value is defined as the smallest value returned by
  1366. * {@link #getActualMaximum(int)} for any possible time value,
  1367. * taking into consideration the current values of the
  1368. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1369. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1370. * {@link #getGregorianChange(Date) getGregorianChange} and
  1371. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1372. *
  1373. * @param field the calendar field
  1374. * @return the lowest maximum value for the given calendar field.
  1375. * @see #getMinimum(int)
  1376. * @see #getMaximum(int)
  1377. * @see #getGreatestMinimum(int)
  1378. * @see #getActualMinimum(int)
  1379. * @see #getActualMaximum(int)
  1380. */
  1381. public int getLeastMaximum(int field) {
  1382. switch (field) {
  1383. case MONTH:
  1384. case DAY_OF_MONTH:
  1385. case DAY_OF_YEAR:
  1386. case WEEK_OF_YEAR:
  1387. case WEEK_OF_MONTH:
  1388. case DAY_OF_WEEK_IN_MONTH:
  1389. case YEAR:
  1390. {
  1391. GregorianCalendar gc = (GregorianCalendar) clone();
  1392. gc.setLenient(true);
  1393. gc.setTimeInMillis(gregorianCutover);
  1394. int v1 = gc.getActualMaximum(field);
  1395. gc.setTimeInMillis(gregorianCutover-1);
  1396. int v2 = gc.getActualMaximum(field);
  1397. return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
  1398. }
  1399. }
  1400. return LEAST_MAX_VALUES[field];
  1401. }
  1402. /**
  1403. * Returns the minimum value that this calendar field could have,
  1404. * taking into consideration the given time value and the current
  1405. * values of the
  1406. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1407. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1408. * {@link #getGregorianChange(Date) getGregorianChange} and
  1409. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1410. *
  1411. * <p>For example, if the Gregorian change date is January 10,
  1412. * 1970 and the date of this <code>GregorianCalendar</code> is
  1413. * January 20, 1970, the actual minimum value of the
  1414. * <code>DAY_OF_MONTH</code> field is 10 because the previous date
  1415. * of January 10, 1970 is December 27, 1996 (in the Julian
  1416. * calendar). Therefore, December 28, 1969 to January 9, 1970
  1417. * don't exist.
  1418. *
  1419. * @param field the calendar field
  1420. * @return the minimum of the given field for the time value of
  1421. * this <code>GregorianCalendar</code>
  1422. * @see #getMinimum(int)
  1423. * @see #getMaximum(int)
  1424. * @see #getGreatestMinimum(int)
  1425. * @see #getLeastMaximum(int)
  1426. * @see #getActualMaximum(int)
  1427. * @since 1.2
  1428. */
  1429. public int getActualMinimum(int field) {
  1430. if (field == DAY_OF_MONTH) {
  1431. GregorianCalendar gc = getNormalizedCalendar();
  1432. int year = gc.cdate.getNormalizedYear();
  1433. if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
  1434. long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
  1435. BaseCalendar.Date d = getCalendarDate(month1);
  1436. return d.getDayOfMonth();
  1437. }
  1438. }
  1439. return getMinimum(field);
  1440. }
  1441. /**
  1442. * Returns the maximum value that this calendar field could have,
  1443. * taking into consideration the given time value and the current
  1444. * values of the
  1445. * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
  1446. * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
  1447. * {@link #getGregorianChange(Date) getGregorianChange} and
  1448. * {@link Calendar#getTimeZone() getTimeZone} methods.
  1449. * For example, if the date of this instance is February 1, 2004,
  1450. * the actual maximum value of the <code>DAY_OF_MONTH</code> field
  1451. * is 29 because 2004 is a leap year, and if the date of this
  1452. * instance is February 1, 2005, it's 28.
  1453. *
  1454. * @param field the calendar field
  1455. * @return the maximum of the given field for the time value of
  1456. * this <code>GregorianCalendar</code>
  1457. * @see #getMinimum(int)
  1458. * @see #getMaximum(int)
  1459. * @see #getGreatestMinimum(int)
  1460. * @see #getLeastMaximum(int)
  1461. * @see #getActualMinimum(int)
  1462. * @since 1.2
  1463. */
  1464. public int getActualMaximum(int field) {
  1465. final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
  1466. HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
  1467. ZONE_OFFSET_MASK|DST_OFFSET_MASK;
  1468. if ((fieldsForFixedMax & (1<<field)) != 0) {
  1469. return getMaximum(field);
  1470. }
  1471. GregorianCalendar gc = getNormalizedCalendar();
  1472. BaseCalendar.Date date = gc.cdate;
  1473. BaseCalendar cal = gc.calsys;
  1474. int normalizedYear = date.getNormalizedYear();
  1475. int value = -1;
  1476. switch (field) {
  1477. case MONTH:
  1478. {
  1479. if (!gc.isCutoverYear(normalizedYear)) {
  1480. value = DECEMBER;
  1481. break;
  1482. }
  1483. // January 1 of the next year may or may not exist.
  1484. long nextJan1;
  1485. do {
  1486. nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
  1487. } while (nextJan1 < gregorianCutoverDate);
  1488. BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
  1489. cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
  1490. value = d.getMonth() - 1;
  1491. }
  1492. break;
  1493. case DAY_OF_MONTH:
  1494. {
  1495. value = cal.getMonthLength(date);
  1496. if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
  1497. break;
  1498. }
  1499. // Handle cutover year.
  1500. long fd = gc.getCurrentFixedDate();
  1501. if (fd >= gregorianCutoverDate) {
  1502. break;
  1503. }
  1504. int monthLength = gc.actualMonthLength();
  1505. long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
  1506. // Convert the fixed date to its calendar date.
  1507. BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
  1508. value = d.getDayOfMonth();
  1509. }
  1510. break;
  1511. case DAY_OF_YEAR:
  1512. {
  1513. if (!gc.isCutoverYear(normalizedYear)) {
  1514. value = cal.getYearLength(date);
  1515. break;
  1516. }
  1517. // Handle cutover year.
  1518. long jan1;
  1519. if (gregorianCutoverYear == gregorianCutoverYearJulian) {
  1520. BaseCalendar cocal = gc.getCutoverCalendarSystem();
  1521. jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
  1522. } else if (normalizedYear == gregorianCutoverYearJulian) {
  1523. jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
  1524. } else {
  1525. jan1 = gregorianCutoverDate;
  1526. }
  1527. // January 1 of the next year may or may not exist.
  1528. long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
  1529. if (nextJan1 < gregorianCutoverDate) {
  1530. nextJan1 = gregorianCutoverDate;
  1531. }
  1532. assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
  1533. date.getDayOfMonth(), date);
  1534. assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
  1535. date.getDayOfMonth(), date);
  1536. value = (int)(nextJan1 - jan1);
  1537. }
  1538. break;
  1539. case WEEK_OF_YEAR:
  1540. {
  1541. if (!gc.isCutoverYear(normalizedYear)) {
  1542. // Get the day of week of January 1 of the year
  1543. CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  1544. d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
  1545. int dayOfWeek = cal.getDayOfWeek(d);
  1546. // Normalize the day of week with the firstDayOfWeek value
  1547. dayOfWeek -= getFirstDayOfWeek();
  1548. if (dayOfWeek < 0) {
  1549. dayOfWeek += 7;
  1550. }
  1551. value = 52;
  1552. int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
  1553. if ((magic == 6) ||
  1554. (date.isLeapYear() && (magic == 5 || magic == 12))) {
  1555. value++;
  1556. }
  1557. break;
  1558. }
  1559. if (gc == this) {
  1560. gc = (GregorianCalendar) gc.clone();
  1561. }
  1562. gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
  1563. value = gc.get(WEEK_OF_YEAR);
  1564. }
  1565. break;
  1566. case WEEK_OF_MONTH:
  1567. {
  1568. if (!gc.isCutoverYear(normalizedYear)) {
  1569. CalendarDate d = cal.newCalendarDate(null);
  1570. d.setDate(date.getYear(), date.getMonth(), 1);
  1571. int dayOfWeek = cal.getDayOfWeek(d);
  1572. int monthLength = cal.getMonthLength(d);
  1573. dayOfWeek -= getFirstDayOfWeek();
  1574. if (dayOfWeek < 0) {
  1575. dayOfWeek += 7;
  1576. }
  1577. int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
  1578. value = 3;
  1579. if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
  1580. value++;
  1581. }
  1582. monthLength -= nDaysFirstWeek + 7 * 3;
  1583. if (monthLength > 0) {
  1584. value++;
  1585. if (monthLength > 7) {
  1586. value++;
  1587. }
  1588. }
  1589. break;
  1590. }
  1591. // Cutover year handling
  1592. if (gc == this) {
  1593. gc = (GregorianCalendar) gc.clone();
  1594. }
  1595. int y = gc.internalGet(YEAR);
  1596. int m = gc.internalGet(MONTH);
  1597. do {
  1598. value = gc.get(WEEK_OF_MONTH);
  1599. gc.add(WEEK_OF_MONTH, +1);
  1600. } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
  1601. }
  1602. break;
  1603. case DAY_OF_WEEK_IN_MONTH:
  1604. {
  1605. // may be in the Gregorian cutover month
  1606. int ndays, dow1;
  1607. int dow = date.getDayOfWeek();
  1608. if (!gc.isCutoverYear(normalizedYear)) {
  1609. BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
  1610. ndays = cal.getMonthLength(d);
  1611. d.setDayOfMonth(1);
  1612. cal.normalize(d);
  1613. dow1 = d.getDayOfWeek();
  1614. } else {
  1615. // Let a cloned GregorianCalendar take care of the cutover cases.
  1616. if (gc == this) {
  1617. gc = (GregorianCalendar) clone();
  1618. }
  1619. ndays = gc.actualMonthLength();
  1620. gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
  1621. dow1 = gc.get(DAY_OF_WEEK);
  1622. }
  1623. int x = dow - dow1;
  1624. if (x < 0) {
  1625. x += 7;
  1626. }
  1627. ndays -= x;
  1628. value = (ndays + 6) / 7;
  1629. }
  1630. break;
  1631. case YEAR:
  1632. /* The year computation is no different, in principle, from the
  1633. * others, however, the range of possible maxima is large. In
  1634. * addition, the way we know we've exceeded the range is different.
  1635. * For these reasons, we use the special case code below to handle
  1636. * this field.
  1637. *
  1638. * The actual maxima for YEAR depend on the type of calendar:
  1639. *
  1640. * Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
  1641. * Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE
  1642. * Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE
  1643. *
  1644. * We know we've exceeded the maximum when either the month, date,
  1645. * time, or era changes in response to setting the year. We don't
  1646. * check for month, date, and time here because the year and era are
  1647. * sufficient to detect an invalid year setting. NOTE: If code is
  1648. * added to check the month and date in the future for some reason,
  1649. * Feb 29 must be allowed to shift to Mar 1 when setting the year.
  1650. */
  1651. {
  1652. if (gc == this) {
  1653. gc = (GregorianCalendar) clone();
  1654. }
  1655. // Calculate the millisecond offset from the beginning
  1656. // of the year of this calendar and adjust the max
  1657. // year value if we are beyond the limit in the max
  1658. // year.
  1659. long current = gc.getYearOffsetInMillis();
  1660. if (gc.internalGetEra() == CE) {
  1661. gc.setTimeInMillis(Long.MAX_VALUE);
  1662. value = gc.get(YEAR);
  1663. long maxEnd = gc.getYearOffsetInMillis();
  1664. if (current > maxEnd) {
  1665. value--;
  1666. }
  1667. } else {
  1668. CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
  1669. gcal : getJulianCalendarSystem();
  1670. CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
  1671. long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
  1672. maxEnd *= 60;
  1673. maxEnd += d.getMinutes();
  1674. maxEnd *= 60;
  1675. maxEnd += d.getSeconds();
  1676. maxEnd *= 1000;
  1677. maxEnd += d.getMillis();
  1678. value = d.getYear();
  1679. if (value <= 0) {
  1680. assert mincal == gcal;
  1681. value = 1 - value;
  1682. }
  1683. if (current < maxEnd) {
  1684. value--;
  1685. }
  1686. }
  1687. }
  1688. break;
  1689. default:
  1690. throw new ArrayIndexOutOfBoundsException(field);
  1691. }
  1692. return value;
  1693. }
  1694. /**
  1695. * Returns the millisecond offset from the beginning of this
  1696. * year. This Calendar object must have been normalized.
  1697. */
  1698. private final long getYearOffsetInMillis() {
  1699. long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
  1700. t += internalGet(HOUR_OF_DAY);
  1701. t *= 60;
  1702. t += internalGet(MINUTE);
  1703. t *= 60;
  1704. t += internalGet(SECOND);
  1705. t *= 1000;
  1706. return t + internalGet(MILLISECOND) -
  1707. (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
  1708. }
  1709. public Object clone()
  1710. {
  1711. GregorianCalendar other = (GregorianCalendar) super.clone();
  1712. other.gdate = (BaseCalendar.Date) gdate.clone();
  1713. if (cdate != null) {
  1714. if (cdate != gdate) {
  1715. other.cdate = (BaseCalendar.Date) cdate.clone();
  1716. } else {
  1717. other.cdate = other.gdate;
  1718. }
  1719. }
  1720. other.originalFields = null;
  1721. other.zoneOffsets = null;
  1722. return other;
  1723. }
  1724. public TimeZone getTimeZone() {
  1725. TimeZone zone = super.getTimeZone();
  1726. // To share the zone by CalendarDates
  1727. gdate.setZone(zone);
  1728. if (cdate != null && cdate != gdate) {
  1729. cdate.setZone(zone);
  1730. }
  1731. return zone;
  1732. }
  1733. public void setTimeZone(TimeZone zone) {
  1734. super.setTimeZone(zone);
  1735. // To share the zone by CalendarDates
  1736. gdate.setZone(zone);
  1737. if (cdate != null && cdate != gdate) {
  1738. cdate.setZone(zone);
  1739. }
  1740. }
  1741. //////////////////////
  1742. // Proposed public API
  1743. //////////////////////
  1744. /**
  1745. * Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
  1746. * This may be one year before or after the Gregorian or Julian year stored
  1747. * in the <code>YEAR</code> field. For example, January 1, 1999 is considered
  1748. * Friday of week 53 of 1998 (if minimal days in first week is
  1749. * 2 or less, and the first day of the week is Sunday). Given
  1750. * these same settings, the ISO year of January 1, 1999 is
  1751. * 1998.
  1752. *
  1753. * <p>This method calls {@link Calendar#complete} before
  1754. * calculating the week-based year.
  1755. *
  1756. * @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
  1757. * may be one year before or after the <code>YEAR</code> field.
  1758. * @see #YEAR
  1759. * @see #WEEK_OF_YEAR
  1760. */
  1761. /*
  1762. public int getWeekBasedYear() {
  1763. complete();
  1764. // TODO: Below doesn't work for gregorian cutover...
  1765. int weekOfYear = internalGet(WEEK_OF_YEAR);
  1766. int year = internalGet(YEAR);
  1767. if (internalGet(MONTH) == Calendar.JANUARY) {
  1768. if (weekOfYear >= 52) {
  1769. --year;
  1770. }
  1771. } else {
  1772. if (weekOfYear == 1) {
  1773. ++year;
  1774. }
  1775. }
  1776. return year;
  1777. }
  1778. */
  1779. /////////////////////////////
  1780. // Time => Fields computation
  1781. /////////////////////////////
  1782. /**
  1783. * The fixed date corresponding to gdate. If the value is
  1784. * Long.MIN_VALUE, the fixed date value is unknown. Currently,
  1785. * Julian calendar dates are not cached.
  1786. */
  1787. transient private long cachedFixedDate = Long.MIN_VALUE;
  1788. /**
  1789. * Converts the time value (millisecond offset from the <a
  1790. * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
  1791. * The time is <em>not</em>
  1792. * recomputed first; to recompute the time, then the fields, call the
  1793. * <code>complete</code> method.
  1794. *
  1795. * @see Calendar#complete
  1796. */
  1797. protected void computeFields() {
  1798. int mask = 0;
  1799. if (isPartiallyNormalized()) {
  1800. // Determine which calendar fields need to be computed.
  1801. mask = getSetStateFields();
  1802. int fieldMask = ~mask & ALL_FIELDS;
  1803. mask |= computeFields(fieldMask,
  1804. (mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK))
  1805. == (ZONE_OFFSET_MASK|DST_OFFSET_MASK) ? fields : null,
  1806. ZONE_OFFSET);
  1807. assert mask == ALL_FIELDS;
  1808. } else {
  1809. // Specify all fields
  1810. mask = ALL_FIELDS;
  1811. computeFields(mask, null, 0);
  1812. }
  1813. // After computing all the fields, set the field state to `COMPUTED'.
  1814. setFieldsComputed(mask);
  1815. }
  1816. /**
  1817. * This computeFields implements the conversion from UTC
  1818. * (millisecond offset from the Epoch) to calendar
  1819. * field values. fieldMask specifies which fields to change the
  1820. * setting state to COMPUTED, although all fields are set to
  1821. * the correct values. This is required to fix 4685354.
  1822. *
  1823. * @param fieldMask a bit mask to specify which fields to change
  1824. * the setting state.
  1825. * @param offsets an <code>int</code> array having time zone
  1826. * offset values at 'time', or <code>null</code> if time zone
  1827. * offsets are not known. The <code>int</code> array must be
  1828. * either <code>zoneOffsets[]</code> or <code>fields[]</code>.
  1829. * @param index an index to <code>offsets[]</code>. Must be 0 for
  1830. * <code>zoneOffsets[]</code> or <code>ZONE_OFFSET</code> for
  1831. * <code>fields[]</code>.
  1832. * @return a new field mask that indicates what field values have
  1833. * actually been set.
  1834. */
  1835. private int computeFields(int fieldMask, int[] offsets, int index) {
  1836. int zoneOffset;
  1837. if (offsets != null) {
  1838. zoneOffset = offsets[index] + offsets[index + 1];
  1839. } else {
  1840. TimeZone tz = getZone();
  1841. if (zoneOffsets == null) {
  1842. zoneOffsets = new int[2];
  1843. }
  1844. if (tz instanceof ZoneInfo) {
  1845. zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
  1846. } else {
  1847. zoneOffset = tz.getOffset(time);
  1848. zoneOffsets[0] = tz.getRawOffset();
  1849. zoneOffsets[1] = zoneOffset - zoneOffsets[0];
  1850. }
  1851. }
  1852. // By computing time and zoneOffset separately, we can take
  1853. // the wider range of time+zoneOffset than the previous
  1854. // implementation.
  1855. long fixedDate = zoneOffset / ONE_DAY;
  1856. int timeOfDay = zoneOffset % (int)ONE_DAY;
  1857. fixedDate += time / ONE_DAY;
  1858. timeOfDay += (int) (time % ONE_DAY);
  1859. if (timeOfDay >= ONE_DAY) {
  1860. timeOfDay -= ONE_DAY;
  1861. ++fixedDate;
  1862. } else {
  1863. while (timeOfDay < 0) {
  1864. timeOfDay += ONE_DAY;
  1865. --fixedDate;
  1866. }
  1867. }
  1868. fixedDate += EPOCH_OFFSET;
  1869. int era = CE;
  1870. int year;
  1871. if (fixedDate >= gregorianCutoverDate) {
  1872. // Handle Gregorian dates.
  1873. assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
  1874. : "cache control: not normalized";
  1875. assert cachedFixedDate == Long.MIN_VALUE ||
  1876. gcal.getFixedDate(gdate.getNormalizedYear(),
  1877. gdate.getMonth(),
  1878. gdate.getDayOfMonth(), gdate)
  1879. == cachedFixedDate
  1880. : "cache control: inconsictency" +
  1881. ", cachedFixedDate=" + cachedFixedDate +
  1882. ", computed=" +
  1883. gcal.getFixedDate(gdate.getNormalizedYear(),
  1884. gdate.getMonth(),
  1885. gdate.getDayOfMonth(),
  1886. gdate) +
  1887. ", date=" + gdate;
  1888. // See if we can use gdate to avoid date calculation.
  1889. if (fixedDate != cachedFixedDate) {
  1890. gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
  1891. cachedFixedDate = fixedDate;
  1892. }
  1893. year = gdate.getYear();
  1894. if (year <= 0) {
  1895. year = 1 - year;
  1896. era = BCE;
  1897. }
  1898. calsys = gcal;
  1899. cdate = gdate;
  1900. assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
  1901. } else {
  1902. // Handle Julian calendar dates.
  1903. calsys = getJulianCalendarSystem();
  1904. cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
  1905. jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
  1906. Era e = cdate.getEra();
  1907. if (e == jeras[0]) {
  1908. era = BCE;
  1909. }
  1910. year = cdate.getYear();
  1911. }
  1912. // Always set the ERA and YEAR values.
  1913. internalSet(ERA, era);
  1914. internalSet(YEAR, year);
  1915. int mask = fieldMask | (ERA_MASK|YEAR_MASK);
  1916. int month = cdate.getMonth() - 1; // 0-based
  1917. int dayOfMonth = cdate.getDayOfMonth();
  1918. // Set the basic date fields.
  1919. if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
  1920. != 0) {
  1921. internalSet(MONTH, month);
  1922. internalSet(DAY_OF_MONTH, dayOfMonth);
  1923. internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
  1924. mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
  1925. }
  1926. if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
  1927. |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
  1928. if (timeOfDay != 0) {
  1929. int hours = timeOfDay / ONE_HOUR;
  1930. internalSet(HOUR_OF_DAY, hours);
  1931. internalSet(AM_PM, hours / 12); // Assume AM == 0
  1932. internalSet(HOUR, hours % 12);
  1933. int r = timeOfDay % ONE_HOUR;
  1934. internalSet(MINUTE, r / ONE_MINUTE);
  1935. r %= ONE_MINUTE;
  1936. internalSet(SECOND, r / ONE_SECOND);
  1937. internalSet(MILLISECOND, r % ONE_SECOND);
  1938. } else {
  1939. internalSet(HOUR_OF_DAY, 0);
  1940. internalSet(AM_PM, AM);
  1941. internalSet(HOUR, 0);
  1942. internalSet(MINUTE, 0);
  1943. internalSet(SECOND, 0);
  1944. internalSet(MILLISECOND, 0);
  1945. }
  1946. mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
  1947. |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
  1948. }
  1949. if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
  1950. // Avoid setting fields[] to fields[]
  1951. if (offsets != fields) {
  1952. internalSet(ZONE_OFFSET, zoneOffsets[0]);
  1953. internalSet(DST_OFFSET, zoneOffsets[1]);
  1954. }
  1955. mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
  1956. }
  1957. if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
  1958. int normalizedYear = cdate.getNormalizedYear();
  1959. long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
  1960. int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
  1961. long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
  1962. int cutoverGap = 0;
  1963. int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
  1964. int relativeDayOfMonth = dayOfMonth - 1;
  1965. // If we are in the cutover year, we need some special handling.
  1966. if (normalizedYear == cutoverYear) {
  1967. // Need to take care of the "missing" days.
  1968. if (getCutoverCalendarSystem() == jcal) {
  1969. // We need to find out where we are. The cutover
  1970. // gap could even be more than one year. (One
  1971. // year difference in ~48667 years.)
  1972. fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
  1973. if (fixedDate >= gregorianCutoverDate) {
  1974. fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
  1975. }
  1976. }
  1977. int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
  1978. cutoverGap = dayOfYear - realDayOfYear;
  1979. dayOfYear = realDayOfYear;
  1980. relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
  1981. }
  1982. internalSet(DAY_OF_YEAR, dayOfYear);
  1983. internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
  1984. int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
  1985. // The spec is to calculate WEEK_OF_YEAR in the
  1986. // ISO8601-style. This creates problems, though.
  1987. if (weekOfYear == 0) {
  1988. // If the date belongs to the last week of the
  1989. // previous year, use the week number of "12/31" of
  1990. // the "previous" year. Again, if the previous year is
  1991. // the Gregorian cutover year, we need to take care of
  1992. // it. Usually the previous day of January 1 is
  1993. // December 31, which is not always true in
  1994. // GregorianCalendar.
  1995. long fixedDec31 = fixedDateJan1 - 1;
  1996. long prevJan1;
  1997. if (normalizedYear > (cutoverYear + 1)) {
  1998. prevJan1 = fixedDateJan1 - 365;
  1999. if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
  2000. --prevJan1;
  2001. }
  2002. } else {
  2003. BaseCalendar calForJan1 = calsys;
  2004. int prevYear = normalizedYear - 1;
  2005. if (prevYear == cutoverYear) {
  2006. calForJan1 = getCutoverCalendarSystem();
  2007. }
  2008. prevJan1 = calForJan1.getFixedDate(prevYear,
  2009. BaseCalendar.JANUARY,
  2010. 1,
  2011. null);
  2012. while (prevJan1 > fixedDec31) {
  2013. prevJan1 = getJulianCalendarSystem().getFixedDate(--prevYear,
  2014. BaseCalendar.JANUARY,
  2015. 1,
  2016. null);
  2017. }
  2018. }
  2019. weekOfYear = getWeekNumber(prevJan1, fixedDec31);
  2020. } else {
  2021. if (normalizedYear > gregorianCutoverYear ||
  2022. normalizedYear < (gregorianCutoverYearJulian - 1)) {
  2023. // Regular years
  2024. if (weekOfYear >= 52) {
  2025. long nextJan1 = fixedDateJan1 + 365;
  2026. if (cdate.isLeapYear()) {
  2027. nextJan1++;
  2028. }
  2029. long nextJan1st = calsys.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
  2030. getFirstDayOfWeek());
  2031. int ndays = (int)(nextJan1st - nextJan1);
  2032. if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
  2033. // The first days forms a week in which the date is included.
  2034. weekOfYear = 1;
  2035. }
  2036. }
  2037. } else {
  2038. BaseCalendar calForJan1 = calsys;
  2039. int nextYear = normalizedYear + 1;
  2040. if (nextYear == (gregorianCutoverYearJulian + 1) &&
  2041. nextYear < gregorianCutoverYear) {
  2042. // In case the gap is more than one year.
  2043. nextYear = gregorianCutoverYear;
  2044. }
  2045. if (nextYear == gregorianCutoverYear) {
  2046. calForJan1 = getCutoverCalendarSystem();
  2047. }
  2048. long nextJan1 = calForJan1.getFixedDate(nextYear,
  2049. BaseCalendar.JANUARY,
  2050. 1,
  2051. null);
  2052. if (nextJan1 < fixedDate) {
  2053. nextJan1 = gregorianCutoverDate;
  2054. calForJan1 = gcal;
  2055. }
  2056. long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
  2057. getFirstDayOfWeek());
  2058. int ndays = (int)(nextJan1st - nextJan1);
  2059. if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
  2060. // The first days forms a week in which the date is included.
  2061. weekOfYear = 1;
  2062. }
  2063. }
  2064. }
  2065. internalSet(WEEK_OF_YEAR, weekOfYear);
  2066. internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
  2067. mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
  2068. }
  2069. return mask;
  2070. }
  2071. /**
  2072. * Returns the number of weeks in a period between fixedDay1 and
  2073. * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
  2074. * is applied to calculate the number of weeks.
  2075. *
  2076. * @param fixedDay1 the fixed date of the first day of the period
  2077. * @param fixedDate the fixed date of the last day of the period
  2078. * @return the number of weeks of the given period
  2079. */
  2080. private final int getWeekNumber(long fixedDay1, long fixedDate) {
  2081. // We can always use `gcal' since Julian and Gregorian are the
  2082. // same thing for this calculation.
  2083. long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
  2084. getFirstDayOfWeek());
  2085. int ndays = (int)(fixedDay1st - fixedDay1);
  2086. assert ndays <= 7;
  2087. if (ndays >= getMinimalDaysInFirstWeek()) {
  2088. fixedDay1st -= 7;
  2089. }
  2090. int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
  2091. if (normalizedDayOfPeriod >= 0) {
  2092. return normalizedDayOfPeriod / 7 + 1;
  2093. }
  2094. return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
  2095. }
  2096. /**
  2097. * Converts calendar field values to the time value (millisecond
  2098. * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
  2099. *
  2100. * @exception IllegalArgumentException if any calendar fields are invalid.
  2101. */
  2102. protected void computeTime() {
  2103. // In non-lenient mode, perform brief checking of calendar
  2104. // fields which have been set externally. Through this
  2105. // checking, the field values are stored in originalFields[]
  2106. // to see if any of them are normalized later.
  2107. if (!isLenient()) {
  2108. if (originalFields == null) {
  2109. originalFields = new int[FIELD_COUNT];
  2110. }
  2111. for (int field = 0; field < FIELD_COUNT; field++) {
  2112. int value = internalGet(field);
  2113. if (isExternallySet(field)) {
  2114. // Quick validation for any out of range values
  2115. if (value < getMinimum(field) || value > getMaximum(field)) {
  2116. throw new IllegalArgumentException(getFieldName(field));
  2117. }
  2118. }
  2119. originalFields[field] = value;
  2120. }
  2121. }
  2122. // Let the super class determine which calendar fields to be
  2123. // used to calculate the time.
  2124. int fieldMask = selectFields();
  2125. // The year defaults to the epoch start. We don't check
  2126. // fieldMask for YEAR because YEAR is a mandatory field to
  2127. // determine the date.
  2128. int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
  2129. int era = internalGetEra();
  2130. if (era == BCE) {
  2131. year = 1 - year;
  2132. } else if (era != CE) {
  2133. // Even in lenient mode we disallow ERA values other than CE & BCE.
  2134. // (The same normalization rule as add()/roll() could be
  2135. // applied here in lenient mode. But this checking is kept
  2136. // unchanged for compatibility as of 1.5.)
  2137. throw new IllegalArgumentException("Invalid era");
  2138. }
  2139. // If year is 0 or negative, we need to set the ERA value later.
  2140. if (year <= 0 && !isSet(ERA)) {
  2141. fieldMask |= ERA_MASK;
  2142. setFieldsComputed(ERA_MASK);
  2143. }
  2144. // Calculate the time of day. We rely on the convention that
  2145. // an UNSET field has 0.
  2146. long timeOfDay = 0;
  2147. if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
  2148. timeOfDay += (long) internalGet(HOUR_OF_DAY);
  2149. } else {
  2150. timeOfDay += internalGet(HOUR);
  2151. // The default value of AM_PM is 0 which designates AM.
  2152. if (isFieldSet(fieldMask, AM_PM)) {
  2153. timeOfDay += 12 * internalGet(AM_PM);
  2154. }
  2155. }
  2156. timeOfDay *= 60;
  2157. timeOfDay += internalGet(MINUTE);
  2158. timeOfDay *= 60;
  2159. timeOfDay += internalGet(SECOND);
  2160. timeOfDay *= 1000;
  2161. timeOfDay += internalGet(MILLISECOND);
  2162. // Convert the time of day to the number of days and the
  2163. // millisecond offset from midnight.
  2164. long fixedDate = timeOfDay / ONE_DAY;
  2165. timeOfDay %= ONE_DAY;
  2166. while (timeOfDay < 0) {
  2167. timeOfDay += ONE_DAY;
  2168. --fixedDate;
  2169. }
  2170. // Calculate the fixed date since January 1, 1 (Gregorian).
  2171. calculateFixedDate: {
  2172. long gfd, jfd;
  2173. if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
  2174. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  2175. if (gfd >= gregorianCutoverDate) {
  2176. fixedDate = gfd;
  2177. break calculateFixedDate;
  2178. }
  2179. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  2180. } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
  2181. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  2182. if (jfd < gregorianCutoverDate) {
  2183. fixedDate = jfd;
  2184. break calculateFixedDate;
  2185. }
  2186. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  2187. } else {
  2188. gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
  2189. jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
  2190. }
  2191. // Now we have to determine which calendar date it is.
  2192. if (gfd >= gregorianCutoverDate) {
  2193. if (jfd >= gregorianCutoverDate) {
  2194. fixedDate = gfd;
  2195. } else {
  2196. // The date is in an "overlapping" period. No way
  2197. // to disambiguate it. Determine it using the
  2198. // previous date calculation.
  2199. if (calsys == gcal || calsys == null) {
  2200. fixedDate = gfd;
  2201. } else {
  2202. fixedDate = jfd;
  2203. }
  2204. }
  2205. } else {
  2206. if (jfd < gregorianCutoverDate) {
  2207. fixedDate = jfd;
  2208. } else {
  2209. // The date is in a "missing" period.
  2210. if (!isLenient()) {
  2211. throw new IllegalArgumentException("the specified date doesn't exist");
  2212. }
  2213. // Take the Julian date for compatibility, which
  2214. // will produce a Gregorian date.
  2215. fixedDate = jfd;
  2216. }
  2217. }
  2218. }
  2219. // millis represents local wall-clock time in milliseconds.
  2220. long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
  2221. // Compute the time zone offset and DST offset. There are two potential
  2222. // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
  2223. // for discussion purposes here.
  2224. // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
  2225. // can be in standard or in DST depending. However, 2:00 am is an invalid
  2226. // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
  2227. // We assume standard time.
  2228. // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
  2229. // can be in standard or DST. Both are valid representations (the rep
  2230. // jumps from 1:59:59 DST to 1:00:00 Std).
  2231. // Again, we assume standard time.
  2232. // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  2233. // or DST_OFFSET fields; then we use those fields.
  2234. TimeZone zone = getZone();
  2235. if (zoneOffsets == null) {
  2236. zoneOffsets = new int[2];
  2237. }
  2238. if (zone instanceof ZoneInfo) {
  2239. if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK))
  2240. != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
  2241. ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
  2242. }
  2243. if (isFieldSet(fieldMask, ZONE_OFFSET)) {
  2244. zoneOffsets[0] = internalGet(ZONE_OFFSET);
  2245. }
  2246. if (isFieldSet(fieldMask, DST_OFFSET)) {
  2247. zoneOffsets[1] = internalGet(DST_OFFSET);
  2248. }
  2249. } else {
  2250. zoneOffsets[0] = isFieldSet(fieldMask, ZONE_OFFSET) ?
  2251. internalGet(ZONE_OFFSET) : zone.getRawOffset();
  2252. if (isFieldSet(fieldMask, DST_OFFSET)) {
  2253. zoneOffsets[1] = internalGet(DST_OFFSET);
  2254. } else {
  2255. zoneOffsets[1] = zone.getOffsets(millis - (long)zoneOffsets[0], null)
  2256. - zoneOffsets[0];
  2257. }
  2258. }
  2259. // Adjust the time zone offset values to get the UTC time.
  2260. millis -= zoneOffsets[0] + zoneOffsets[1];
  2261. // Set this calendar's time in milliseconds
  2262. time = millis;
  2263. int mask = computeFields(fieldMask | getSetStateFields(), null, 0);
  2264. if (!isLenient()) {
  2265. for (int field = 0; field < FIELD_COUNT; field++) {
  2266. if (!isExternallySet(field)) {
  2267. continue;
  2268. }
  2269. if (originalFields[field] != internalGet(field)) {
  2270. // Restore the original field values
  2271. System.arraycopy(originalFields, 0, fields, 0, fields.length);
  2272. throw new IllegalArgumentException(getFieldName(field));
  2273. }
  2274. }
  2275. }
  2276. setFieldsNormalized(mask);
  2277. }
  2278. /**
  2279. * Computes the fixed date under either the Gregorian or the
  2280. * Julian calendar, using the given year and the specified calendar fields.
  2281. *
  2282. * @param cal the CalendarSystem to be used for the date calculation
  2283. * @param year the normalized year number, with 0 indicating the
  2284. * year 1 BCE, -1 indicating 2 BCE, etc.
  2285. * @param fieldMask the calendar fields to be used for the date calculation
  2286. * @return the fixed date
  2287. * @see Calendar#selectFields
  2288. */
  2289. private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
  2290. int month = JANUARY;
  2291. if (isFieldSet(fieldMask, MONTH)) {
  2292. // No need to check if MONTH has been set (no isSet(MONTH)
  2293. // call) since its unset value happens to be JANUARY (0).
  2294. month = internalGet(MONTH);
  2295. // If the month is out of range, adjust it into range
  2296. if (month > DECEMBER) {
  2297. year += month / 12;
  2298. month %= 12;
  2299. } else if (month < JANUARY) {
  2300. int[] rem = new int[1];
  2301. year += CalendarUtils.floorDivide(month, 12, rem);
  2302. month = rem[0];
  2303. }
  2304. }
  2305. // Get the fixed date since Jan 1, 1 (Gregorian). We are on
  2306. // the first day of either `month' or January in 'year'.
  2307. long fixedDate = cal.getFixedDate(year, month + 1, 1,
  2308. cal == gcal ? gdate : null);
  2309. if (isFieldSet(fieldMask, MONTH)) {
  2310. // Month-based calculations
  2311. if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
  2312. // We are on the first day of the month. Just add the
  2313. // offset if DAY_OF_MONTH is set. If the isSet call
  2314. // returns false, that means DAY_OF_MONTH has been
  2315. // selected just because of the selected
  2316. // combination. We don't need to add any since the
  2317. // default value is the 1st.
  2318. if (isSet(DAY_OF_MONTH)) {
  2319. // To avoid underflow with DAY_OF_MONTH-1, add
  2320. // DAY_OF_MONTH, then subtract 1.
  2321. fixedDate += internalGet(DAY_OF_MONTH);
  2322. fixedDate--;
  2323. }
  2324. } else {
  2325. if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
  2326. long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
  2327. getFirstDayOfWeek());
  2328. // If we have enough days in the first week, then
  2329. // move to the previous week.
  2330. if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
  2331. firstDayOfWeek -= 7;
  2332. }
  2333. if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
  2334. firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
  2335. internalGet(DAY_OF_WEEK));
  2336. }
  2337. // In lenient mode, we treat days of the previous
  2338. // months as a part of the specified
  2339. // WEEK_OF_MONTH. See 4633646.
  2340. fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
  2341. } else {
  2342. int dayOfWeek;
  2343. if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
  2344. dayOfWeek = internalGet(DAY_OF_WEEK);
  2345. } else {
  2346. dayOfWeek = getFirstDayOfWeek();
  2347. }
  2348. // We are basing this on the day-of-week-in-month. The only
  2349. // trickiness occurs if the day-of-week-in-month is
  2350. // negative.
  2351. int dowim;
  2352. if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
  2353. dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
  2354. } else {
  2355. dowim = 1;
  2356. }
  2357. if (dowim >= 0) {
  2358. fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
  2359. dayOfWeek);
  2360. } else {
  2361. // Go to the first day of the next week of
  2362. // the specified week boundary.
  2363. int lastDate = monthLength(month, year) + (7 * (dowim + 1));
  2364. // Then, get the day of week date on or before the last date.
  2365. fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
  2366. dayOfWeek);
  2367. }
  2368. }
  2369. }
  2370. } else {
  2371. if (year == gregorianCutoverYear && cal == gcal
  2372. && fixedDate < gregorianCutoverDate
  2373. && gregorianCutoverYear != gregorianCutoverYearJulian) {
  2374. // January 1 of the year doesn't exist. Use
  2375. // gregorianCutoverDate as the first day of the
  2376. // year.
  2377. fixedDate = gregorianCutoverDate;
  2378. }
  2379. // We are on the first day of the year.
  2380. if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
  2381. // Add the offset, then subtract 1. (Make sure to avoid underflow.)
  2382. fixedDate += internalGet(DAY_OF_YEAR);
  2383. fixedDate--;
  2384. } else {
  2385. long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
  2386. getFirstDayOfWeek());
  2387. // If we have enough days in the first week, then move
  2388. // to the previous week.
  2389. if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
  2390. firstDayOfWeek -= 7;
  2391. }
  2392. if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
  2393. int dayOfWeek = internalGet(DAY_OF_WEEK);
  2394. if (dayOfWeek != getFirstDayOfWeek()) {
  2395. firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
  2396. dayOfWeek);
  2397. }
  2398. }
  2399. fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
  2400. }
  2401. }
  2402. return fixedDate;
  2403. }
  2404. /**
  2405. * Returns this object if it's normalized (all fields and time are
  2406. * in sync). Otherwise, a cloned object is returned after calling
  2407. * complete() in lenient mode.
  2408. */
  2409. private final GregorianCalendar getNormalizedCalendar() {
  2410. GregorianCalendar gc;
  2411. if (isFullyNormalized()) {
  2412. gc = this;
  2413. } else {
  2414. // Create a clone and normalize the calendar fields
  2415. gc = (GregorianCalendar) this.clone();
  2416. gc.setLenient(true);
  2417. gc.complete();
  2418. }
  2419. return gc;
  2420. }
  2421. /**
  2422. * Returns the Julian calendar system instance (singleton). 'jcal'
  2423. * and 'jeras' are set upon the return.
  2424. */
  2425. synchronized private static final BaseCalendar getJulianCalendarSystem() {
  2426. if (jcal == null) {
  2427. jcal = (JulianCalendar) CalendarSystem.forName("julian");
  2428. jeras = jcal.getEras();
  2429. }
  2430. return jcal;
  2431. }
  2432. /**
  2433. * Returns the calendar system for dates before the cutover date
  2434. * in the cutover year. If the cutover date is January 1, the
  2435. * method returns Gregorian. Otherwise, Julian.
  2436. */
  2437. private BaseCalendar getCutoverCalendarSystem() {
  2438. CalendarDate date = getGregorianCutoverDate();
  2439. if (date.getMonth() == BaseCalendar.JANUARY
  2440. && date.getDayOfMonth() == 1) {
  2441. return gcal;
  2442. }
  2443. return getJulianCalendarSystem();
  2444. }
  2445. /**
  2446. * Determines if the specified year (normalized) is the Gregorian
  2447. * cutover year. This object must have been normalized.
  2448. */
  2449. private final boolean isCutoverYear(int normalizedYear) {
  2450. int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
  2451. return normalizedYear == cutoverYear;
  2452. }
  2453. /**
  2454. * Returns the fixed date of the first day of the year (usually
  2455. * January 1) before the specified date.
  2456. *
  2457. * @param date the date for which the first day of the year is
  2458. * calculated. The date has to be in the cut-over year (Gregorian
  2459. * or Julian).
  2460. * @param fixedDate the fixed date representation of the date
  2461. */
  2462. private final long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
  2463. assert date.getNormalizedYear() == gregorianCutoverYear ||
  2464. date.getNormalizedYear() == gregorianCutoverYearJulian;
  2465. if (gregorianCutoverYear != gregorianCutoverYearJulian) {
  2466. if (fixedDate >= gregorianCutoverDate) {
  2467. // Dates before the cutover date don't exist
  2468. // in the same (Gregorian) year. So, no
  2469. // January 1 exists in the year. Use the
  2470. // cutover date as the first day of the year.
  2471. return gregorianCutoverDate;
  2472. }
  2473. }
  2474. // January 1 of the normalized year should exist.
  2475. BaseCalendar jcal = getJulianCalendarSystem();
  2476. return jcal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
  2477. }
  2478. /**
  2479. * Returns the fixed date of the first date of the month (usually
  2480. * the 1st of the month) before the specified date.
  2481. *
  2482. * @param date the date for which the first day of the month is
  2483. * calculated. The date has to be in the cut-over year (Gregorian
  2484. * or Julian).
  2485. * @param fixedDate the fixed date representation of the date
  2486. */
  2487. private final long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
  2488. assert date.getNormalizedYear() == gregorianCutoverYear ||
  2489. date.getNormalizedYear() == gregorianCutoverYearJulian;
  2490. BaseCalendar.Date gCutover = getGregorianCutoverDate();
  2491. if (gCutover.getMonth() == BaseCalendar.JANUARY
  2492. && gCutover.getDayOfMonth() == 1) {
  2493. // The cutover happened on January 1.
  2494. return fixedDate - date.getDayOfMonth() + 1;
  2495. }
  2496. long fixedDateMonth1;
  2497. // The cutover happened sometime during the year.
  2498. if (date.getMonth() == gCutover.getMonth()) {
  2499. // The cutover happened in the month.
  2500. BaseCalendar.Date jLastDate = getLastJulianDate();
  2501. if (gregorianCutoverYear == gregorianCutoverYearJulian
  2502. && gCutover.getMonth() == jLastDate.getMonth()) {
  2503. // The "gap" fits in the same month.
  2504. fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
  2505. date.getMonth(),
  2506. 1,
  2507. null);
  2508. } else {
  2509. // Use the cutover date as the first day of the month.
  2510. fixedDateMonth1 = gregorianCutoverDate;
  2511. }
  2512. } else {
  2513. // The cutover happened before the month.
  2514. fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
  2515. }
  2516. return fixedDateMonth1;
  2517. }
  2518. /**
  2519. * Returns a CalendarDate produced from the specified fixed date.
  2520. *
  2521. * @param fd the fixed date
  2522. */
  2523. private final BaseCalendar.Date getCalendarDate(long fd) {
  2524. BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
  2525. BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  2526. cal.getCalendarDateFromFixedDate(d, fd);
  2527. return d;
  2528. }
  2529. /**
  2530. * Returns the Gregorian cutover date as a BaseCalendar.Date. The
  2531. * date is a Gregorian date.
  2532. */
  2533. private final BaseCalendar.Date getGregorianCutoverDate() {
  2534. return getCalendarDate(gregorianCutoverDate);
  2535. }
  2536. /**
  2537. * Returns the day before the Gregorian cutover date as a
  2538. * BaseCalendar.Date. The date is a Julian date.
  2539. */
  2540. private final BaseCalendar.Date getLastJulianDate() {
  2541. return getCalendarDate(gregorianCutoverDate - 1);
  2542. }
  2543. /**
  2544. * Returns the length of the specified month in the specified
  2545. * year. The year number must be normalized.
  2546. *
  2547. * @see #isLeapYear(int)
  2548. */
  2549. private final int monthLength(int month, int year) {
  2550. return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
  2551. }
  2552. /**
  2553. * Returns the length of the specified month in the year provided
  2554. * by internalGet(YEAR).
  2555. *
  2556. * @see #isLeapYear(int)
  2557. */
  2558. private final int monthLength(int month) {
  2559. int year = internalGet(YEAR);
  2560. if (internalGetEra() == BCE) {
  2561. year = 1 - year;
  2562. }
  2563. return monthLength(month, year);
  2564. }
  2565. private final int actualMonthLength() {
  2566. int year = cdate.getNormalizedYear();
  2567. if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
  2568. return calsys.getMonthLength(cdate);
  2569. }
  2570. BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
  2571. long fd = calsys.getFixedDate(date);
  2572. long month1 = getFixedDateMonth1(date, fd);
  2573. long next1 = month1 + calsys.getMonthLength(date);
  2574. if (next1 < gregorianCutoverDate) {
  2575. return (int)(next1 - month1);
  2576. }
  2577. if (cdate != gdate) {
  2578. date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
  2579. }
  2580. gcal.getCalendarDateFromFixedDate(date, next1);
  2581. next1 = getFixedDateMonth1(date, next1);
  2582. return (int)(next1 - month1);
  2583. }
  2584. /**
  2585. * Returns the length (in days) of the specified year. The year
  2586. * must be normalized.
  2587. */
  2588. private final int yearLength(int year) {
  2589. return isLeapYear(year) ? 366 : 365;
  2590. }
  2591. /**
  2592. * Returns the length (in days) of the year provided by
  2593. * internalGet(YEAR).
  2594. */
  2595. private final int yearLength() {
  2596. int year = internalGet(YEAR);
  2597. if (internalGetEra() == BCE) {
  2598. year = 1 - year;
  2599. }
  2600. return yearLength(year);
  2601. }
  2602. /**
  2603. * After adjustments such as add(MONTH), add(YEAR), we don't want the
  2604. * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
  2605. * 3, we want it to go to Feb 28. Adjustments which might run into this
  2606. * problem call this method to retain the proper month.
  2607. */
  2608. private final void pinDayOfMonth() {
  2609. int year = internalGet(YEAR);
  2610. int monthLen;
  2611. if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
  2612. monthLen = monthLength(internalGet(MONTH));
  2613. } else {
  2614. GregorianCalendar gc = getNormalizedCalendar();
  2615. monthLen = gc.getActualMaximum(DAY_OF_MONTH);
  2616. }
  2617. int dom = internalGet(DAY_OF_MONTH);
  2618. if (dom > monthLen) {
  2619. set(DAY_OF_MONTH, monthLen);
  2620. }
  2621. }
  2622. /**
  2623. * Returns the fixed date value of this object. The time value and
  2624. * calendar fields must be in synch.
  2625. */
  2626. private final long getCurrentFixedDate() {
  2627. assert isTimeSet && areFieldsSet
  2628. && ((calsys == gcal) ? cachedFixedDate != Long.MIN_VALUE : true);
  2629. return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
  2630. }
  2631. /**
  2632. * Returns the new value after 'roll'ing the specified value and amount.
  2633. */
  2634. private static final int getRolledValue(int value, int amount, int min, int max) {
  2635. assert value >= min && value <= max;
  2636. int range = max - min + 1;
  2637. amount %= range;
  2638. int n = value + amount;
  2639. if (n > max) {
  2640. n -= range;
  2641. } else if (n < min) {
  2642. n += range;
  2643. }
  2644. assert n >= min && n <= max;
  2645. return n;
  2646. }
  2647. /**
  2648. * Returns the ERA. We need a special method for this because the
  2649. * default ERA is CE, but a zero (unset) ERA is BCE.
  2650. */
  2651. private final int internalGetEra() {
  2652. return isSet(ERA) ? internalGet(ERA) : CE;
  2653. }
  2654. /**
  2655. * Updates internal state.
  2656. */
  2657. private void readObject(ObjectInputStream stream)
  2658. throws IOException, ClassNotFoundException {
  2659. stream.defaultReadObject();
  2660. if (gdate == null) {
  2661. gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
  2662. cachedFixedDate = Long.MIN_VALUE;
  2663. }
  2664. setGregorianChange(gregorianCutover);
  2665. }
  2666. }