37 * * Redistributions in binary form must reproduce the above copyright notice, 38 * this list of conditions and the following disclaimer in the documentation 39 * and/or other materials provided with the distribution. 40 * 41 * * Neither the name of JSR-310 nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 package java.time.calendar; 58 59 import static java.time.calendar.ThaiBuddhistChrono.YEARS_DIFFERENCE; 60 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 61 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 62 import static java.time.temporal.ChronoField.YEAR; 63 64 import java.io.DataInput; 65 import java.io.DataOutput; 66 import java.io.IOException; 67 import java.io.Serializable; 68 import java.time.DateTimeException; 69 import java.time.LocalDate; 70 import java.time.temporal.ChronoField; 71 import java.time.temporal.ChronoLocalDate; 72 import java.time.temporal.TemporalField; 73 import java.time.temporal.ValueRange; 74 import java.util.Objects; 75 76 /** 77 * A date in the Thai Buddhist calendar system. 78 * <p> 79 * This implements {@code ChronoLocalDate} for the {@link ThaiBuddhistChrono Thai Buddhist calendar}. 80 * 81 * <h3>Specification for implementors</h3> 82 * This class is immutable and thread-safe. 83 * 84 * @since 1.8 85 */ 86 final class ThaiBuddhistDate 87 extends ChronoDateImpl<ThaiBuddhistChrono> 88 implements ChronoLocalDate<ThaiBuddhistChrono>, Serializable { 89 // this class is package-scoped so that future conversion to public 90 // would not change serialization 91 92 /** 93 * Serialization version. 94 */ 95 private static final long serialVersionUID = -8722293800195731463L; 96 97 /** 98 * The underlying date. 99 */ 100 private final LocalDate isoDate; 101 102 /** 103 * Creates an instance from an ISO date. 104 * 105 * @param isoDate the standard local date, validated not null 106 */ 107 ThaiBuddhistDate(LocalDate isoDate) { 108 Objects.requireNonNull(isoDate, "isoDate"); 109 this.isoDate = isoDate; 110 } 111 112 //----------------------------------------------------------------------- 113 @Override 114 public ThaiBuddhistChrono getChrono() { 115 return ThaiBuddhistChrono.INSTANCE; 116 } 117 118 @Override 119 public int lengthOfMonth() { 120 return isoDate.lengthOfMonth(); 121 } 122 123 @Override 124 public ValueRange range(TemporalField field) { 125 if (field instanceof ChronoField) { 126 if (isSupported(field)) { 127 ChronoField f = (ChronoField) field; 128 switch (f) { 129 case DAY_OF_MONTH: 130 case DAY_OF_YEAR: 131 case ALIGNED_WEEK_OF_MONTH: 132 return isoDate.range(field); 133 case YEAR_OF_ERA: { 134 ValueRange range = YEAR.range(); 135 long max = (getProlepticYear() <= 0 ? -(range.getMinimum() + YEARS_DIFFERENCE) + 1 : range.getMaximum() + YEARS_DIFFERENCE); 136 return ValueRange.of(1, max); 137 } 138 } 139 return getChrono().range(f); 140 } 141 throw new DateTimeException("Unsupported field: " + field.getName()); 142 } 143 return field.doRange(this); 144 } 145 146 @Override 147 public long getLong(TemporalField field) { 148 if (field instanceof ChronoField) { 149 switch ((ChronoField) field) { 150 case YEAR_OF_ERA: { 151 int prolepticYear = getProlepticYear(); 152 return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear); 153 } 154 case YEAR: 155 return getProlepticYear(); 156 case ERA: 157 return (getProlepticYear() >= 1 ? 1 : 0); 158 } 159 return isoDate.getLong(field); 160 } 161 return field.doGet(this); 162 } 163 164 private int getProlepticYear() { 165 return isoDate.getYear() + YEARS_DIFFERENCE; 166 } 167 168 //----------------------------------------------------------------------- 169 @Override 170 public ThaiBuddhistDate with(TemporalField field, long newValue) { 171 if (field instanceof ChronoField) { 172 ChronoField f = (ChronoField) field; 173 if (getLong(f) == newValue) { 174 return this; 175 } 176 switch (f) { 177 case YEAR_OF_ERA: 178 case YEAR: 179 case ERA: { 180 f.checkValidValue(newValue); 181 int nvalue = (int) newValue; 182 switch (f) { 183 case YEAR_OF_ERA: 184 return with(isoDate.withYear((getProlepticYear() >= 1 ? nvalue : 1 - nvalue) - YEARS_DIFFERENCE)); 185 case YEAR: 186 return with(isoDate.withYear(nvalue - YEARS_DIFFERENCE)); 187 case ERA: 188 return with(isoDate.withYear((1 - getProlepticYear()) - YEARS_DIFFERENCE)); 189 } 190 } 191 } 192 return with(isoDate.with(field, newValue)); 193 } 194 return (ThaiBuddhistDate) ChronoLocalDate.super.with(field, newValue); 195 } 196 197 //----------------------------------------------------------------------- 198 @Override 199 ThaiBuddhistDate plusYears(long years) { 200 return with(isoDate.plusYears(years)); 201 } 202 203 @Override 204 ThaiBuddhistDate plusMonths(long months) { 205 return with(isoDate.plusMonths(months)); 206 } 207 208 @Override 209 ThaiBuddhistDate plusDays(long days) { 210 return with(isoDate.plusDays(days)); 211 } 212 213 private ThaiBuddhistDate with(LocalDate newDate) { 214 return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate)); 215 } 216 217 @Override // override for performance 218 public long toEpochDay() { 219 return isoDate.toEpochDay(); 220 } 221 222 //------------------------------------------------------------------------- 223 @Override // override for performance 224 public boolean equals(Object obj) { 225 if (this == obj) { 226 return true; 227 } 228 if (obj instanceof ThaiBuddhistDate) { 229 ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj; 230 return this.isoDate.equals(otherDate.isoDate); 231 } 232 return false; 233 } 234 235 @Override // override for performance 236 public int hashCode() { 237 return getChrono().getId().hashCode() ^ isoDate.hashCode(); 238 } 239 240 //----------------------------------------------------------------------- 241 private Object writeReplace() { 242 return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this); 243 } 244 245 void writeExternal(DataOutput out) throws IOException { 246 // MinguoChrono is implicit in the THAIBUDDHIST_DATE_TYPE 247 out.writeInt(this.get(YEAR)); 248 out.writeByte(this.get(MONTH_OF_YEAR)); 249 out.writeByte(this.get(DAY_OF_MONTH)); 250 } 251 252 static ChronoLocalDate<ThaiBuddhistChrono> readExternal(DataInput in) throws IOException { 253 int year = in.readInt(); 254 int month = in.readByte(); 255 int dayOfMonth = in.readByte(); 256 return ThaiBuddhistChrono.INSTANCE.date(year, month, dayOfMonth); 257 } 258 259 } | 37 * * Redistributions in binary form must reproduce the above copyright notice, 38 * this list of conditions and the following disclaimer in the documentation 39 * and/or other materials provided with the distribution. 40 * 41 * * Neither the name of JSR-310 nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 package java.time.chrono; 58 59 import static java.time.chrono.ThaiBuddhistChronology.YEARS_DIFFERENCE; 60 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 61 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 62 import static java.time.temporal.ChronoField.YEAR; 63 64 import java.io.DataInput; 65 import java.io.DataOutput; 66 import java.io.IOException; 67 import java.io.Serializable; 68 import java.time.Clock; 69 import java.time.DateTimeException; 70 import java.time.LocalDate; 71 import java.time.LocalTime; 72 import java.time.Period; 73 import java.time.ZoneId; 74 import java.time.temporal.ChronoField; 75 import java.time.temporal.TemporalQuery; 76 import java.time.temporal.TemporalAccessor; 77 import java.time.temporal.TemporalAdjuster; 78 import java.time.temporal.TemporalAmount; 79 import java.time.temporal.TemporalField; 80 import java.time.temporal.TemporalUnit; 81 import java.time.temporal.ValueRange; 82 import java.util.Objects; 83 84 /** 85 * A date in the Thai Buddhist calendar system. 86 * <p> 87 * This date operates using the {@linkplain ThaiBuddhistChronology Thai Buddhist calendar}. 88 * This calendar system is primarily used in Thailand. 89 * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}. 90 * 91 * <h3>Specification for implementors</h3> 92 * This class is immutable and thread-safe. 93 * 94 * @since 1.8 95 */ 96 public final class ThaiBuddhistDate 97 extends ChronoDateImpl<ThaiBuddhistDate> 98 implements ChronoLocalDate<ThaiBuddhistDate>, Serializable { 99 100 /** 101 * Serialization version. 102 */ 103 private static final long serialVersionUID = -8722293800195731463L; 104 105 /** 106 * The underlying date. 107 */ 108 private final LocalDate isoDate; 109 110 //----------------------------------------------------------------------- 111 /** 112 * Obtains the current {@code ThaiBuddhistDate} from the system clock in the default time-zone. 113 * <p> 114 * This will query the {@link Clock#systemDefaultZone() system clock} in the default 115 * time-zone to obtain the current date. 116 * <p> 117 * Using this method will prevent the ability to use an alternate clock for testing 118 * because the clock is hard-coded. 119 * 120 * @return the current date using the system clock and default time-zone, not null 121 */ 122 public static ThaiBuddhistDate now() { 123 return now(Clock.systemDefaultZone()); 124 } 125 126 /** 127 * Obtains the current {@code ThaiBuddhistDate} from the system clock in the specified time-zone. 128 * <p> 129 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. 130 * Specifying the time-zone avoids dependence on the default time-zone. 131 * <p> 132 * Using this method will prevent the ability to use an alternate clock for testing 133 * because the clock is hard-coded. 134 * 135 * @param zone the zone ID to use, not null 136 * @return the current date using the system clock, not null 137 */ 138 public static ThaiBuddhistDate now(ZoneId zone) { 139 return now(Clock.system(zone)); 140 } 141 142 /** 143 * Obtains the current {@code ThaiBuddhistDate} from the specified clock. 144 * <p> 145 * This will query the specified clock to obtain the current date - today. 146 * Using this method allows the use of an alternate clock for testing. 147 * The alternate clock may be introduced using {@linkplain Clock dependency injection}. 148 * 149 * @param clock the clock to use, not null 150 * @return the current date, not null 151 * @throws DateTimeException if the current date cannot be obtained 152 */ 153 public static ThaiBuddhistDate now(Clock clock) { 154 return ThaiBuddhistChronology.INSTANCE.date(LocalDate.now(clock)); 155 } 156 157 /** 158 * Obtains a {@code ThaiBuddhistDate} representing a date in the Thai Buddhist calendar 159 * system from the proleptic-year, month-of-year and day-of-month fields. 160 * <p> 161 * This returns a {@code ThaiBuddhistDate} with the specified fields. 162 * The day must be valid for the year and month, otherwise an exception will be thrown. 163 * 164 * @param prolepticYear the Thai Buddhist proleptic-year 165 * @param month the Thai Buddhist month-of-year, from 1 to 12 166 * @param dayOfMonth the Thai Buddhist day-of-month, from 1 to 31 167 * @return the date in Thai Buddhist calendar system, not null 168 * @throws DateTimeException if the value of any field is out of range, 169 * or if the day-of-month is invalid for the month-year 170 */ 171 public static ThaiBuddhistDate of(int prolepticYear, int month, int dayOfMonth) { 172 return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth)); 173 } 174 175 /** 176 * Obtains a {@code ThaiBuddhistDate} from a temporal object. 177 * <p> 178 * This obtains a date in the Thai Buddhist calendar system based on the specified temporal. 179 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 180 * which this factory converts to an instance of {@code ThaiBuddhistDate}. 181 * <p> 182 * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY} 183 * field, which is standardized across calendar systems. 184 * <p> 185 * This method matches the signature of the functional interface {@link TemporalQuery} 186 * allowing it to be used as a query via method reference, {@code ThaiBuddhistDate::from}. 187 * 188 * @param temporal the temporal object to convert, not null 189 * @return the date in Thai Buddhist calendar system, not null 190 * @throws DateTimeException if unable to convert to a {@code ThaiBuddhistDate} 191 */ 192 public static ThaiBuddhistDate from(TemporalAccessor temporal) { 193 return ThaiBuddhistChronology.INSTANCE.date(temporal); 194 } 195 196 //----------------------------------------------------------------------- 197 /** 198 * Creates an instance from an ISO date. 199 * 200 * @param isoDate the standard local date, validated not null 201 */ 202 ThaiBuddhistDate(LocalDate isoDate) { 203 Objects.requireNonNull(isoDate, "isoDate"); 204 this.isoDate = isoDate; 205 } 206 207 //----------------------------------------------------------------------- 208 @Override 209 public ThaiBuddhistChronology getChronology() { 210 return ThaiBuddhistChronology.INSTANCE; 211 } 212 213 @Override 214 public int lengthOfMonth() { 215 return isoDate.lengthOfMonth(); 216 } 217 218 @Override 219 public ValueRange range(TemporalField field) { 220 if (field instanceof ChronoField) { 221 if (isSupported(field)) { 222 ChronoField f = (ChronoField) field; 223 switch (f) { 224 case DAY_OF_MONTH: 225 case DAY_OF_YEAR: 226 case ALIGNED_WEEK_OF_MONTH: 227 return isoDate.range(field); 228 case YEAR_OF_ERA: { 229 ValueRange range = YEAR.range(); 230 long max = (getProlepticYear() <= 0 ? -(range.getMinimum() + YEARS_DIFFERENCE) + 1 : range.getMaximum() + YEARS_DIFFERENCE); 231 return ValueRange.of(1, max); 232 } 233 } 234 return getChronology().range(f); 235 } 236 throw new DateTimeException("Unsupported field: " + field.getName()); 237 } 238 return field.rangeRefinedBy(this); 239 } 240 241 @Override 242 public long getLong(TemporalField field) { 243 if (field instanceof ChronoField) { 244 switch ((ChronoField) field) { 245 case YEAR_OF_ERA: { 246 int prolepticYear = getProlepticYear(); 247 return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear); 248 } 249 case YEAR: 250 return getProlepticYear(); 251 case ERA: 252 return (getProlepticYear() >= 1 ? 1 : 0); 253 } 254 return isoDate.getLong(field); 255 } 256 return field.getFrom(this); 257 } 258 259 private int getProlepticYear() { 260 return isoDate.getYear() + YEARS_DIFFERENCE; 261 } 262 263 //----------------------------------------------------------------------- 264 @Override 265 public ThaiBuddhistDate with(TemporalField field, long newValue) { 266 if (field instanceof ChronoField) { 267 ChronoField f = (ChronoField) field; 268 if (getLong(f) == newValue) { 269 return this; 270 } 271 switch (f) { 272 case YEAR_OF_ERA: 273 case YEAR: 274 case ERA: { 275 f.checkValidValue(newValue); 276 int nvalue = (int) newValue; 277 switch (f) { 278 case YEAR_OF_ERA: 279 return with(isoDate.withYear((getProlepticYear() >= 1 ? nvalue : 1 - nvalue) - YEARS_DIFFERENCE)); 280 case YEAR: 281 return with(isoDate.withYear(nvalue - YEARS_DIFFERENCE)); 282 case ERA: 283 return with(isoDate.withYear((1 - getProlepticYear()) - YEARS_DIFFERENCE)); 284 } 285 } 286 } 287 return with(isoDate.with(field, newValue)); 288 } 289 return (ThaiBuddhistDate) ChronoLocalDate.super.with(field, newValue); 290 } 291 292 /** 293 * {@inheritDoc} 294 * @throws DateTimeException {@inheritDoc} 295 * @throws ArithmeticException {@inheritDoc} 296 */ 297 @Override 298 public ThaiBuddhistDate with(TemporalAdjuster adjuster) { 299 return (ThaiBuddhistDate)super.with(adjuster); 300 } 301 302 /** 303 * {@inheritDoc} 304 * @throws DateTimeException {@inheritDoc} 305 * @throws ArithmeticException {@inheritDoc} 306 */ 307 @Override 308 public ThaiBuddhistDate plus(TemporalAmount amount) { 309 return (ThaiBuddhistDate)super.plus(amount); 310 } 311 312 /** 313 * {@inheritDoc} 314 * @throws DateTimeException {@inheritDoc} 315 * @throws ArithmeticException {@inheritDoc} 316 */ 317 @Override 318 public ThaiBuddhistDate minus(TemporalAmount amount) { 319 return (ThaiBuddhistDate)super.minus(amount); 320 } 321 322 //----------------------------------------------------------------------- 323 @Override 324 ThaiBuddhistDate plusYears(long years) { 325 return with(isoDate.plusYears(years)); 326 } 327 328 @Override 329 ThaiBuddhistDate plusMonths(long months) { 330 return with(isoDate.plusMonths(months)); 331 } 332 333 @Override 334 ThaiBuddhistDate plusWeeks(long weeksToAdd) { 335 return (ThaiBuddhistDate)super.plusWeeks(weeksToAdd); 336 } 337 338 @Override 339 ThaiBuddhistDate plusDays(long days) { 340 return with(isoDate.plusDays(days)); 341 } 342 343 @Override 344 public ThaiBuddhistDate plus(long amountToAdd, TemporalUnit unit) { 345 return (ThaiBuddhistDate)super.plus(amountToAdd, unit); 346 } 347 348 @Override 349 public ThaiBuddhistDate minus(long amountToAdd, TemporalUnit unit) { 350 return (ThaiBuddhistDate)super.minus(amountToAdd, unit); 351 } 352 353 @Override 354 ThaiBuddhistDate minusYears(long yearsToSubtract) { 355 return (ThaiBuddhistDate)super.minusYears(yearsToSubtract); 356 } 357 358 @Override 359 ThaiBuddhistDate minusMonths(long monthsToSubtract) { 360 return (ThaiBuddhistDate)super.minusMonths(monthsToSubtract); 361 } 362 363 @Override 364 ThaiBuddhistDate minusWeeks(long weeksToSubtract) { 365 return (ThaiBuddhistDate)super.minusWeeks(weeksToSubtract); 366 } 367 368 @Override 369 ThaiBuddhistDate minusDays(long daysToSubtract) { 370 return (ThaiBuddhistDate)super.minusDays(daysToSubtract); 371 } 372 373 private ThaiBuddhistDate with(LocalDate newDate) { 374 return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate)); 375 } 376 377 @Override // for javadoc and covariant return type 378 public final ChronoLocalDateTime<ThaiBuddhistDate> atTime(LocalTime localTime) { 379 return (ChronoLocalDateTime<ThaiBuddhistDate>)super.atTime(localTime); 380 } 381 382 @Override 383 public Period periodUntil(ChronoLocalDate<?> endDate) { 384 return isoDate.periodUntil(endDate); 385 } 386 387 @Override // override for performance 388 public long toEpochDay() { 389 return isoDate.toEpochDay(); 390 } 391 392 //------------------------------------------------------------------------- 393 @Override // override for performance 394 public boolean equals(Object obj) { 395 if (this == obj) { 396 return true; 397 } 398 if (obj instanceof ThaiBuddhistDate) { 399 ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj; 400 return this.isoDate.equals(otherDate.isoDate); 401 } 402 return false; 403 } 404 405 @Override // override for performance 406 public int hashCode() { 407 return getChronology().getId().hashCode() ^ isoDate.hashCode(); 408 } 409 410 //----------------------------------------------------------------------- 411 private Object writeReplace() { 412 return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this); 413 } 414 415 void writeExternal(DataOutput out) throws IOException { 416 // ThaiBuddhistChronology is implicit in the THAIBUDDHIST_DATE_TYPE 417 out.writeInt(this.get(YEAR)); 418 out.writeByte(this.get(MONTH_OF_YEAR)); 419 out.writeByte(this.get(DAY_OF_MONTH)); 420 } 421 422 static ThaiBuddhistDate readExternal(DataInput in) throws IOException { 423 int year = in.readInt(); 424 int month = in.readByte(); 425 int dayOfMonth = in.readByte(); 426 return ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth); 427 } 428 429 } |