1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2013, 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</code> is a concrete subclass of 58 * <code>Calendar</code> and provides the standard calendar system 59 * used by most of the world. 60 * 61 * <p> <code>GregorianCalendar</code> 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</code> 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</code> 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</code> may be used for all years to generate 83 * meaningful and consistent results. However, dates obtained using 84 * <code>GregorianCalendar</code> 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 * <h3><a id="week_and_year">Week Of Year and Week Year</a></h3> 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 * <h4>Week Of Month</h4> 138 * 139 * <p>Values calculated for the <code>WEEK_OF_MONTH</code> 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()</code> contiguous days in that month, 143 * ending on the day before <code>getFirstDayOfWeek()</code>. 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()</code>, and will not include days of 146 * the previous month. Days of a month before week 1 have a 147 * <code>WEEK_OF_MONTH</code> of 0. 148 * 149 * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code> 150 * and <code>getMinimalDaysInFirstWeek()</code> 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</code> of 1. Thursday, January 1 through 153 * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If 154 * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1 155 * through January 3 have a <code>WEEK_OF_MONTH</code> of 1. 156 * 157 * <h4>Default Fields Values</h4> 158 * 159 * <p>The <code>clear</code> method sets calendar field(s) 160 * undefined. <code>GregorianCalendar</code> 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</code> 179 * </th> 180 * <td> 181 * <code>AD</code> 182 * </td> 183 * </tr> 184 * <tr> 185 * <th scope="row"> 186 * <code>YEAR</code> 187 * </th> 188 * <td> 189 * <code>1970</code> 190 * </td> 191 * </tr> 192 * <tr> 193 * <th scope="row"> 194 * <code>MONTH</code> 195 * </th> 196 * <td> 197 * <code>JANUARY</code> 198 * </td> 199 * </tr> 200 * <tr> 201 * <th scope="row"> 202 * <code>DAY_OF_MONTH</code> 203 * </th> 204 * <td> 205 * <code>1</code> 206 * </td> 207 * </tr> 208 * <tr> 209 * <th scope="row"> 210 * <code>DAY_OF_WEEK</code> 211 * </th> 212 * <td> 213 * <code>the first day of week</code> 214 * </td> 215 * </tr> 216 * <tr> 217 * <th scope="row"> 218 * <code>WEEK_OF_MONTH</code> 219 * </th> 220 * <td> 221 * <code>0</code> 222 * </td> 223 * </tr> 224 * <tr> 225 * <th scope="row"> 226 * <code>DAY_OF_WEEK_IN_MONTH</code> 227 * </th> 228 * <td> 229 * <code>1</code> 230 * </td> 231 * </tr> 232 * <tr> 233 * <th scope="row"> 234 * <code>AM_PM</code> 235 * </th> 236 * <td> 237 * <code>AM</code> 238 * </td> 239 * </tr> 240 * <tr> 241 * <th scope="row"> 242 * <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code> 243 * </th> 244 * <td> 245 * <code>0</code> 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 301 * System.out.println("Current Time, with hour reset to 3"); 302 * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override 303 * calendar.set(Calendar.HOUR, 3); 304 * System.out.println("ERA: " + calendar.get(Calendar.ERA)); 305 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR)); 306 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH)); 307 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR)); 308 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH)); 309 * System.out.println("DATE: " + calendar.get(Calendar.DATE)); 310 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH)); 311 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR)); 312 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK)); 313 * System.out.println("DAY_OF_WEEK_IN_MONTH: " 314 * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH)); 315 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM)); 316 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR)); 317 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY)); 318 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE)); 319 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND)); 320 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND)); 321 * System.out.println("ZONE_OFFSET: " 322 * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours 323 * System.out.println("DST_OFFSET: " 324 * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours 325 * </pre> 326 * </blockquote> 327 * 328 * @see TimeZone 329 * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu 330 * @since 1.1 331 */ 332 public class GregorianCalendar extends Calendar { 333 /* 334 * Implementation Notes 335 * 336 * The epoch is the number of days or milliseconds from some defined 337 * starting point. The epoch for java.util.Date is used here; that is, 338 * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other 339 * epochs which are used are January 1, year 1 (Gregorian), which is day 1 340 * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is 341 * day 1 of the Julian calendar. 342 * 343 * We implement the proleptic Julian and Gregorian calendars. This means we 344 * implement the modern definition of the calendar even though the 345 * historical usage differs. For example, if the Gregorian change is set 346 * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which 347 * labels dates preceding the invention of the Gregorian calendar in 1582 as 348 * if the calendar existed then. 349 * 350 * Likewise, with the Julian calendar, we assume a consistent 351 * 4-year leap year rule, even though the historical pattern of 352 * leap years is irregular, being every 3 years from 45 BCE 353 * through 9 BCE, then every 4 years from 8 CE onwards, with no 354 * leap years in-between. Thus date computations and functions 355 * such as isLeapYear() are not intended to be historically 356 * accurate. 357 */ 358 359 ////////////////// 360 // Class Variables 361 ////////////////// 362 363 /** 364 * Value of the <code>ERA</code> field indicating 365 * the period before the common era (before Christ), also known as BCE. 366 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is 367 * ..., 2 BC, 1 BC, 1 AD, 2 AD,... 368 * 369 * @see #ERA 370 */ 371 public static final int BC = 0; 372 373 /** 374 * Value of the {@link #ERA} field indicating 375 * the period before the common era, the same value as {@link #BC}. 376 * 377 * @see #CE 378 */ 379 static final int BCE = 0; 380 381 /** 382 * Value of the <code>ERA</code> field indicating 383 * the common era (Anno Domini), also known as CE. 384 * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is 385 * ..., 2 BC, 1 BC, 1 AD, 2 AD,... 386 * 387 * @see #ERA 388 */ 389 public static final int AD = 1; 390 391 /** 392 * Value of the {@link #ERA} field indicating 393 * the common era, the same value as {@link #AD}. 394 * 395 * @see #BCE 396 */ 397 static final int CE = 1; 398 399 private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian) 400 private static final int EPOCH_YEAR = 1970; 401 402 static final int MONTH_LENGTH[] 403 = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based 404 static final int LEAP_MONTH_LENGTH[] 405 = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based 406 407 // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit 408 // into ints, they must be longs in order to prevent arithmetic overflow 409 // when performing (bug 4173516). 410 private static final int ONE_SECOND = 1000; 411 private static final int ONE_MINUTE = 60*ONE_SECOND; 412 private static final int ONE_HOUR = 60*ONE_MINUTE; 413 private static final long ONE_DAY = 24*ONE_HOUR; 414 private static final long ONE_WEEK = 7*ONE_DAY; 415 416 /* 417 * <pre> 418 * Greatest Least 419 * Field name Minimum Minimum Maximum Maximum 420 * ---------- ------- ------- ------- ------- 421 * ERA 0 0 1 1 422 * YEAR 1 1 292269054 292278994 423 * MONTH 0 0 11 11 424 * WEEK_OF_YEAR 1 1 52* 53 425 * WEEK_OF_MONTH 0 0 4* 6 426 * DAY_OF_MONTH 1 1 28* 31 427 * DAY_OF_YEAR 1 1 365* 366 428 * DAY_OF_WEEK 1 1 7 7 429 * DAY_OF_WEEK_IN_MONTH 1 1 4* 6 430 * AM_PM 0 0 1 1 431 * HOUR 0 0 11 11 432 * HOUR_OF_DAY 0 0 23 23 433 * MINUTE 0 0 59 59 434 * SECOND 0 0 59 59 435 * MILLISECOND 0 0 999 999 436 * ZONE_OFFSET -13:00 -13:00 14:00 14:00 437 * DST_OFFSET 0:00 0:00 0:20 2:00 438 * </pre> 439 * *: depends on the Gregorian change date 440 */ 441 static final int MIN_VALUES[] = { 442 BCE, // ERA 443 1, // YEAR 444 JANUARY, // MONTH 445 1, // WEEK_OF_YEAR 446 0, // WEEK_OF_MONTH 447 1, // DAY_OF_MONTH 448 1, // DAY_OF_YEAR 449 SUNDAY, // DAY_OF_WEEK 450 1, // DAY_OF_WEEK_IN_MONTH 451 AM, // AM_PM 452 0, // HOUR 453 0, // HOUR_OF_DAY 454 0, // MINUTE 455 0, // SECOND 456 0, // MILLISECOND 457 -13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility) 458 0 // DST_OFFSET 459 }; 460 static final int LEAST_MAX_VALUES[] = { 461 CE, // ERA 462 292269054, // YEAR 463 DECEMBER, // MONTH 464 52, // WEEK_OF_YEAR 465 4, // WEEK_OF_MONTH 466 28, // DAY_OF_MONTH 467 365, // DAY_OF_YEAR 468 SATURDAY, // DAY_OF_WEEK 469 4, // DAY_OF_WEEK_IN 470 PM, // AM_PM 471 11, // HOUR 472 23, // HOUR_OF_DAY 473 59, // MINUTE 474 59, // SECOND 475 999, // MILLISECOND 476 14*ONE_HOUR, // ZONE_OFFSET 477 20*ONE_MINUTE // DST_OFFSET (historical least maximum) 478 }; 479 static final int MAX_VALUES[] = { 480 CE, // ERA 481 292278994, // YEAR 482 DECEMBER, // MONTH 483 53, // WEEK_OF_YEAR 484 6, // WEEK_OF_MONTH 485 31, // DAY_OF_MONTH 486 366, // DAY_OF_YEAR 487 SATURDAY, // DAY_OF_WEEK 488 6, // DAY_OF_WEEK_IN 489 PM, // AM_PM 490 11, // HOUR 491 23, // HOUR_OF_DAY 492 59, // MINUTE 493 59, // SECOND 494 999, // MILLISECOND 495 14*ONE_HOUR, // ZONE_OFFSET 496 2*ONE_HOUR // DST_OFFSET (double summer time) 497 }; 498 499 // Proclaim serialization compatibility with JDK 1.1 500 @SuppressWarnings("FieldNameHidesFieldInSuperclass") 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</code> 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</code> 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</code> 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</code> 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</code> 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</code> calendar field in the calendar. 637 * @param month the value used to set the <code>MONTH</code> 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</code> 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</code> 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</code> calendar field in the calendar. 650 * @param month the value used to set the <code>MONTH</code> 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</code> calendar field in the calendar. 653 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field 654 * in the calendar. 655 * @param minute the value used to set the <code>MINUTE</code> 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</code> calendar field in the calendar. 668 * @param month the value used to set the <code>MONTH</code> 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</code> calendar field in the calendar. 671 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field 672 * in the calendar. 673 * @param minute the value used to set the <code>MINUTE</code> calendar field 674 * in the calendar. 675 * @param second the value used to set the <code>SECOND</code> 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</code> 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</code> calendar field in the calendar. 688 * @param month the value used to set the <code>MONTH</code> 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</code> calendar field in the calendar. 691 * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field 692 * in the calendar. 693 * @param minute the value used to set the <code>MINUTE</code> calendar field 694 * in the calendar. 695 * @param second the value used to set the <code>SECOND</code> calendar field 696 * in the calendar. 697 * @param millis the value used to set the <code>MILLISECOND</code> 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 aLocale 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</code> 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)</code>. To obtain a pure Gregorian calendar, 761 * set the change date to <code>Date(Long.MIN_VALUE)</code>. 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</code> 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</code> if 821 * the given year is a leap year. To specify BC year numbers, 822 * <code>1 - year number</code> must be given. For example, year BC 4 is 823 * specified as -3. 824 * 825 * @param year the given year. 826 * @return <code>true</code> if the given year is a leap year; <code>false</code> 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</code> to the specified 864 * <code>Object</code>. The result is <code>true</code> if and 865 * only if the argument is a <code>GregorianCalendar</code> 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</code> parameters and Gregorian change date as 869 * this object. 870 * 871 * @param obj the object to compare with. 872 * @return <code>true</code> if this object is equal to <code>obj</code>; 873 * <code>false</code> 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</code> 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</code> 896 * after the call minus the value of <code>field</code> before the 897 * call is <code>amount</code>, modulo any overflow that has occurred in 898 * <code>field</code>. 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</code> 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</code> is a smaller field than 908 * <code>DAY_OF_MONTH</code>. 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 * @exception IllegalArgumentException if <code>field</code> is 915 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, 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</code> 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</code> field is unchanged 1108 * because it is a larger field than <code>MONTH</code>.</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</code> if rolling up, <code>false</code> otherwise. 1112 * @exception IllegalArgumentException if <code>field</code> is 1113 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, 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</code> is thrown. 1133 * 1134 * <p> 1135 * <em>Example</em>: Consider a <code>GregorianCalendar</code> 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</code>, the <code>DAY_OF_MONTH</code> field cannot 1139 * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible 1140 * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it 1141 * is a larger field than <code>MONTH</code>. 1142 * <p> 1143 * <em>Example</em>: Consider a <code>GregorianCalendar</code> 1144 * originally set to Sunday June 6, 1999. Calling 1145 * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to 1146 * Tuesday June 1, 1999, whereas calling 1147 * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to 1148 * Sunday May 30, 1999. This is because the roll rule imposes an 1149 * additional constraint: The <code>MONTH</code> must not change when the 1150 * <code>WEEK_OF_MONTH</code> 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</code>, an invariant 1153 * when changing the <code>WEEK_OF_MONTH</code>, 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</code>. 1159 * @exception IllegalArgumentException if <code>field</code> is 1160 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, 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</code> 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</code> 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: 1568 case DAY_OF_MONTH: 1569 case DAY_OF_YEAR: 1570 case WEEK_OF_YEAR: 1571 case WEEK_OF_MONTH: 1572 case DAY_OF_WEEK_IN_MONTH: 1573 case YEAR: 1574 { 1575 // On or after Gregorian 200-3-1, Julian and Gregorian 1576 // calendar dates are the same or Gregorian dates are 1577 // larger (i.e., there is a "gap") after 300-3-1. 1578 if (gregorianCutoverYear > 200) { 1579 break; 1580 } 1581 // There might be "overlapping" dates. 1582 GregorianCalendar gc = (GregorianCalendar) clone(); 1583 gc.setLenient(true); 1584 gc.setTimeInMillis(gregorianCutover); 1585 int v1 = gc.getActualMaximum(field); 1586 gc.setTimeInMillis(gregorianCutover-1); 1587 int v2 = gc.getActualMaximum(field); 1588 return Math.max(MAX_VALUES[field], Math.max(v1, v2)); 1589 } 1590 } 1591 return MAX_VALUES[field]; 1592 } 1593 1594 /** 1595 * Returns the highest minimum value for the given calendar field 1596 * of this <code>GregorianCalendar</code> instance. The highest 1597 * minimum value is defined as the largest value returned by 1598 * {@link #getActualMinimum(int)} for any possible time value, 1599 * taking into consideration the current values of the 1600 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, 1601 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, 1602 * {@link #getGregorianChange() getGregorianChange} and 1603 * {@link Calendar#getTimeZone() getTimeZone} methods. 1604 * 1605 * @param field the calendar field. 1606 * @return the highest minimum value for the given calendar field. 1607 * @see #getMinimum(int) 1608 * @see #getMaximum(int) 1609 * @see #getLeastMaximum(int) 1610 * @see #getActualMinimum(int) 1611 * @see #getActualMaximum(int) 1612 */ 1613 @Override getGreatestMinimum(int field)1614 public int getGreatestMinimum(int field) { 1615 if (field == DAY_OF_MONTH) { 1616 BaseCalendar.Date d = getGregorianCutoverDate(); 1617 long mon1 = getFixedDateMonth1(d, gregorianCutoverDate); 1618 d = getCalendarDate(mon1); 1619 return Math.max(MIN_VALUES[field], d.getDayOfMonth()); 1620 } 1621 return MIN_VALUES[field]; 1622 } 1623 1624 /** 1625 * Returns the lowest maximum value for the given calendar field 1626 * of this <code>GregorianCalendar</code> instance. The lowest 1627 * maximum value is defined as the smallest value returned by 1628 * {@link #getActualMaximum(int)} for any possible time value, 1629 * taking into consideration the current values of the 1630 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, 1631 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, 1632 * {@link #getGregorianChange() getGregorianChange} and 1633 * {@link Calendar#getTimeZone() getTimeZone} methods. 1634 * 1635 * @param field the calendar field 1636 * @return the lowest maximum value for the given calendar field. 1637 * @see #getMinimum(int) 1638 * @see #getMaximum(int) 1639 * @see #getGreatestMinimum(int) 1640 * @see #getActualMinimum(int) 1641 * @see #getActualMaximum(int) 1642 */ 1643 @Override getLeastMaximum(int field)1644 public int getLeastMaximum(int field) { 1645 switch (field) { 1646 case MONTH: 1647 case DAY_OF_MONTH: 1648 case DAY_OF_YEAR: 1649 case WEEK_OF_YEAR: 1650 case WEEK_OF_MONTH: 1651 case DAY_OF_WEEK_IN_MONTH: 1652 case YEAR: 1653 { 1654 GregorianCalendar gc = (GregorianCalendar) clone(); 1655 gc.setLenient(true); 1656 gc.setTimeInMillis(gregorianCutover); 1657 int v1 = gc.getActualMaximum(field); 1658 gc.setTimeInMillis(gregorianCutover-1); 1659 int v2 = gc.getActualMaximum(field); 1660 return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2)); 1661 } 1662 } 1663 return LEAST_MAX_VALUES[field]; 1664 } 1665 1666 /** 1667 * Returns the minimum value that this calendar field could have, 1668 * taking into consideration the given time value and the current 1669 * values of the 1670 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, 1671 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, 1672 * {@link #getGregorianChange() getGregorianChange} and 1673 * {@link Calendar#getTimeZone() getTimeZone} methods. 1674 * 1675 * <p>For example, if the Gregorian change date is January 10, 1676 * 1970 and the date of this <code>GregorianCalendar</code> is 1677 * January 20, 1970, the actual minimum value of the 1678 * <code>DAY_OF_MONTH</code> field is 10 because the previous date 1679 * of January 10, 1970 is December 27, 1996 (in the Julian 1680 * calendar). Therefore, December 28, 1969 to January 9, 1970 1681 * don't exist. 1682 * 1683 * @param field the calendar field 1684 * @return the minimum of the given field for the time value of 1685 * this <code>GregorianCalendar</code> 1686 * @see #getMinimum(int) 1687 * @see #getMaximum(int) 1688 * @see #getGreatestMinimum(int) 1689 * @see #getLeastMaximum(int) 1690 * @see #getActualMaximum(int) 1691 * @since 1.2 1692 */ 1693 @Override getActualMinimum(int field)1694 public int getActualMinimum(int field) { 1695 if (field == DAY_OF_MONTH) { 1696 GregorianCalendar gc = getNormalizedCalendar(); 1697 int year = gc.cdate.getNormalizedYear(); 1698 if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) { 1699 long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate)); 1700 BaseCalendar.Date d = getCalendarDate(month1); 1701 return d.getDayOfMonth(); 1702 } 1703 } 1704 return getMinimum(field); 1705 } 1706 1707 /** 1708 * Returns the maximum value that this calendar field could have, 1709 * taking into consideration the given time value and the current 1710 * values of the 1711 * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, 1712 * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, 1713 * {@link #getGregorianChange() getGregorianChange} and 1714 * {@link Calendar#getTimeZone() getTimeZone} methods. 1715 * For example, if the date of this instance is February 1, 2004, 1716 * the actual maximum value of the <code>DAY_OF_MONTH</code> field 1717 * is 29 because 2004 is a leap year, and if the date of this 1718 * instance is February 1, 2005, it's 28. 1719 * 1720 * <p>This method calculates the maximum value of {@link 1721 * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link 1722 * Calendar#YEAR YEAR} (calendar year) value, not the <a 1723 * href="#week_year">week year</a>. Call {@link 1724 * #getWeeksInWeekYear()} to get the maximum value of {@code 1725 * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}. 1726 * 1727 * @param field the calendar field 1728 * @return the maximum of the given field for the time value of 1729 * this <code>GregorianCalendar</code> 1730 * @see #getMinimum(int) 1731 * @see #getMaximum(int) 1732 * @see #getGreatestMinimum(int) 1733 * @see #getLeastMaximum(int) 1734 * @see #getActualMinimum(int) 1735 * @since 1.2 1736 */ 1737 @Override getActualMaximum(int field)1738 public int getActualMaximum(int field) { 1739 final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK| 1740 HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK| 1741 ZONE_OFFSET_MASK|DST_OFFSET_MASK; 1742 if ((fieldsForFixedMax & (1<<field)) != 0) { 1743 return getMaximum(field); 1744 } 1745 1746 GregorianCalendar gc = getNormalizedCalendar(); 1747 BaseCalendar.Date date = gc.cdate; 1748 BaseCalendar cal = gc.calsys; 1749 int normalizedYear = date.getNormalizedYear(); 1750 1751 int value = -1; 1752 switch (field) { 1753 case MONTH: 1754 { 1755 if (!gc.isCutoverYear(normalizedYear)) { 1756 value = DECEMBER; 1757 break; 1758 } 1759 1760 // January 1 of the next year may or may not exist. 1761 long nextJan1; 1762 do { 1763 nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null); 1764 } while (nextJan1 < gregorianCutoverDate); 1765 BaseCalendar.Date d = (BaseCalendar.Date) date.clone(); 1766 cal.getCalendarDateFromFixedDate(d, nextJan1 - 1); 1767 value = d.getMonth() - 1; 1768 } 1769 break; 1770 1771 case DAY_OF_MONTH: 1772 { 1773 value = cal.getMonthLength(date); 1774 if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) { 1775 break; 1776 } 1777 1778 // Handle cutover year. 1779 long fd = gc.getCurrentFixedDate(); 1780 if (fd >= gregorianCutoverDate) { 1781 break; 1782 } 1783 int monthLength = gc.actualMonthLength(); 1784 long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1; 1785 // Convert the fixed date to its calendar date. 1786 BaseCalendar.Date d = gc.getCalendarDate(monthEnd); 1787 value = d.getDayOfMonth(); 1788 } 1789 break; 1790 1791 case DAY_OF_YEAR: 1792 { 1793 if (!gc.isCutoverYear(normalizedYear)) { 1794 value = cal.getYearLength(date); 1795 break; 1796 } 1797 1798 // Handle cutover year. 1799 long jan1; 1800 if (gregorianCutoverYear == gregorianCutoverYearJulian) { 1801 BaseCalendar cocal = gc.getCutoverCalendarSystem(); 1802 jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null); 1803 } else if (normalizedYear == gregorianCutoverYearJulian) { 1804 jan1 = cal.getFixedDate(normalizedYear, 1, 1, null); 1805 } else { 1806 jan1 = gregorianCutoverDate; 1807 } 1808 // January 1 of the next year may or may not exist. 1809 long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null); 1810 if (nextJan1 < gregorianCutoverDate) { 1811 nextJan1 = gregorianCutoverDate; 1812 } 1813 assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(), 1814 date.getDayOfMonth(), date); 1815 assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(), 1816 date.getDayOfMonth(), date); 1817 value = (int)(nextJan1 - jan1); 1818 } 1819 break; 1820 1821 case WEEK_OF_YEAR: 1822 { 1823 if (!gc.isCutoverYear(normalizedYear)) { 1824 // Get the day of week of January 1 of the year 1825 CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE); 1826 d.setDate(date.getYear(), BaseCalendar.JANUARY, 1); 1827 int dayOfWeek = cal.getDayOfWeek(d); 1828 // Normalize the day of week with the firstDayOfWeek value 1829 dayOfWeek -= getFirstDayOfWeek(); 1830 if (dayOfWeek < 0) { 1831 dayOfWeek += 7; 1832 } 1833 value = 52; 1834 int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1; 1835 if ((magic == 6) || 1836 (date.isLeapYear() && (magic == 5 || magic == 12))) { 1837 value++; 1838 } 1839 break; 1840 } 1841 1842 if (gc == this) { 1843 gc = (GregorianCalendar) gc.clone(); 1844 } 1845 int maxDayOfYear = getActualMaximum(DAY_OF_YEAR); 1846 gc.set(DAY_OF_YEAR, maxDayOfYear); 1847 value = gc.get(WEEK_OF_YEAR); 1848 if (internalGet(YEAR) != gc.getWeekYear()) { 1849 gc.set(DAY_OF_YEAR, maxDayOfYear - 7); 1850 value = gc.get(WEEK_OF_YEAR); 1851 } 1852 } 1853 break; 1854 1855 case WEEK_OF_MONTH: 1856 { 1857 if (!gc.isCutoverYear(normalizedYear)) { 1858 CalendarDate d = cal.newCalendarDate(null); 1859 d.setDate(date.getYear(), date.getMonth(), 1); 1860 int dayOfWeek = cal.getDayOfWeek(d); 1861 int monthLength = cal.getMonthLength(d); 1862 dayOfWeek -= getFirstDayOfWeek(); 1863 if (dayOfWeek < 0) { 1864 dayOfWeek += 7; 1865 } 1866 int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week 1867 value = 3; 1868 if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) { 1869 value++; 1870 } 1871 monthLength -= nDaysFirstWeek + 7 * 3; 1872 if (monthLength > 0) { 1873 value++; 1874 if (monthLength > 7) { 1875 value++; 1876 } 1877 } 1878 break; 1879 } 1880 1881 // Cutover year handling 1882 if (gc == this) { 1883 gc = (GregorianCalendar) gc.clone(); 1884 } 1885 int y = gc.internalGet(YEAR); 1886 int m = gc.internalGet(MONTH); 1887 do { 1888 value = gc.get(WEEK_OF_MONTH); 1889 gc.add(WEEK_OF_MONTH, +1); 1890 } while (gc.get(YEAR) == y && gc.get(MONTH) == m); 1891 } 1892 break; 1893 1894 case DAY_OF_WEEK_IN_MONTH: 1895 { 1896 // may be in the Gregorian cutover month 1897 int ndays, dow1; 1898 int dow = date.getDayOfWeek(); 1899 if (!gc.isCutoverYear(normalizedYear)) { 1900 BaseCalendar.Date d = (BaseCalendar.Date) date.clone(); 1901 ndays = cal.getMonthLength(d); 1902 d.setDayOfMonth(1); 1903 cal.normalize(d); 1904 dow1 = d.getDayOfWeek(); 1905 } else { 1906 // Let a cloned GregorianCalendar take care of the cutover cases. 1907 if (gc == this) { 1908 gc = (GregorianCalendar) clone(); 1909 } 1910 ndays = gc.actualMonthLength(); 1911 gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH)); 1912 dow1 = gc.get(DAY_OF_WEEK); 1913 } 1914 int x = dow - dow1; 1915 if (x < 0) { 1916 x += 7; 1917 } 1918 ndays -= x; 1919 value = (ndays + 6) / 7; 1920 } 1921 break; 1922 1923 case YEAR: 1924 /* The year computation is no different, in principle, from the 1925 * others, however, the range of possible maxima is large. In 1926 * addition, the way we know we've exceeded the range is different. 1927 * For these reasons, we use the special case code below to handle 1928 * this field. 1929 * 1930 * The actual maxima for YEAR depend on the type of calendar: 1931 * 1932 * Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE 1933 * Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE 1934 * Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE 1935 * 1936 * We know we've exceeded the maximum when either the month, date, 1937 * time, or era changes in response to setting the year. We don't 1938 * check for month, date, and time here because the year and era are 1939 * sufficient to detect an invalid year setting. NOTE: If code is 1940 * added to check the month and date in the future for some reason, 1941 * Feb 29 must be allowed to shift to Mar 1 when setting the year. 1942 */ 1943 { 1944 if (gc == this) { 1945 gc = (GregorianCalendar) clone(); 1946 } 1947 1948 // Calculate the millisecond offset from the beginning 1949 // of the year of this calendar and adjust the max 1950 // year value if we are beyond the limit in the max 1951 // year. 1952 long current = gc.getYearOffsetInMillis(); 1953 1954 if (gc.internalGetEra() == CE) { 1955 gc.setTimeInMillis(Long.MAX_VALUE); 1956 value = gc.get(YEAR); 1957 long maxEnd = gc.getYearOffsetInMillis(); 1958 if (current > maxEnd) { 1959 value--; 1960 } 1961 } else { 1962 CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ? 1963 gcal : getJulianCalendarSystem(); 1964 CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone()); 1965 long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours(); 1966 maxEnd *= 60; 1967 maxEnd += d.getMinutes(); 1968 maxEnd *= 60; 1969 maxEnd += d.getSeconds(); 1970 maxEnd *= 1000; 1971 maxEnd += d.getMillis(); 1972 value = d.getYear(); 1973 if (value <= 0) { 1974 assert mincal == gcal; 1975 value = 1 - value; 1976 } 1977 if (current < maxEnd) { 1978 value--; 1979 } 1980 } 1981 } 1982 break; 1983 1984 default: 1985 throw new ArrayIndexOutOfBoundsException(field); 1986 } 1987 return value; 1988 } 1989 1990 /** 1991 * Returns the millisecond offset from the beginning of this 1992 * year. This Calendar object must have been normalized. 1993 */ getYearOffsetInMillis()1994 private long getYearOffsetInMillis() { 1995 long t = (internalGet(DAY_OF_YEAR) - 1) * 24; 1996 t += internalGet(HOUR_OF_DAY); 1997 t *= 60; 1998 t += internalGet(MINUTE); 1999 t *= 60; 2000 t += internalGet(SECOND); 2001 t *= 1000; 2002 return t + internalGet(MILLISECOND) - 2003 (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET)); 2004 } 2005 2006 @Override clone()2007 public Object clone() 2008 { 2009 GregorianCalendar other = (GregorianCalendar) super.clone(); 2010 2011 other.gdate = (BaseCalendar.Date) gdate.clone(); 2012 if (cdate != null) { 2013 if (cdate != gdate) { 2014 other.cdate = (BaseCalendar.Date) cdate.clone(); 2015 } else { 2016 other.cdate = other.gdate; 2017 } 2018 } 2019 other.originalFields = null; 2020 other.zoneOffsets = null; 2021 return other; 2022 } 2023 2024 @Override getTimeZone()2025 public TimeZone getTimeZone() { 2026 TimeZone zone = super.getTimeZone(); 2027 // To share the zone by CalendarDates 2028 gdate.setZone(zone); 2029 if (cdate != null && cdate != gdate) { 2030 cdate.setZone(zone); 2031 } 2032 return zone; 2033 } 2034 2035 @Override setTimeZone(TimeZone zone)2036 public void setTimeZone(TimeZone zone) { 2037 super.setTimeZone(zone); 2038 // To share the zone by CalendarDates 2039 gdate.setZone(zone); 2040 if (cdate != null && cdate != gdate) { 2041 cdate.setZone(zone); 2042 } 2043 } 2044 2045 /** 2046 * Returns {@code true} indicating this {@code GregorianCalendar} 2047 * supports week dates. 2048 * 2049 * @return {@code true} (always) 2050 * @see #getWeekYear() 2051 * @see #setWeekDate(int,int,int) 2052 * @see #getWeeksInWeekYear() 2053 * @since 1.7 2054 */ 2055 @Override isWeekDateSupported()2056 public final boolean isWeekDateSupported() { 2057 return true; 2058 } 2059 2060 /** 2061 * Returns the <a href="#week_year">week year</a> represented by this 2062 * {@code GregorianCalendar}. The dates in the weeks between 1 and the 2063 * maximum week number of the week year have the same week year value 2064 * that may be one year before or after the {@link Calendar#YEAR YEAR} 2065 * (calendar year) value. 2066 * 2067 * <p>This method calls {@link Calendar#complete()} before 2068 * calculating the week year. 2069 * 2070 * @return the week year represented by this {@code GregorianCalendar}. 2071 * If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is 2072 * represented by 0 or a negative number: BC 1 is 0, BC 2 2073 * is -1, BC 3 is -2, and so on. 2074 * @throws IllegalArgumentException 2075 * if any of the calendar fields is invalid in non-lenient mode. 2076 * @see #isWeekDateSupported() 2077 * @see #getWeeksInWeekYear() 2078 * @see Calendar#getFirstDayOfWeek() 2079 * @see Calendar#getMinimalDaysInFirstWeek() 2080 * @since 1.7 2081 */ 2082 @Override getWeekYear()2083 public int getWeekYear() { 2084 int year = get(YEAR); // implicitly calls complete() 2085 if (internalGetEra() == BCE) { 2086 year = 1 - year; 2087 } 2088 2089 // Fast path for the Gregorian calendar years that are never 2090 // affected by the Julian-Gregorian transition 2091 if (year > gregorianCutoverYear + 1) { 2092 int weekOfYear = internalGet(WEEK_OF_YEAR); 2093 if (internalGet(MONTH) == JANUARY) { 2094 if (weekOfYear >= 52) { 2095 --year; 2096 } 2097 } else { 2098 if (weekOfYear == 1) { 2099 ++year; 2100 } 2101 } 2102 return year; 2103 } 2104 2105 // General (slow) path 2106 int dayOfYear = internalGet(DAY_OF_YEAR); 2107 int maxDayOfYear = getActualMaximum(DAY_OF_YEAR); 2108 int minimalDays = getMinimalDaysInFirstWeek(); 2109 2110 // Quickly check the possibility of year adjustments before 2111 // cloning this GregorianCalendar. 2112 if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) { 2113 return year; 2114 } 2115 2116 // Create a clone to work on the calculation 2117 GregorianCalendar cal = (GregorianCalendar) clone(); 2118 cal.setLenient(true); 2119 // Use GMT so that intermediate date calculations won't 2120 // affect the time of day fields. 2121 cal.setTimeZone(TimeZone.getTimeZone("GMT")); 2122 // Go to the first day of the year, which is usually January 1. 2123 cal.set(DAY_OF_YEAR, 1); 2124 cal.complete(); 2125 2126 // Get the first day of the first day-of-week in the year. 2127 int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK); 2128 if (delta != 0) { 2129 if (delta < 0) { 2130 delta += 7; 2131 } 2132 cal.add(DAY_OF_YEAR, delta); 2133 } 2134 int minDayOfYear = cal.get(DAY_OF_YEAR); 2135 if (dayOfYear < minDayOfYear) { 2136 if (minDayOfYear <= minimalDays) { 2137 --year; 2138 } 2139 } else { 2140 cal.set(YEAR, year + 1); 2141 cal.set(DAY_OF_YEAR, 1); 2142 cal.complete(); 2143 int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK); 2144 if (del != 0) { 2145 if (del < 0) { 2146 del += 7; 2147 } 2148 cal.add(DAY_OF_YEAR, del); 2149 } 2150 minDayOfYear = cal.get(DAY_OF_YEAR) - 1; 2151 if (minDayOfYear == 0) { 2152 minDayOfYear = 7; 2153 } 2154 if (minDayOfYear >= minimalDays) { 2155 int days = maxDayOfYear - dayOfYear + 1; 2156 if (days <= (7 - minDayOfYear)) { 2157 ++year; 2158 } 2159 } 2160 } 2161 return year; 2162 } 2163 2164 /** 2165 * Sets this {@code GregorianCalendar} to the date given by the 2166 * date specifiers - <a href="#week_year">{@code weekYear}</a>, 2167 * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear} 2168 * follows the <a href="#week_and_year">{@code WEEK_OF_YEAR} 2169 * numbering</a>. The {@code dayOfWeek} value must be one of the 2170 * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link 2171 * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}. 2172 * 2173 * <p>Note that the numeric day-of-week representation differs from 2174 * the ISO 8601 standard, and that the {@code weekOfYear} 2175 * numbering is compatible with the standard when {@code 2176 * getFirstDayOfWeek()} is {@code MONDAY} and {@code 2177 * getMinimalDaysInFirstWeek()} is 4. 2178 * 2179 * <p>Unlike the {@code set} method, all of the calendar fields 2180 * and the instant of time value are calculated upon return. 2181 * 2182 * <p>If {@code weekOfYear} is out of the valid week-of-year 2183 * range in {@code weekYear}, the {@code weekYear} 2184 * and {@code weekOfYear} values are adjusted in lenient 2185 * mode, or an {@code IllegalArgumentException} is thrown in 2186 * non-lenient mode. 2187 * 2188 * @param weekYear the week year 2189 * @param weekOfYear the week number based on {@code weekYear} 2190 * @param dayOfWeek the day of week value: one of the constants 2191 * for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field: 2192 * {@link Calendar#SUNDAY SUNDAY}, ..., 2193 * {@link Calendar#SATURDAY SATURDAY}. 2194 * @exception IllegalArgumentException 2195 * if any of the given date specifiers is invalid, 2196 * or if any of the calendar fields are inconsistent 2197 * with the given date specifiers in non-lenient mode 2198 * @see GregorianCalendar#isWeekDateSupported() 2199 * @see Calendar#getFirstDayOfWeek() 2200 * @see Calendar#getMinimalDaysInFirstWeek() 2201 * @since 1.7 2202 */ 2203 @Override setWeekDate(int weekYear, int weekOfYear, int dayOfWeek)2204 public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { 2205 if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) { 2206 throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek); 2207 } 2208 2209 // To avoid changing the time of day fields by date 2210 // calculations, use a clone with the GMT time zone. 2211 GregorianCalendar gc = (GregorianCalendar) clone(); 2212 gc.setLenient(true); 2213 int era = gc.get(ERA); 2214 gc.clear(); 2215 gc.setTimeZone(TimeZone.getTimeZone("GMT")); 2216 gc.set(ERA, era); 2217 gc.set(YEAR, weekYear); 2218 gc.set(WEEK_OF_YEAR, 1); 2219 gc.set(DAY_OF_WEEK, getFirstDayOfWeek()); 2220 int days = dayOfWeek - getFirstDayOfWeek(); 2221 if (days < 0) { 2222 days += 7; 2223 } 2224 days += 7 * (weekOfYear - 1); 2225 if (days != 0) { 2226 gc.add(DAY_OF_YEAR, days); 2227 } else { 2228 gc.complete(); 2229 } 2230 2231 if (!isLenient() && 2232 (gc.getWeekYear() != weekYear 2233 || gc.internalGet(WEEK_OF_YEAR) != weekOfYear 2234 || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) { 2235 throw new IllegalArgumentException(); 2236 } 2237 2238 set(ERA, gc.internalGet(ERA)); 2239 set(YEAR, gc.internalGet(YEAR)); 2240 set(MONTH, gc.internalGet(MONTH)); 2241 set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH)); 2242 2243 // to avoid throwing an IllegalArgumentException in 2244 // non-lenient, set WEEK_OF_YEAR internally 2245 internalSet(WEEK_OF_YEAR, weekOfYear); 2246 complete(); 2247 } 2248 2249 /** 2250 * Returns the number of weeks in the <a href="#week_year">week year</a> 2251 * represented by this {@code GregorianCalendar}. 2252 * 2253 * <p>For example, if this {@code GregorianCalendar}'s date is 2254 * December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO 2255 * 8601 compatible setting</a>, this method will return 53 for the 2256 * period: December 29, 2008 to January 3, 2010 while {@link 2257 * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return 2258 * 52 for the period: December 31, 2007 to December 28, 2008. 2259 * 2260 * @return the number of weeks in the week year. 2261 * @see Calendar#WEEK_OF_YEAR 2262 * @see #getWeekYear() 2263 * @see #getActualMaximum(int) 2264 * @since 1.7 2265 */ 2266 @Override getWeeksInWeekYear()2267 public int getWeeksInWeekYear() { 2268 GregorianCalendar gc = getNormalizedCalendar(); 2269 int weekYear = gc.getWeekYear(); 2270 if (weekYear == gc.internalGet(YEAR)) { 2271 return gc.getActualMaximum(WEEK_OF_YEAR); 2272 } 2273 2274 // Use the 2nd week for calculating the max of WEEK_OF_YEAR 2275 if (gc == this) { 2276 gc = (GregorianCalendar) gc.clone(); 2277 } 2278 gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK)); 2279 return gc.getActualMaximum(WEEK_OF_YEAR); 2280 } 2281 2282 ///////////////////////////// 2283 // Time => Fields computation 2284 ///////////////////////////// 2285 2286 /** 2287 * The fixed date corresponding to gdate. If the value is 2288 * Long.MIN_VALUE, the fixed date value is unknown. Currently, 2289 * Julian calendar dates are not cached. 2290 */ 2291 private transient long cachedFixedDate = Long.MIN_VALUE; 2292 2293 /** 2294 * Converts the time value (millisecond offset from the <a 2295 * href="Calendar.html#Epoch">Epoch</a>) to calendar field values. 2296 * The time is <em>not</em> 2297 * recomputed first; to recompute the time, then the fields, call the 2298 * <code>complete</code> method. 2299 * 2300 * @see Calendar#complete 2301 */ 2302 @Override computeFields()2303 protected void computeFields() { 2304 int mask; 2305 if (isPartiallyNormalized()) { 2306 // Determine which calendar fields need to be computed. 2307 mask = getSetStateFields(); 2308 int fieldMask = ~mask & ALL_FIELDS; 2309 // We have to call computTime in case calsys == null in 2310 // order to set calsys and cdate. (6263644) 2311 if (fieldMask != 0 || calsys == null) { 2312 mask |= computeFields(fieldMask, 2313 mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)); 2314 assert mask == ALL_FIELDS; 2315 } 2316 } else { 2317 mask = ALL_FIELDS; 2318 computeFields(mask, 0); 2319 } 2320 // After computing all the fields, set the field state to `COMPUTED'. 2321 setFieldsComputed(mask); 2322 } 2323 2324 /** 2325 * This computeFields implements the conversion from UTC 2326 * (millisecond offset from the Epoch) to calendar 2327 * field values. fieldMask specifies which fields to change the 2328 * setting state to COMPUTED, although all fields are set to 2329 * the correct values. This is required to fix 4685354. 2330 * 2331 * @param fieldMask a bit mask to specify which fields to change 2332 * the setting state. 2333 * @param tzMask a bit mask to specify which time zone offset 2334 * fields to be used for time calculations 2335 * @return a new field mask that indicates what field values have 2336 * actually been set. 2337 */ computeFields(int fieldMask, int tzMask)2338 private int computeFields(int fieldMask, int tzMask) { 2339 int zoneOffset = 0; 2340 TimeZone tz = getZone(); 2341 if (zoneOffsets == null) { 2342 zoneOffsets = new int[2]; 2343 } 2344 if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) { 2345 if (tz instanceof ZoneInfo) { 2346 // BEGIN Android-changed: use libcore.util.ZoneInfo. 2347 // The method name to get offsets differs from sun.util.calendar.ZoneInfo 2348 // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets); 2349 ZoneInfo zoneInfo = (ZoneInfo) tz; 2350 zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets); 2351 // END Android-changed: use libcore.util.ZoneInfo. 2352 } else { 2353 zoneOffset = tz.getOffset(time); 2354 zoneOffsets[0] = tz.getRawOffset(); 2355 zoneOffsets[1] = zoneOffset - zoneOffsets[0]; 2356 } 2357 } 2358 if (tzMask != 0) { 2359 if (isFieldSet(tzMask, ZONE_OFFSET)) { 2360 zoneOffsets[0] = internalGet(ZONE_OFFSET); 2361 } 2362 if (isFieldSet(tzMask, DST_OFFSET)) { 2363 zoneOffsets[1] = internalGet(DST_OFFSET); 2364 } 2365 zoneOffset = zoneOffsets[0] + zoneOffsets[1]; 2366 } 2367 2368 // By computing time and zoneOffset separately, we can take 2369 // the wider range of time+zoneOffset than the previous 2370 // implementation. 2371 long fixedDate = zoneOffset / ONE_DAY; 2372 int timeOfDay = zoneOffset % (int)ONE_DAY; 2373 fixedDate += time / ONE_DAY; 2374 timeOfDay += (int) (time % ONE_DAY); 2375 if (timeOfDay >= ONE_DAY) { 2376 timeOfDay -= ONE_DAY; 2377 ++fixedDate; 2378 } else { 2379 while (timeOfDay < 0) { 2380 timeOfDay += ONE_DAY; 2381 --fixedDate; 2382 } 2383 } 2384 fixedDate += EPOCH_OFFSET; 2385 2386 int era = CE; 2387 int year; 2388 if (fixedDate >= gregorianCutoverDate) { 2389 // Handle Gregorian dates. 2390 assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized() 2391 : "cache control: not normalized"; 2392 assert cachedFixedDate == Long.MIN_VALUE || 2393 gcal.getFixedDate(gdate.getNormalizedYear(), 2394 gdate.getMonth(), 2395 gdate.getDayOfMonth(), gdate) 2396 == cachedFixedDate 2397 : "cache control: inconsictency" + 2398 ", cachedFixedDate=" + cachedFixedDate + 2399 ", computed=" + 2400 gcal.getFixedDate(gdate.getNormalizedYear(), 2401 gdate.getMonth(), 2402 gdate.getDayOfMonth(), 2403 gdate) + 2404 ", date=" + gdate; 2405 2406 // See if we can use gdate to avoid date calculation. 2407 if (fixedDate != cachedFixedDate) { 2408 gcal.getCalendarDateFromFixedDate(gdate, fixedDate); 2409 cachedFixedDate = fixedDate; 2410 } 2411 2412 year = gdate.getYear(); 2413 if (year <= 0) { 2414 year = 1 - year; 2415 era = BCE; 2416 } 2417 calsys = gcal; 2418 cdate = gdate; 2419 assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate; 2420 } else { 2421 // Handle Julian calendar dates. 2422 calsys = getJulianCalendarSystem(); 2423 cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone()); 2424 jcal.getCalendarDateFromFixedDate(cdate, fixedDate); 2425 Era e = cdate.getEra(); 2426 if (e == jeras[0]) { 2427 era = BCE; 2428 } 2429 year = cdate.getYear(); 2430 } 2431 2432 // Always set the ERA and YEAR values. 2433 internalSet(ERA, era); 2434 internalSet(YEAR, year); 2435 int mask = fieldMask | (ERA_MASK|YEAR_MASK); 2436 2437 int month = cdate.getMonth() - 1; // 0-based 2438 int dayOfMonth = cdate.getDayOfMonth(); 2439 2440 // Set the basic date fields. 2441 if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK)) 2442 != 0) { 2443 internalSet(MONTH, month); 2444 internalSet(DAY_OF_MONTH, dayOfMonth); 2445 internalSet(DAY_OF_WEEK, cdate.getDayOfWeek()); 2446 mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK; 2447 } 2448 2449 if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK 2450 |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) { 2451 if (timeOfDay != 0) { 2452 int hours = timeOfDay / ONE_HOUR; 2453 internalSet(HOUR_OF_DAY, hours); 2454 internalSet(AM_PM, hours / 12); // Assume AM == 0 2455 internalSet(HOUR, hours % 12); 2456 int r = timeOfDay % ONE_HOUR; 2457 internalSet(MINUTE, r / ONE_MINUTE); 2458 r %= ONE_MINUTE; 2459 internalSet(SECOND, r / ONE_SECOND); 2460 internalSet(MILLISECOND, r % ONE_SECOND); 2461 } else { 2462 internalSet(HOUR_OF_DAY, 0); 2463 internalSet(AM_PM, AM); 2464 internalSet(HOUR, 0); 2465 internalSet(MINUTE, 0); 2466 internalSet(SECOND, 0); 2467 internalSet(MILLISECOND, 0); 2468 } 2469 mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK 2470 |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK); 2471 } 2472 2473 if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) { 2474 internalSet(ZONE_OFFSET, zoneOffsets[0]); 2475 internalSet(DST_OFFSET, zoneOffsets[1]); 2476 mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK); 2477 } 2478 2479 if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) { 2480 int normalizedYear = cdate.getNormalizedYear(); 2481 long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate); 2482 int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1; 2483 long fixedDateMonth1 = fixedDate - dayOfMonth + 1; 2484 int cutoverGap = 0; 2485 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian; 2486 int relativeDayOfMonth = dayOfMonth - 1; 2487 2488 // If we are in the cutover year, we need some special handling. 2489 if (normalizedYear == cutoverYear) { 2490 // Need to take care of the "missing" days. 2491 if (gregorianCutoverYearJulian <= gregorianCutoverYear) { 2492 // We need to find out where we are. The cutover 2493 // gap could even be more than one year. (One 2494 // year difference in ~48667 years.) 2495 fixedDateJan1 = getFixedDateJan1(cdate, fixedDate); 2496 if (fixedDate >= gregorianCutoverDate) { 2497 fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate); 2498 } 2499 } 2500 int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1; 2501 cutoverGap = dayOfYear - realDayOfYear; 2502 dayOfYear = realDayOfYear; 2503 relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1); 2504 } 2505 internalSet(DAY_OF_YEAR, dayOfYear); 2506 internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1); 2507 2508 int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate); 2509 2510 // The spec is to calculate WEEK_OF_YEAR in the 2511 // ISO8601-style. This creates problems, though. 2512 if (weekOfYear == 0) { 2513 // If the date belongs to the last week of the 2514 // previous year, use the week number of "12/31" of 2515 // the "previous" year. Again, if the previous year is 2516 // the Gregorian cutover year, we need to take care of 2517 // it. Usually the previous day of January 1 is 2518 // December 31, which is not always true in 2519 // GregorianCalendar. 2520 long fixedDec31 = fixedDateJan1 - 1; 2521 long prevJan1 = fixedDateJan1 - 365; 2522 if (normalizedYear > (cutoverYear + 1)) { 2523 if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) { 2524 --prevJan1; 2525 } 2526 } else if (normalizedYear <= gregorianCutoverYearJulian) { 2527 if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) { 2528 --prevJan1; 2529 } 2530 } else { 2531 BaseCalendar calForJan1 = calsys; 2532 //int prevYear = normalizedYear - 1; 2533 int prevYear = getCalendarDate(fixedDec31).getNormalizedYear(); 2534 if (prevYear == gregorianCutoverYear) { 2535 calForJan1 = getCutoverCalendarSystem(); 2536 if (calForJan1 == jcal) { 2537 prevJan1 = calForJan1.getFixedDate(prevYear, 2538 BaseCalendar.JANUARY, 2539 1, 2540 null); 2541 } else { 2542 prevJan1 = gregorianCutoverDate; 2543 calForJan1 = gcal; 2544 } 2545 } else if (prevYear <= gregorianCutoverYearJulian) { 2546 calForJan1 = getJulianCalendarSystem(); 2547 prevJan1 = calForJan1.getFixedDate(prevYear, 2548 BaseCalendar.JANUARY, 2549 1, 2550 null); 2551 } 2552 } 2553 weekOfYear = getWeekNumber(prevJan1, fixedDec31); 2554 } else { 2555 if (normalizedYear > gregorianCutoverYear || 2556 normalizedYear < (gregorianCutoverYearJulian - 1)) { 2557 // Regular years 2558 if (weekOfYear >= 52) { 2559 long nextJan1 = fixedDateJan1 + 365; 2560 if (cdate.isLeapYear()) { 2561 nextJan1++; 2562 } 2563 long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6, 2564 getFirstDayOfWeek()); 2565 int ndays = (int)(nextJan1st - nextJan1); 2566 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { 2567 // The first days forms a week in which the date is included. 2568 weekOfYear = 1; 2569 } 2570 } 2571 } else { 2572 BaseCalendar calForJan1 = calsys; 2573 int nextYear = normalizedYear + 1; 2574 if (nextYear == (gregorianCutoverYearJulian + 1) && 2575 nextYear < gregorianCutoverYear) { 2576 // In case the gap is more than one year. 2577 nextYear = gregorianCutoverYear; 2578 } 2579 if (nextYear == gregorianCutoverYear) { 2580 calForJan1 = getCutoverCalendarSystem(); 2581 } 2582 2583 long nextJan1; 2584 if (nextYear > gregorianCutoverYear 2585 || gregorianCutoverYearJulian == gregorianCutoverYear 2586 || nextYear == gregorianCutoverYearJulian) { 2587 nextJan1 = calForJan1.getFixedDate(nextYear, 2588 BaseCalendar.JANUARY, 2589 1, 2590 null); 2591 } else { 2592 nextJan1 = gregorianCutoverDate; 2593 calForJan1 = gcal; 2594 } 2595 2596 long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6, 2597 getFirstDayOfWeek()); 2598 int ndays = (int)(nextJan1st - nextJan1); 2599 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { 2600 // The first days forms a week in which the date is included. 2601 weekOfYear = 1; 2602 } 2603 } 2604 } 2605 internalSet(WEEK_OF_YEAR, weekOfYear); 2606 internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate)); 2607 mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK); 2608 } 2609 return mask; 2610 } 2611 2612 /** 2613 * Returns the number of weeks in a period between fixedDay1 and 2614 * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule 2615 * is applied to calculate the number of weeks. 2616 * 2617 * @param fixedDay1 the fixed date of the first day of the period 2618 * @param fixedDate the fixed date of the last day of the period 2619 * @return the number of weeks of the given period 2620 */ getWeekNumber(long fixedDay1, long fixedDate)2621 private int getWeekNumber(long fixedDay1, long fixedDate) { 2622 // We can always use `gcal' since Julian and Gregorian are the 2623 // same thing for this calculation. 2624 long fixedDay1st = Gregorian.getDayOfWeekDateOnOrBefore(fixedDay1 + 6, 2625 getFirstDayOfWeek()); 2626 int ndays = (int)(fixedDay1st - fixedDay1); 2627 assert ndays <= 7; 2628 if (ndays >= getMinimalDaysInFirstWeek()) { 2629 fixedDay1st -= 7; 2630 } 2631 int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st); 2632 if (normalizedDayOfPeriod >= 0) { 2633 return normalizedDayOfPeriod / 7 + 1; 2634 } 2635 return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1; 2636 } 2637 2638 /** 2639 * Converts calendar field values to the time value (millisecond 2640 * offset from the <a href="Calendar.html#Epoch">Epoch</a>). 2641 * 2642 * @exception IllegalArgumentException if any calendar fields are invalid. 2643 */ 2644 @Override computeTime()2645 protected void computeTime() { 2646 // In non-lenient mode, perform brief checking of calendar 2647 // fields which have been set externally. Through this 2648 // checking, the field values are stored in originalFields[] 2649 // to see if any of them are normalized later. 2650 if (!isLenient()) { 2651 if (originalFields == null) { 2652 originalFields = new int[FIELD_COUNT]; 2653 } 2654 for (int field = 0; field < FIELD_COUNT; field++) { 2655 int value = internalGet(field); 2656 if (isExternallySet(field)) { 2657 // Quick validation for any out of range values 2658 if (value < getMinimum(field) || value > getMaximum(field)) { 2659 throw new IllegalArgumentException(getFieldName(field)); 2660 } 2661 } 2662 originalFields[field] = value; 2663 } 2664 } 2665 2666 // Let the super class determine which calendar fields to be 2667 // used to calculate the time. 2668 int fieldMask = selectFields(); 2669 2670 // The year defaults to the epoch start. We don't check 2671 // fieldMask for YEAR because YEAR is a mandatory field to 2672 // determine the date. 2673 int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR; 2674 2675 int era = internalGetEra(); 2676 if (era == BCE) { 2677 year = 1 - year; 2678 } else if (era != CE) { 2679 // Even in lenient mode we disallow ERA values other than CE & BCE. 2680 // (The same normalization rule as add()/roll() could be 2681 // applied here in lenient mode. But this checking is kept 2682 // unchanged for compatibility as of 1.5.) 2683 throw new IllegalArgumentException("Invalid era"); 2684 } 2685 2686 // If year is 0 or negative, we need to set the ERA value later. 2687 if (year <= 0 && !isSet(ERA)) { 2688 fieldMask |= ERA_MASK; 2689 setFieldsComputed(ERA_MASK); 2690 } 2691 2692 // Calculate the time of day. We rely on the convention that 2693 // an UNSET field has 0. 2694 long timeOfDay = 0; 2695 if (isFieldSet(fieldMask, HOUR_OF_DAY)) { 2696 timeOfDay += (long) internalGet(HOUR_OF_DAY); 2697 } else { 2698 timeOfDay += internalGet(HOUR); 2699 // The default value of AM_PM is 0 which designates AM. 2700 if (isFieldSet(fieldMask, AM_PM)) { 2701 timeOfDay += 12 * internalGet(AM_PM); 2702 } 2703 } 2704 timeOfDay *= 60; 2705 timeOfDay += internalGet(MINUTE); 2706 timeOfDay *= 60; 2707 timeOfDay += internalGet(SECOND); 2708 timeOfDay *= 1000; 2709 timeOfDay += internalGet(MILLISECOND); 2710 2711 // Convert the time of day to the number of days and the 2712 // millisecond offset from midnight. 2713 long fixedDate = timeOfDay / ONE_DAY; 2714 timeOfDay %= ONE_DAY; 2715 while (timeOfDay < 0) { 2716 timeOfDay += ONE_DAY; 2717 --fixedDate; 2718 } 2719 2720 // Calculate the fixed date since January 1, 1 (Gregorian). 2721 calculateFixedDate: { 2722 long gfd, jfd; 2723 if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) { 2724 gfd = fixedDate + getFixedDate(gcal, year, fieldMask); 2725 if (gfd >= gregorianCutoverDate) { 2726 fixedDate = gfd; 2727 break calculateFixedDate; 2728 } 2729 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); 2730 } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) { 2731 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); 2732 if (jfd < gregorianCutoverDate) { 2733 fixedDate = jfd; 2734 break calculateFixedDate; 2735 } 2736 gfd = jfd; 2737 } else { 2738 jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask); 2739 gfd = fixedDate + getFixedDate(gcal, year, fieldMask); 2740 } 2741 2742 // Now we have to determine which calendar date it is. 2743 2744 // If the date is relative from the beginning of the year 2745 // in the Julian calendar, then use jfd; 2746 if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) { 2747 if (gregorianCutoverYear == gregorianCutoverYearJulian) { 2748 fixedDate = jfd; 2749 break calculateFixedDate; 2750 } else if (year == gregorianCutoverYear) { 2751 fixedDate = gfd; 2752 break calculateFixedDate; 2753 } 2754 } 2755 2756 if (gfd >= gregorianCutoverDate) { 2757 if (jfd >= gregorianCutoverDate) { 2758 fixedDate = gfd; 2759 } else { 2760 // The date is in an "overlapping" period. No way 2761 // to disambiguate it. Determine it using the 2762 // previous date calculation. 2763 if (calsys == gcal || calsys == null) { 2764 fixedDate = gfd; 2765 } else { 2766 fixedDate = jfd; 2767 } 2768 } 2769 } else { 2770 if (jfd < gregorianCutoverDate) { 2771 fixedDate = jfd; 2772 } else { 2773 // The date is in a "missing" period. 2774 if (!isLenient()) { 2775 throw new IllegalArgumentException("the specified date doesn't exist"); 2776 } 2777 // Take the Julian date for compatibility, which 2778 // will produce a Gregorian date. 2779 fixedDate = jfd; 2780 } 2781 } 2782 } 2783 2784 // millis represents local wall-clock time in milliseconds. 2785 long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay; 2786 2787 // Compute the time zone offset and DST offset. There are two potential 2788 // ambiguities here. We'll assume a 2:00 am (wall time) switchover time 2789 // for discussion purposes here. 2790 // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am 2791 // can be in standard or in DST depending. However, 2:00 am is an invalid 2792 // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST). 2793 // We assume standard time. 2794 // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am 2795 // can be in standard or DST. Both are valid representations (the rep 2796 // jumps from 1:59:59 DST to 1:00:00 Std). 2797 // Again, we assume standard time. 2798 // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET 2799 // or DST_OFFSET fields; then we use those fields. 2800 TimeZone zone = getZone(); 2801 // BEGIN Android-changed: time zone related calculation via helper methods. 2802 int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK); 2803 2804 millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone); 2805 // END Android-changed: time zone related calculation via helper methods. 2806 2807 // Set this calendar's time in milliseconds 2808 time = millis; 2809 2810 int mask = computeFields(fieldMask | getSetStateFields(), tzMask); 2811 2812 if (!isLenient()) { 2813 for (int field = 0; field < FIELD_COUNT; field++) { 2814 if (!isExternallySet(field)) { 2815 continue; 2816 } 2817 if (originalFields[field] != internalGet(field)) { 2818 String s = originalFields[field] + " -> " + internalGet(field); 2819 // Restore the original field values 2820 System.arraycopy(originalFields, 0, fields, 0, fields.length); 2821 throw new IllegalArgumentException(getFieldName(field) + ": " + s); 2822 } 2823 } 2824 } 2825 setFieldsNormalized(mask); 2826 } 2827 2828 // BEGIN Android-added: helper methods for time zone related calculation. 2829 /** 2830 * Calculates the time in milliseconds that this calendar represents using the UTC time, 2831 * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge 2832 * of what fields were explicitly set on the calendar. 2833 * 2834 * <p>A time is represented as the number of milliseconds since 2835 * <i>1st January 1970 00:00:00.000 UTC</i>. 2836 * 2837 * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time}, 2838 * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as 2839 * used in {@link SimpleTimeZone}. Specifically: 2840 * 2841 * <dl> 2842 * <dt><b>UTC time</b></dt> 2843 * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time, 2844 * standard time and wall time are all identical within the UTC time zone.</dd> 2845 * <dt><b>standard time</b></dt> 2846 * <dd>This is the local time within the time zone and is not affected by DST.</dd> 2847 * <dt><b>wall time</b></dt> 2848 * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone 2849 * supports DST then it will be the same as <b>standard time</b> when outside DST and it will 2850 * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar 2851 * represent.</dd> 2852 * </dl> 2853 * 2854 * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented 2855 * a standard time in the {@code UTC} time zone. It is the value that would be returned by 2856 * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If 2857 * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of 2858 * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a 2859 * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to 2860 * 0. 2861 * 2862 * <p>To adjust from a UTC time in millis to the standard time in millis we must 2863 * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert 2864 * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to 2865 * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00. 2866 * 2867 * <p>As the zone offset can depend on the time and we cannot calculate the time properly until 2868 * we know the time there is a bit of a catch-22. So, what this does is use the 2869 * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then 2870 * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They 2871 * are then used to make the final wall time calculation. 2872 * 2873 * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See 2874 * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information. 2875 * 2876 * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and 2877 * {@link #DST_OFFSET_MASK} 2878 * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT. 2879 * @param zone the actual time zone. 2880 * @return the UTC time in millis after adjusting for zone and DST offset. 2881 */ adjustForZoneAndDaylightSavingsTime( int tzMask, long utcTimeInMillis, TimeZone zone)2882 private long adjustForZoneAndDaylightSavingsTime( 2883 int tzMask, long utcTimeInMillis, TimeZone zone) { 2884 2885 // The following don't actually need to be initialized because they are always set before 2886 // they are used but the compiler cannot detect that. 2887 int zoneOffset = 0; 2888 int dstOffset = 0; 2889 2890 // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information 2891 // from the TimeZone. 2892 if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) { 2893 if (zoneOffsets == null) { 2894 zoneOffsets = new int[2]; 2895 } 2896 int gmtOffset = isFieldSet(tzMask, ZONE_OFFSET) ? 2897 internalGet(ZONE_OFFSET) : zone.getRawOffset(); 2898 2899 // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure 2900 // and not used in the final calculation as the offset used here may not be the same as 2901 // the actual offset the time zone requires be used for this time. This is to handle 2902 // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00 2903 // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30 2904 // for dates before the change over. 2905 long standardTimeInZone = utcTimeInMillis - gmtOffset; 2906 2907 // Retrieve the correct zone and DST offsets from the time zone. 2908 if (zone instanceof ZoneInfo) { 2909 // Android-changed: libcore ZoneInfo uses different method to get offsets. 2910 ZoneInfo zoneInfo = (ZoneInfo) zone; 2911 zoneInfo.getOffsetsByUtcTime(standardTimeInZone, zoneOffsets); 2912 } else { 2913 zone.getOffsets(standardTimeInZone, zoneOffsets); 2914 } 2915 zoneOffset = zoneOffsets[0]; 2916 dstOffset = zoneOffsets[1]; 2917 2918 // If necessary adjust the DST offset to handle an invalid wall clock sensibly. 2919 dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset); 2920 } 2921 2922 // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the 2923 // fields, potentially overriding information from the TimeZone. 2924 if (tzMask != 0) { 2925 if (isFieldSet(tzMask, ZONE_OFFSET)) { 2926 zoneOffset = internalGet(ZONE_OFFSET); 2927 } 2928 if (isFieldSet(tzMask, DST_OFFSET)) { 2929 dstOffset = internalGet(DST_OFFSET); 2930 } 2931 } 2932 2933 // Adjust the time zone offset values to get the UTC time. 2934 long standardTimeInZone = utcTimeInMillis - zoneOffset; 2935 return standardTimeInZone - dstOffset; 2936 } 2937 2938 /** 2939 * If the supplied millis is in daylight savings time (DST) and is the result of an invalid 2940 * wall clock then adjust the DST offset to ensure sensible behavior. 2941 * 2942 * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour) 2943 * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks 2944 * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of 2945 * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to 2946 * 03:00. The following table shows the relationship between the time in millis, the standard 2947 * time and the wall time at the point of transitioning into DST. As can be seen there is no 2948 * 02:00 in the wall time. 2949 * 2950 * <pre> 2951 * Time In Millis - ...... x+1h ..... x+2h ..... x+3h 2952 * Standard Time - ...... 01:00 ..... 02:00 ..... 03:00 ..... 2953 * Wall Time - ...... 01:00 ..... 03:00 ..... 04:00 ..... 2954 * ^ 2955 * 02:00 missing 2956 * </pre> 2957 * 2958 * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so 2959 * that it is in that invalid period then this code attempts to do something sensible. It 2960 * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both 2961 * the input calendar fields perspective and from the time in millis perspective. Of course the 2962 * result of that is that when the time is formatted in that time zone that the time is 2963 * actually 03:MM:SS.SSS. 2964 * 2965 * <pre> 2966 * Wall Time - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 ..... 2967 * Time In Millis - ...... x+1h ..... <b> x+2h .....</b> x+2h ..... x+3h ..... 2968 * </pre> 2969 * 2970 * <p>The way that works is as follows. First the standard time is calculated and the DST 2971 * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in 2972 * DST an hour earlier (or however long the DST offset is) then it must be in that invalid 2973 * period, in which case set the DST offset to 0. That is then subtracted from the time in 2974 * millis to produce the correct result. The following diagram illustrates the process. 2975 * 2976 * <pre> 2977 * Standard Time - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 ..... 2978 * Time In Millis - ...... x+1h ..... x+2h ..... x+3h ..... x+4h ..... 2979 * DST Offset - ...... 0h ..... 1h ..... 1h ..... 1h ..... 2980 * Adjusted DST - ...... 0h ..... <b>0h</b> ..... 1h ..... 1h ..... 2981 * Adjusted Time - ...... x+1h ..... x+2h ..... <b>x+2h</b> ..... <b>x+3h</b> ..... 2982 * </pre> 2983 * 2984 * @return the adjusted DST offset. 2985 */ adjustDstOffsetForInvalidWallClock( long standardTimeInZone, TimeZone zone, int dstOffset)2986 private int adjustDstOffsetForInvalidWallClock( 2987 long standardTimeInZone, TimeZone zone, int dstOffset) { 2988 2989 if (dstOffset != 0) { 2990 // If applying the DST offset produces a time that is outside DST then it must be 2991 // an invalid wall clock so clear the DST offset to avoid that happening. 2992 if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) { 2993 dstOffset = 0; 2994 } 2995 } 2996 return dstOffset; 2997 } 2998 // END Android-added: helper methods for time zone related calculation. 2999 3000 /** 3001 * Computes the fixed date under either the Gregorian or the 3002 * Julian calendar, using the given year and the specified calendar fields. 3003 * 3004 * @param cal the CalendarSystem to be used for the date calculation 3005 * @param year the normalized year number, with 0 indicating the 3006 * year 1 BCE, -1 indicating 2 BCE, etc. 3007 * @param fieldMask the calendar fields to be used for the date calculation 3008 * @return the fixed date 3009 * @see Calendar#selectFields 3010 */ getFixedDate(BaseCalendar cal, int year, int fieldMask)3011 private long getFixedDate(BaseCalendar cal, int year, int fieldMask) { 3012 int month = JANUARY; 3013 if (isFieldSet(fieldMask, MONTH)) { 3014 // No need to check if MONTH has been set (no isSet(MONTH) 3015 // call) since its unset value happens to be JANUARY (0). 3016 month = internalGet(MONTH); 3017 3018 // If the month is out of range, adjust it into range 3019 if (month > DECEMBER) { 3020 year += month / 12; 3021 month %= 12; 3022 } else if (month < JANUARY) { 3023 int[] rem = new int[1]; 3024 year += CalendarUtils.floorDivide(month, 12, rem); 3025 month = rem[0]; 3026 } 3027 } 3028 3029 // Get the fixed date since Jan 1, 1 (Gregorian). We are on 3030 // the first day of either `month' or January in 'year'. 3031 long fixedDate = cal.getFixedDate(year, month + 1, 1, 3032 cal == gcal ? gdate : null); 3033 if (isFieldSet(fieldMask, MONTH)) { 3034 // Month-based calculations 3035 if (isFieldSet(fieldMask, DAY_OF_MONTH)) { 3036 // We are on the first day of the month. Just add the 3037 // offset if DAY_OF_MONTH is set. If the isSet call 3038 // returns false, that means DAY_OF_MONTH has been 3039 // selected just because of the selected 3040 // combination. We don't need to add any since the 3041 // default value is the 1st. 3042 if (isSet(DAY_OF_MONTH)) { 3043 // To avoid underflow with DAY_OF_MONTH-1, add 3044 // DAY_OF_MONTH, then subtract 1. 3045 fixedDate += internalGet(DAY_OF_MONTH); 3046 fixedDate--; 3047 } 3048 } else { 3049 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) { 3050 long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6, 3051 getFirstDayOfWeek()); 3052 // If we have enough days in the first week, then 3053 // move to the previous week. 3054 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { 3055 firstDayOfWeek -= 7; 3056 } 3057 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { 3058 firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, 3059 internalGet(DAY_OF_WEEK)); 3060 } 3061 // In lenient mode, we treat days of the previous 3062 // months as a part of the specified 3063 // WEEK_OF_MONTH. See 4633646. 3064 fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1); 3065 } else { 3066 int dayOfWeek; 3067 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { 3068 dayOfWeek = internalGet(DAY_OF_WEEK); 3069 } else { 3070 dayOfWeek = getFirstDayOfWeek(); 3071 } 3072 // We are basing this on the day-of-week-in-month. The only 3073 // trickiness occurs if the day-of-week-in-month is 3074 // negative. 3075 int dowim; 3076 if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) { 3077 dowim = internalGet(DAY_OF_WEEK_IN_MONTH); 3078 } else { 3079 dowim = 1; 3080 } 3081 if (dowim >= 0) { 3082 fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1, 3083 dayOfWeek); 3084 } else { 3085 // Go to the first day of the next week of 3086 // the specified week boundary. 3087 int lastDate = monthLength(month, year) + (7 * (dowim + 1)); 3088 // Then, get the day of week date on or before the last date. 3089 fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1, 3090 dayOfWeek); 3091 } 3092 } 3093 } 3094 } else { 3095 if (year == gregorianCutoverYear && cal == gcal 3096 && fixedDate < gregorianCutoverDate 3097 && gregorianCutoverYear != gregorianCutoverYearJulian) { 3098 // January 1 of the year doesn't exist. Use 3099 // gregorianCutoverDate as the first day of the 3100 // year. 3101 fixedDate = gregorianCutoverDate; 3102 } 3103 // We are on the first day of the year. 3104 if (isFieldSet(fieldMask, DAY_OF_YEAR)) { 3105 // Add the offset, then subtract 1. (Make sure to avoid underflow.) 3106 fixedDate += internalGet(DAY_OF_YEAR); 3107 fixedDate--; 3108 } else { 3109 long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6, 3110 getFirstDayOfWeek()); 3111 // If we have enough days in the first week, then move 3112 // to the previous week. 3113 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { 3114 firstDayOfWeek -= 7; 3115 } 3116 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { 3117 int dayOfWeek = internalGet(DAY_OF_WEEK); 3118 if (dayOfWeek != getFirstDayOfWeek()) { 3119 firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, 3120 dayOfWeek); 3121 } 3122 } 3123 fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1); 3124 } 3125 } 3126 3127 return fixedDate; 3128 } 3129 3130 /** 3131 * Returns this object if it's normalized (all fields and time are 3132 * in sync). Otherwise, a cloned object is returned after calling 3133 * complete() in lenient mode. 3134 */ getNormalizedCalendar()3135 private GregorianCalendar getNormalizedCalendar() { 3136 GregorianCalendar gc; 3137 if (isFullyNormalized()) { 3138 gc = this; 3139 } else { 3140 // Create a clone and normalize the calendar fields 3141 gc = (GregorianCalendar) this.clone(); 3142 gc.setLenient(true); 3143 gc.complete(); 3144 } 3145 return gc; 3146 } 3147 3148 /** 3149 * Returns the Julian calendar system instance (singleton). 'jcal' 3150 * and 'jeras' are set upon the return. 3151 */ getJulianCalendarSystem()3152 private static synchronized BaseCalendar getJulianCalendarSystem() { 3153 if (jcal == null) { 3154 jcal = (JulianCalendar) CalendarSystem.forName("julian"); 3155 jeras = jcal.getEras(); 3156 } 3157 return jcal; 3158 } 3159 3160 /** 3161 * Returns the calendar system for dates before the cutover date 3162 * in the cutover year. If the cutover date is January 1, the 3163 * method returns Gregorian. Otherwise, Julian. 3164 */ getCutoverCalendarSystem()3165 private BaseCalendar getCutoverCalendarSystem() { 3166 if (gregorianCutoverYearJulian < gregorianCutoverYear) { 3167 return gcal; 3168 } 3169 return getJulianCalendarSystem(); 3170 } 3171 3172 /** 3173 * Determines if the specified year (normalized) is the Gregorian 3174 * cutover year. This object must have been normalized. 3175 */ isCutoverYear(int normalizedYear)3176 private boolean isCutoverYear(int normalizedYear) { 3177 int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian; 3178 return normalizedYear == cutoverYear; 3179 } 3180 3181 /** 3182 * Returns the fixed date of the first day of the year (usually 3183 * January 1) before the specified date. 3184 * 3185 * @param date the date for which the first day of the year is 3186 * calculated. The date has to be in the cut-over year (Gregorian 3187 * or Julian). 3188 * @param fixedDate the fixed date representation of the date 3189 */ getFixedDateJan1(BaseCalendar.Date date, long fixedDate)3190 private long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) { 3191 assert date.getNormalizedYear() == gregorianCutoverYear || 3192 date.getNormalizedYear() == gregorianCutoverYearJulian; 3193 if (gregorianCutoverYear != gregorianCutoverYearJulian) { 3194 if (fixedDate >= gregorianCutoverDate) { 3195 // Dates before the cutover date don't exist 3196 // in the same (Gregorian) year. So, no 3197 // January 1 exists in the year. Use the 3198 // cutover date as the first day of the year. 3199 return gregorianCutoverDate; 3200 } 3201 } 3202 // January 1 of the normalized year should exist. 3203 BaseCalendar juliancal = getJulianCalendarSystem(); 3204 return juliancal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null); 3205 } 3206 3207 /** 3208 * Returns the fixed date of the first date of the month (usually 3209 * the 1st of the month) before the specified date. 3210 * 3211 * @param date the date for which the first day of the month is 3212 * calculated. The date has to be in the cut-over year (Gregorian 3213 * or Julian). 3214 * @param fixedDate the fixed date representation of the date 3215 */ getFixedDateMonth1(BaseCalendar.Date date, long fixedDate)3216 private long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) { 3217 assert date.getNormalizedYear() == gregorianCutoverYear || 3218 date.getNormalizedYear() == gregorianCutoverYearJulian; 3219 BaseCalendar.Date gCutover = getGregorianCutoverDate(); 3220 if (gCutover.getMonth() == BaseCalendar.JANUARY 3221 && gCutover.getDayOfMonth() == 1) { 3222 // The cutover happened on January 1. 3223 return fixedDate - date.getDayOfMonth() + 1; 3224 } 3225 3226 long fixedDateMonth1; 3227 // The cutover happened sometime during the year. 3228 if (date.getMonth() == gCutover.getMonth()) { 3229 // The cutover happened in the month. 3230 BaseCalendar.Date jLastDate = getLastJulianDate(); 3231 if (gregorianCutoverYear == gregorianCutoverYearJulian 3232 && gCutover.getMonth() == jLastDate.getMonth()) { 3233 // The "gap" fits in the same month. 3234 fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(), 3235 date.getMonth(), 3236 1, 3237 null); 3238 } else { 3239 // Use the cutover date as the first day of the month. 3240 fixedDateMonth1 = gregorianCutoverDate; 3241 } 3242 } else { 3243 // The cutover happened before the month. 3244 fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1; 3245 } 3246 3247 return fixedDateMonth1; 3248 } 3249 3250 /** 3251 * Returns a CalendarDate produced from the specified fixed date. 3252 * 3253 * @param fd the fixed date 3254 */ getCalendarDate(long fd)3255 private BaseCalendar.Date getCalendarDate(long fd) { 3256 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem(); 3257 BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE); 3258 cal.getCalendarDateFromFixedDate(d, fd); 3259 return d; 3260 } 3261 3262 /** 3263 * Returns the Gregorian cutover date as a BaseCalendar.Date. The 3264 * date is a Gregorian date. 3265 */ getGregorianCutoverDate()3266 private BaseCalendar.Date getGregorianCutoverDate() { 3267 return getCalendarDate(gregorianCutoverDate); 3268 } 3269 3270 /** 3271 * Returns the day before the Gregorian cutover date as a 3272 * BaseCalendar.Date. The date is a Julian date. 3273 */ getLastJulianDate()3274 private BaseCalendar.Date getLastJulianDate() { 3275 return getCalendarDate(gregorianCutoverDate - 1); 3276 } 3277 3278 /** 3279 * Returns the length of the specified month in the specified 3280 * year. The year number must be normalized. 3281 * 3282 * @see #isLeapYear(int) 3283 */ monthLength(int month, int year)3284 private int monthLength(int month, int year) { 3285 return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month]; 3286 } 3287 3288 /** 3289 * Returns the length of the specified month in the year provided 3290 * by internalGet(YEAR). 3291 * 3292 * @see #isLeapYear(int) 3293 */ monthLength(int month)3294 private int monthLength(int month) { 3295 int year = internalGet(YEAR); 3296 if (internalGetEra() == BCE) { 3297 year = 1 - year; 3298 } 3299 return monthLength(month, year); 3300 } 3301 actualMonthLength()3302 private int actualMonthLength() { 3303 int year = cdate.getNormalizedYear(); 3304 if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) { 3305 return calsys.getMonthLength(cdate); 3306 } 3307 BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone(); 3308 long fd = calsys.getFixedDate(date); 3309 long month1 = getFixedDateMonth1(date, fd); 3310 long next1 = month1 + calsys.getMonthLength(date); 3311 if (next1 < gregorianCutoverDate) { 3312 return (int)(next1 - month1); 3313 } 3314 if (cdate != gdate) { 3315 date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE); 3316 } 3317 gcal.getCalendarDateFromFixedDate(date, next1); 3318 next1 = getFixedDateMonth1(date, next1); 3319 return (int)(next1 - month1); 3320 } 3321 3322 /** 3323 * Returns the length (in days) of the specified year. The year 3324 * must be normalized. 3325 */ yearLength(int year)3326 private int yearLength(int year) { 3327 return isLeapYear(year) ? 366 : 365; 3328 } 3329 3330 /** 3331 * Returns the length (in days) of the year provided by 3332 * internalGet(YEAR). 3333 */ yearLength()3334 private int yearLength() { 3335 int year = internalGet(YEAR); 3336 if (internalGetEra() == BCE) { 3337 year = 1 - year; 3338 } 3339 return yearLength(year); 3340 } 3341 3342 /** 3343 * After adjustments such as add(MONTH), add(YEAR), we don't want the 3344 * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar 3345 * 3, we want it to go to Feb 28. Adjustments which might run into this 3346 * problem call this method to retain the proper month. 3347 */ pinDayOfMonth()3348 private void pinDayOfMonth() { 3349 int year = internalGet(YEAR); 3350 int monthLen; 3351 if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) { 3352 monthLen = monthLength(internalGet(MONTH)); 3353 } else { 3354 GregorianCalendar gc = getNormalizedCalendar(); 3355 monthLen = gc.getActualMaximum(DAY_OF_MONTH); 3356 } 3357 int dom = internalGet(DAY_OF_MONTH); 3358 if (dom > monthLen) { 3359 set(DAY_OF_MONTH, monthLen); 3360 } 3361 } 3362 3363 /** 3364 * Returns the fixed date value of this object. The time value and 3365 * calendar fields must be in synch. 3366 */ getCurrentFixedDate()3367 private long getCurrentFixedDate() { 3368 return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate); 3369 } 3370 3371 /** 3372 * Returns the new value after 'roll'ing the specified value and amount. 3373 */ getRolledValue(int value, int amount, int min, int max)3374 private static int getRolledValue(int value, int amount, int min, int max) { 3375 assert value >= min && value <= max; 3376 int range = max - min + 1; 3377 amount %= range; 3378 int n = value + amount; 3379 if (n > max) { 3380 n -= range; 3381 } else if (n < min) { 3382 n += range; 3383 } 3384 assert n >= min && n <= max; 3385 return n; 3386 } 3387 3388 /** 3389 * Returns the ERA. We need a special method for this because the 3390 * default ERA is CE, but a zero (unset) ERA is BCE. 3391 */ internalGetEra()3392 private int internalGetEra() { 3393 return isSet(ERA) ? internalGet(ERA) : CE; 3394 } 3395 3396 /** 3397 * Updates internal state. 3398 */ readObject(ObjectInputStream stream)3399 private void readObject(ObjectInputStream stream) 3400 throws IOException, ClassNotFoundException { 3401 stream.defaultReadObject(); 3402 if (gdate == null) { 3403 gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone()); 3404 cachedFixedDate = Long.MIN_VALUE; 3405 } 3406 setGregorianChange(gregorianCutover); 3407 } 3408 3409 /** 3410 * Converts this object to a {@code ZonedDateTime} that represents 3411 * the same point on the time-line as this {@code GregorianCalendar}. 3412 * <p> 3413 * Since this object supports a Julian-Gregorian cutover date and 3414 * {@code ZonedDateTime} does not, it is possible that the resulting year, 3415 * month and day will have different values. The result will represent the 3416 * correct date in the ISO calendar system, which will also be the same value 3417 * for Modified Julian Days. 3418 * 3419 * @return a zoned date-time representing the same point on the time-line 3420 * as this gregorian calendar 3421 * @since 1.8 3422 */ toZonedDateTime()3423 public ZonedDateTime toZonedDateTime() { 3424 return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()), 3425 getTimeZone().toZoneId()); 3426 } 3427 3428 /** 3429 * Obtains an instance of {@code GregorianCalendar} with the default locale 3430 * from a {@code ZonedDateTime} object. 3431 * <p> 3432 * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover 3433 * date and uses ISO calendar system, the return GregorianCalendar is a pure 3434 * Gregorian calendar and uses ISO 8601 standard for week definitions, 3435 * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek() 3436 * FirstDayOfWeek} and {@code 4} as the value of the 3437 * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}. 3438 * <p> 3439 * {@code ZoneDateTime} can store points on the time-line further in the 3440 * future and further in the past than {@code GregorianCalendar}. In this 3441 * scenario, this method will throw an {@code IllegalArgumentException} 3442 * exception. 3443 * 3444 * @param zdt the zoned date-time object to convert 3445 * @return the gregorian calendar representing the same point on the 3446 * time-line as the zoned date-time provided 3447 * @exception NullPointerException if {@code zdt} is null 3448 * @exception IllegalArgumentException if the zoned date-time is too 3449 * large to represent as a {@code GregorianCalendar} 3450 * @since 1.8 3451 */ from(ZonedDateTime zdt)3452 public static GregorianCalendar from(ZonedDateTime zdt) { 3453 GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone())); 3454 cal.setGregorianChange(new Date(Long.MIN_VALUE)); 3455 cal.setFirstDayOfWeek(MONDAY); 3456 cal.setMinimalDaysInFirstWeek(4); 3457 try { 3458 cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000), 3459 zdt.get(ChronoField.MILLI_OF_SECOND))); 3460 } catch (ArithmeticException ex) { 3461 throw new IllegalArgumentException(ex); 3462 } 3463 return cal; 3464 } 3465 } 3466