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