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