1 /* 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.util.calendar; 27 28 import java.lang.Cloneable; 29 import java.util.Locale; 30 import java.util.TimeZone; 31 32 /** 33 * The <code>CalendarDate</code> class represents a specific instant 34 * in time by calendar date and time fields that are multiple cycles 35 * in different time unites. The semantics of each calendar field is 36 * given by a concrete calendar system rather than this 37 * <code>CalendarDate</code> class that holds calendar field values 38 * without interpreting them. Therefore, this class can be used to 39 * represent an amount of time, such as 2 years and 3 months. 40 * 41 * <p>A <code>CalendarDate</code> instance can be created by calling 42 * the <code>newCalendarDate</code> or <code>getCalendarDate</code> 43 * methods in <code>CalendarSystem</code>. A 44 * <code>CalendarSystem</code> instance is obtained by calling one of 45 * the factory methods in <code>CalendarSystem</code>. Manipulations 46 * of calendar dates must be handled by the calendar system by which 47 * <code>CalendarDate</code> instances have been created. 48 * 49 * <p>Some calendar fields can be modified through method calls. Any 50 * modification of a calendar field brings the state of a 51 * <code>CalendarDate</code> to <I>not normalized</I>. The 52 * normalization must be performed to make all the calendar fields 53 * consistent with a calendar system. 54 * 55 * <p>The <code>protected</code> methods are intended to be used for 56 * implementing a concrete calendar system, not for general use as an 57 * API. 58 * 59 * @see CalendarSystem 60 * @author Masayoshi Okutsu 61 * @since 1.5 62 */ 63 public abstract class CalendarDate implements Cloneable { 64 public static final int FIELD_UNDEFINED = Integer.MIN_VALUE; 65 public static final long TIME_UNDEFINED = Long.MIN_VALUE; 66 67 private Era era; 68 private int year; 69 private int month; 70 private int dayOfMonth; 71 private int dayOfWeek = FIELD_UNDEFINED; 72 private boolean leapYear; 73 74 private int hours; 75 private int minutes; 76 private int seconds; 77 private int millis; // fractional part of the second 78 private long fraction; // time of day value in millisecond 79 80 private boolean normalized; 81 82 private TimeZone zoneinfo; 83 private int zoneOffset; 84 private int daylightSaving; 85 private boolean forceStandardTime; 86 87 private Locale locale; 88 CalendarDate()89 protected CalendarDate() { 90 this(TimeZone.getDefault()); 91 } 92 CalendarDate(TimeZone zone)93 protected CalendarDate(TimeZone zone) { 94 zoneinfo = zone; 95 } 96 getEra()97 public Era getEra() { 98 return era; 99 } 100 101 /** 102 * Sets the era of the date to the specified era. The default 103 * implementation of this method accepts any Era value, including 104 * <code>null</code>. 105 * 106 * @exception NullPointerException if the calendar system for this 107 * <code>CalendarDate</code> requires eras and the specified era 108 * is null. 109 * @exception IllegalArgumentException if the specified 110 * <code>era</code> is unknown to the calendar 111 * system for this <code>CalendarDate</code>. 112 */ setEra(Era era)113 public CalendarDate setEra(Era era) { 114 if (this.era == era) { 115 return this; 116 } 117 this.era = era; 118 normalized = false; 119 return this; 120 } 121 getYear()122 public int getYear() { 123 return year; 124 } 125 setYear(int year)126 public CalendarDate setYear(int year) { 127 if (this.year != year) { 128 this.year = year; 129 normalized = false; 130 } 131 return this; 132 } 133 addYear(int n)134 public CalendarDate addYear(int n) { 135 if (n != 0) { 136 year += n; 137 normalized = false; 138 } 139 return this; 140 } 141 142 /** 143 * Returns whether the year represented by this 144 * <code>CalendarDate</code> is a leap year. If leap years are 145 * not applicable to the calendar system, this method always 146 * returns <code>false</code>. 147 * 148 * <p>If this <code>CalendarDate</code> hasn't been normalized, 149 * <code>false</code> is returned. The normalization must be 150 * performed to retrieve the correct leap year information. 151 * 152 * @return <code>true</code> if this <code>CalendarDate</code> is 153 * normalized and the year of this <code>CalendarDate</code> is a 154 * leap year, or <code>false</code> otherwise. 155 * @see BaseCalendar#isGregorianLeapYear 156 */ isLeapYear()157 public boolean isLeapYear() { 158 return leapYear; 159 } 160 setLeapYear(boolean leapYear)161 void setLeapYear(boolean leapYear) { 162 this.leapYear = leapYear; 163 } 164 getMonth()165 public int getMonth() { 166 return month; 167 } 168 setMonth(int month)169 public CalendarDate setMonth(int month) { 170 if (this.month != month) { 171 this.month = month; 172 normalized = false; 173 } 174 return this; 175 } 176 addMonth(int n)177 public CalendarDate addMonth(int n) { 178 if (n != 0) { 179 month += n; 180 normalized = false; 181 } 182 return this; 183 } 184 getDayOfMonth()185 public int getDayOfMonth() { 186 return dayOfMonth; 187 } 188 setDayOfMonth(int date)189 public CalendarDate setDayOfMonth(int date) { 190 if (dayOfMonth != date) { 191 dayOfMonth = date; 192 normalized = false; 193 } 194 return this; 195 } 196 addDayOfMonth(int n)197 public CalendarDate addDayOfMonth(int n) { 198 if (n != 0) { 199 dayOfMonth += n; 200 normalized = false; 201 } 202 return this; 203 } 204 205 /** 206 * Returns the day of week value. If this CalendarDate is not 207 * normalized, {@link #FIELD_UNDEFINED} is returned. 208 * 209 * @return day of week or {@link #FIELD_UNDEFINED} 210 */ getDayOfWeek()211 public int getDayOfWeek() { 212 if (!isNormalized()) { 213 dayOfWeek = FIELD_UNDEFINED; 214 } 215 return dayOfWeek; 216 } 217 getHours()218 public int getHours() { 219 return hours; 220 } 221 setHours(int hours)222 public CalendarDate setHours(int hours) { 223 if (this.hours != hours) { 224 this.hours = hours; 225 normalized = false; 226 } 227 return this; 228 } 229 addHours(int n)230 public CalendarDate addHours(int n) { 231 if (n != 0) { 232 hours += n; 233 normalized = false; 234 } 235 return this; 236 } 237 getMinutes()238 public int getMinutes() { 239 return minutes; 240 } 241 setMinutes(int minutes)242 public CalendarDate setMinutes(int minutes) { 243 if (this.minutes != minutes) { 244 this.minutes = minutes; 245 normalized = false; 246 } 247 return this; 248 } 249 addMinutes(int n)250 public CalendarDate addMinutes(int n) { 251 if (n != 0) { 252 minutes += n; 253 normalized = false; 254 } 255 return this; 256 } 257 getSeconds()258 public int getSeconds() { 259 return seconds; 260 } 261 setSeconds(int seconds)262 public CalendarDate setSeconds(int seconds) { 263 if (this.seconds != seconds) { 264 this.seconds = seconds; 265 normalized = false; 266 } 267 return this; 268 } 269 addSeconds(int n)270 public CalendarDate addSeconds(int n) { 271 if (n != 0) { 272 seconds += n; 273 normalized = false; 274 } 275 return this; 276 } 277 getMillis()278 public int getMillis() { 279 return millis; 280 } 281 setMillis(int millis)282 public CalendarDate setMillis(int millis) { 283 if (this.millis != millis) { 284 this.millis = millis; 285 normalized = false; 286 } 287 return this; 288 } 289 addMillis(int n)290 public CalendarDate addMillis(int n) { 291 if (n != 0) { 292 millis += n; 293 normalized = false; 294 } 295 return this; 296 } 297 getTimeOfDay()298 public long getTimeOfDay() { 299 if (!isNormalized()) { 300 return fraction = TIME_UNDEFINED; 301 } 302 return fraction; 303 } 304 setDate(int year, int month, int dayOfMonth)305 public CalendarDate setDate(int year, int month, int dayOfMonth) { 306 setYear(year); 307 setMonth(month); 308 setDayOfMonth(dayOfMonth); 309 return this; 310 } 311 addDate(int year, int month, int dayOfMonth)312 public CalendarDate addDate(int year, int month, int dayOfMonth) { 313 addYear(year); 314 addMonth(month); 315 addDayOfMonth(dayOfMonth); 316 return this; 317 } 318 setTimeOfDay(int hours, int minutes, int seconds, int millis)319 public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) { 320 setHours(hours); 321 setMinutes(minutes); 322 setSeconds(seconds); 323 setMillis(millis); 324 return this; 325 } 326 addTimeOfDay(int hours, int minutes, int seconds, int millis)327 public CalendarDate addTimeOfDay(int hours, int minutes, int seconds, int millis) { 328 addHours(hours); 329 addMinutes(minutes); 330 addSeconds(seconds); 331 addMillis(millis); 332 return this; 333 } 334 setTimeOfDay(long fraction)335 protected void setTimeOfDay(long fraction) { 336 this.fraction = fraction; 337 } 338 isNormalized()339 public boolean isNormalized() { 340 return normalized; 341 } 342 343 isStandardTime()344 public boolean isStandardTime() { 345 return forceStandardTime; 346 } 347 setStandardTime(boolean standardTime)348 public void setStandardTime(boolean standardTime) { 349 forceStandardTime = standardTime; 350 } 351 isDaylightTime()352 public boolean isDaylightTime() { 353 if (isStandardTime()) { 354 return false; 355 } 356 return daylightSaving != 0; 357 } 358 setLocale(Locale loc)359 protected void setLocale(Locale loc) { 360 locale = loc; 361 } 362 getZone()363 public TimeZone getZone() { 364 return zoneinfo; 365 } 366 setZone(TimeZone zoneinfo)367 public CalendarDate setZone(TimeZone zoneinfo) { 368 this.zoneinfo = zoneinfo; 369 return this; 370 } 371 372 /** 373 * Returns whether the specified date is the same date of this 374 * <code>CalendarDate</code>. The time of the day fields are 375 * ignored for the comparison. 376 */ isSameDate(CalendarDate date)377 public boolean isSameDate(CalendarDate date) { 378 return getDayOfWeek() == date.getDayOfWeek() 379 && getMonth() == date.getMonth() 380 && getYear() == date.getYear() 381 && getEra() == date.getEra(); 382 } 383 equals(Object obj)384 public boolean equals(Object obj) { 385 if (!(obj instanceof CalendarDate)) { 386 return false; 387 } 388 CalendarDate that = (CalendarDate) obj; 389 if (isNormalized() != that.isNormalized()) { 390 return false; 391 } 392 boolean hasZone = zoneinfo != null; 393 boolean thatHasZone = that.zoneinfo != null; 394 if (hasZone != thatHasZone) { 395 return false; 396 } 397 if (hasZone && !zoneinfo.equals(that.zoneinfo)) { 398 return false; 399 } 400 return (getEra() == that.getEra() 401 && year == that.year 402 && month == that.month 403 && dayOfMonth == that.dayOfMonth 404 && hours == that.hours 405 && minutes == that.minutes 406 && seconds == that.seconds 407 && millis == that.millis 408 && zoneOffset == that.zoneOffset); 409 } 410 hashCode()411 public int hashCode() { 412 // a pseudo (local standard) time stamp value in milliseconds 413 // from the Epoch, assuming Gregorian calendar fields. 414 long hash = ((((((long)year - 1970) * 12) + (month - 1)) * 30) + dayOfMonth) * 24; 415 hash = ((((((hash + hours) * 60) + minutes) * 60) + seconds) * 1000) + millis; 416 hash -= zoneOffset; 417 int normalized = isNormalized() ? 1 : 0; 418 int era = 0; 419 Era e = getEra(); 420 if (e != null) { 421 era = e.hashCode(); 422 } 423 int zone = zoneinfo != null ? zoneinfo.hashCode() : 0; 424 return (int) hash * (int)(hash >> 32) ^ era ^ normalized ^ zone; 425 } 426 427 /** 428 * Returns a copy of this <code>CalendarDate</code>. The 429 * <code>TimeZone</code> object, if any, is not cloned. 430 * 431 * @return a copy of this <code>CalendarDate</code> 432 */ clone()433 public Object clone() { 434 try { 435 return super.clone(); 436 } catch (CloneNotSupportedException e) { 437 // this shouldn't happen 438 throw new InternalError(e); 439 } 440 } 441 442 /** 443 * Converts calendar date values to a <code>String</code> in the 444 * following format. 445 * <pre> 446 * yyyy-MM-dd'T'HH:mm:ss.SSSz 447 * </pre> 448 * 449 * @see java.text.SimpleDateFormat 450 */ toString()451 public String toString() { 452 StringBuilder sb = new StringBuilder(); 453 CalendarUtils.sprintf0d(sb, year, 4).append('-'); 454 CalendarUtils.sprintf0d(sb, month, 2).append('-'); 455 CalendarUtils.sprintf0d(sb, dayOfMonth, 2).append('T'); 456 CalendarUtils.sprintf0d(sb, hours, 2).append(':'); 457 CalendarUtils.sprintf0d(sb, minutes, 2).append(':'); 458 CalendarUtils.sprintf0d(sb, seconds, 2).append('.'); 459 CalendarUtils.sprintf0d(sb, millis, 3); 460 if (zoneOffset == 0) { 461 sb.append('Z'); 462 } else if (zoneOffset != FIELD_UNDEFINED) { 463 int offset; 464 char sign; 465 if (zoneOffset > 0) { 466 offset = zoneOffset; 467 sign = '+'; 468 } else { 469 offset = -zoneOffset; 470 sign = '-'; 471 } 472 offset /= 60000; 473 sb.append(sign); 474 CalendarUtils.sprintf0d(sb, offset / 60, 2); 475 CalendarUtils.sprintf0d(sb, offset % 60, 2); 476 } else { 477 sb.append(" local time"); 478 } 479 return sb.toString(); 480 } 481 setDayOfWeek(int dayOfWeek)482 protected void setDayOfWeek(int dayOfWeek) { 483 this.dayOfWeek = dayOfWeek; 484 } 485 setNormalized(boolean normalized)486 protected void setNormalized(boolean normalized) { 487 this.normalized = normalized; 488 } 489 getZoneOffset()490 public int getZoneOffset() { 491 return zoneOffset; 492 } 493 setZoneOffset(int offset)494 protected void setZoneOffset(int offset) { 495 zoneOffset = offset; 496 } 497 getDaylightSaving()498 public int getDaylightSaving() { 499 return daylightSaving; 500 } 501 setDaylightSaving(int daylightSaving)502 protected void setDaylightSaving(int daylightSaving) { 503 this.daylightSaving = daylightSaving; 504 } 505 } 506