1 /* 2 * hunt-time: A time library for D programming language. 3 * 4 * Copyright (C) 2015-2018 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.time.chrono.Chronology; 13 14 import hunt.time.temporal.ChronoField; 15 16 import hunt.time.Clock; 17 import hunt.time.Exceptions; 18 import hunt.time.Instant; 19 import hunt.time.LocalDate; 20 import hunt.time.LocalTime; 21 import hunt.time.ZoneId; 22 import hunt.time.ZoneOffset; 23 // import hunt.time.format.DateTimeFormatterBuilder; 24 import hunt.time.format.ResolverStyle; 25 import hunt.time.format.TextStyle; 26 import hunt.time.temporal.ChronoField; 27 import hunt.time.temporal.TemporalAccessor; 28 import hunt.time.temporal.TemporalField; 29 import hunt.time.temporal.TemporalQueries; 30 import hunt.time.temporal.TemporalQuery; 31 import hunt.time.Exceptions; 32 import hunt.time.temporal.ValueRange; 33 import hunt.time.chrono.ChronoLocalDate; 34 import hunt.time.chrono.Era; 35 import hunt.time.chrono.ChronoZonedDateTime; 36 import hunt.time.chrono.ChronoLocalDateTime; 37 import hunt.time.chrono.ChronoPeriod; 38 import hunt.time.chrono.AbstractChronology; 39 import hunt.time.chrono.IsoChronology; 40 import hunt.time.util.QueryHelper; 41 42 import hunt.collection.List; 43 import hunt.collection.Map; 44 import hunt.collection.Set; 45 import hunt.Functions; 46 import hunt.Long; 47 import hunt.util.Common; 48 import hunt.util.Locale; 49 50 51 /** 52 * A calendar system, used to organize and identify dates. 53 * !(p) 54 * The main date and time API is built on the ISO calendar system. 55 * The chronology operates behind the scenes to represent the general concept of a calendar system. 56 * For example, the Japanese, Minguo, Thai Buddhist and others. 57 * !(p) 58 * Most other calendar systems also operate on the shared concepts of year, month and day, 59 * linked to the cycles of the Earth around the Sun, and the Moon around the Earth. 60 * These shared concepts are defined by {@link ChronoField} and are available 61 * for use by any {@code Chronology} implementation: 62 * !(pre) 63 * LocalDate isoDate = ... 64 * ThaiBuddhistDate thaiDate = ... 65 * int isoYear = isoDate.get(ChronoField.YEAR); 66 * int thaiYear = thaiDate.get(ChronoField.YEAR); 67 * </pre> 68 * As shown, although the date objects are _in different calendar systems, represented by different 69 * {@code Chronology} instances, both can be queried using the same constant on {@code ChronoField}. 70 * For a full discussion of the implications of this, see {@link ChronoLocalDate}. 71 * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than 72 * {@code ChronoLocalDate}. 73 * !(p) 74 * While a {@code Chronology} object typically uses {@code ChronoField} and is based on 75 * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required. 76 * A {@code Chronology} instance may represent a totally different kind of calendar system, 77 * such as the Mayan. 78 * !(p) 79 * In practical terms, the {@code Chronology} instance also acts as a factory. 80 * The {@link #of(string)} method allows an instance to be looked up by identifier, 81 * while the {@link #ofLocale(Locale)} method allows lookup by locale. 82 * !(p) 83 * The {@code Chronology} instance provides a set of methods to create {@code ChronoLocalDate} instances. 84 * The date classes are used to manipulate specific dates. 85 * !(ul) 86 * !(li) {@link #dateNow() dateNow()} 87 * !(li) {@link #dateNow(Clock) dateNow(clock)} 88 * !(li) {@link #dateNow(ZoneId) dateNow(zone)} 89 * !(li) {@link #date(int, int, int) date(yearProleptic, month, day)} 90 * !(li) {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)} 91 * !(li) {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)} 92 * !(li) {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)} 93 * !(li) {@link #date(TemporalAccessor) date(TemporalAccessor)} 94 * </ul> 95 * 96 * <h3 id="addcalendars">Adding New Calendars</h3> 97 * The set of available chronologies can be extended by applications. 98 * Adding a new calendar system requires the writing of an implementation of 99 * {@code Chronology}, {@code ChronoLocalDate} and {@code Era}. 100 * The majority of the logic specific to the calendar system will be _in the 101 * {@code ChronoLocalDate} implementation. 102 * The {@code Chronology} implementation acts as a factory. 103 * !(p) 104 * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader} 105 * is used. A file must be added to the {@code META-INF/services} directory with the 106 * name 'hunt.time.chrono.Chronology' listing the implementation classes. 107 * See the ServiceLoader for more details on service loading. 108 * For lookup by id or calendarType, the system provided calendars are found 109 * first followed by application provided calendars. 110 * !(p) 111 * Each chronology must define a chronology ID that is unique within the system. 112 * If the chronology represents a calendar system defined by the 113 * CLDR specification then the calendar type is the concatenation of the 114 * CLDR type and, if applicable, the CLDR variant. 115 * 116 * @implSpec 117 * This interface must be implemented with care to ensure other classes operate correctly. 118 * All implementations that can be instantiated must be final, immutable and thread-safe. 119 * Subclasses should be Serializable wherever possible. 120 * 121 * @since 1.8 122 */ 123 public interface Chronology : Comparable!(Chronology) { 124 125 /** 126 * Obtains an instance of {@code Chronology} from a temporal object. 127 * !(p) 128 * This obtains a chronology based on the specified temporal. 129 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 130 * which this factory converts to an instance of {@code Chronology}. 131 * !(p) 132 * The conversion will obtain the chronology using {@link TemporalQueries#chronology()}. 133 * If the specified temporal object does not have a chronology, {@link IsoChronology} is returned. 134 * !(p) 135 * This method matches the signature of the functional interface {@link TemporalQuery} 136 * allowing it to be used as a query via method reference, {@code Chronology::from}. 137 * 138 * @param temporal the temporal to convert, not null 139 * @return the chronology, not null 140 * @throws DateTimeException if unable to convert to a {@code Chronology} 141 */ 142 static Chronology from(TemporalAccessor temporal) { 143 assert(temporal, "temporal"); 144 Chronology obj = QueryHelper.query!Chronology(temporal,TemporalQueries.chronology()); 145 return obj !is null ? obj : IsoChronology.INSTANCE; 146 } 147 148 //----------------------------------------------------------------------- 149 /** 150 * Obtains an instance of {@code Chronology} from a locale. 151 * !(p) 152 * This returns a {@code Chronology} based on the specified locale, 153 * typically returning {@code IsoChronology}. Other calendar systems 154 * are only returned if they are explicitly selected within the locale. 155 * !(p) 156 * The {@link Locale} class provide access to a range of information useful 157 * for localizing an application. This includes the language and region, 158 * such as "en-GB" for English as used _in Great Britain. 159 * !(p) 160 * The {@code Locale} class also supports an extension mechanism that 161 * can be used to identify a calendar system. The mechanism is a form 162 * of key-value pairs, where the calendar system has the key "ca". 163 * For example, the locale "en-JP-u-ca-japanese" represents the English 164 * language as used _in Japan with the Japanese calendar system. 165 * !(p) 166 * This method finds the desired calendar system _in a manner equivalent 167 * to passing "ca" to {@link Locale#getUnicodeLocaleType(string)}. 168 * If the "ca" key is not present, then {@code IsoChronology} is returned. 169 * !(p) 170 * Note that the behavior of this method differs from the older 171 * {@link java.util.Calendar#getInstance(Locale)} method. 172 * If that method receives a locale of "th_TH" it will return {@code BuddhistCalendar}. 173 * By contrast, this method will return {@code IsoChronology}. 174 * Passing the locale "th-TH-u-ca-buddhist" into either method will 175 * result _in the Thai Buddhist calendar system and is therefore the 176 * recommended approach going forward for Thai calendar system localization. 177 * !(p) 178 * A similar, but simpler, situation occurs for the Japanese calendar system. 179 * The locale "jp_JP_JP" has previously been used to access the calendar. 180 * However, unlike the Thai locale, "ja_JP_JP" is automatically converted by 181 * {@code Locale} to the modern and recommended form of "ja-JP-u-ca-japanese". 182 * Thus, there is no difference _in behavior between this method and 183 * {@code Calendar#getInstance(Locale)}. 184 * 185 * @param locale the locale to use to obtain the calendar system, not null 186 * @return the calendar system associated with the locale, not null 187 * @throws DateTimeException if the locale-specified calendar cannot be found 188 */ 189 static Chronology ofLocale(Locale locale) { 190 return AbstractChronology.ofLocale(locale); 191 } 192 193 //----------------------------------------------------------------------- 194 /** 195 * Obtains an instance of {@code Chronology} from a chronology ID or 196 * calendar system type. 197 * !(p) 198 * This returns a chronology based on either the ID or the type. 199 * The {@link #getId() chronology ID} uniquely identifies the chronology. 200 * The {@link #getCalendarType() calendar system type} is defined by the 201 * CLDR specification. 202 * !(p) 203 * The chronology may be a system chronology or a chronology 204 * provided by the application via ServiceLoader configuration. 205 * !(p) 206 * Since some calendars can be customized, the ID or type typically refers 207 * to the customization. For example, the Gregorian calendar can have multiple 208 * cutover dates from the Julian, but the lookup only provides the cutover date. 209 * 210 * @param id the chronology ID or calendar system type, not null 211 * @return the chronology with the identifier requested, not null 212 * @throws DateTimeException if the chronology cannot be found 213 */ 214 static Chronology of(string id) { 215 return AbstractChronology.of(id); 216 } 217 218 /** 219 * Returns the available chronologies. 220 * !(p) 221 * Each returned {@code Chronology} is available for use _in the system. 222 * The set of chronologies includes the system chronologies and 223 * any chronologies provided by the application via ServiceLoader 224 * configuration. 225 * 226 * @return the independent, modifiable set of the available chronology IDs, not null 227 */ 228 static Set!(Chronology) getAvailableChronologies() { 229 return AbstractChronology.getAvailableChronologies(); 230 } 231 232 //----------------------------------------------------------------------- 233 /** 234 * Gets the ID of the chronology. 235 * !(p) 236 * The ID uniquely identifies the {@code Chronology}. 237 * It can be used to lookup the {@code Chronology} using {@link #of(string)}. 238 * 239 * @return the chronology ID, not null 240 * @see #getCalendarType() 241 */ 242 string getId(); 243 244 /** 245 * Gets the calendar type of the calendar system. 246 * !(p) 247 * The calendar type is an identifier defined by the CLDR and 248 * !(em)Unicode Locale Data Markup Language (LDML)</em> specifications 249 * to uniquely identify a calendar. 250 * The {@code getCalendarType} is the concatenation of the CLDR calendar type 251 * and the variant, if applicable, is appended separated by "-". 252 * The calendar type is used to lookup the {@code Chronology} using {@link #of(string)}. 253 * 254 * @return the calendar system type, null if the calendar is not defined by CLDR/LDML 255 * @see #getId() 256 */ 257 string getCalendarType(); 258 259 //----------------------------------------------------------------------- 260 /** 261 * Obtains a local date _in this chronology from the era, year-of-era, 262 * month-of-year and day-of-month fields. 263 * 264 * @implSpec 265 * The implementation combines the era and year-of-era into a proleptic 266 * year before calling {@link #date(int, int, int)}. 267 * 268 * @param era the era of the correct type for the chronology, not null 269 * @param yearOfEra the chronology year-of-era 270 * @param month the chronology month-of-year 271 * @param dayOfMonth the chronology day-of-month 272 * @return the local date _in this chronology, not null 273 * @throws DateTimeException if unable to create the date 274 * @throws ClassCastException if the {@code era} is not of the correct type for the chronology 275 */ 276 ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth); 277 // ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { 278 // return date(prolepticYear(era, yearOfEra), month, dayOfMonth); 279 // } 280 281 /** 282 * Obtains a local date _in this chronology from the proleptic-year, 283 * month-of-year and day-of-month fields. 284 * 285 * @param prolepticYear the chronology proleptic-year 286 * @param month the chronology month-of-year 287 * @param dayOfMonth the chronology day-of-month 288 * @return the local date _in this chronology, not null 289 * @throws DateTimeException if unable to create the date 290 */ 291 ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); 292 293 /** 294 * Obtains a local date _in this chronology from the era, year-of-era and 295 * day-of-year fields. 296 * 297 * @implSpec 298 * The implementation combines the era and year-of-era into a proleptic 299 * year before calling {@link #dateYearDay(int, int)}. 300 * 301 * @param era the era of the correct type for the chronology, not null 302 * @param yearOfEra the chronology year-of-era 303 * @param dayOfYear the chronology day-of-year 304 * @return the local date _in this chronology, not null 305 * @throws DateTimeException if unable to create the date 306 * @throws ClassCastException if the {@code era} is not of the correct type for the chronology 307 */ 308 ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear); 309 // ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { 310 // return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); 311 // } 312 313 /** 314 * Obtains a local date _in this chronology from the proleptic-year and 315 * day-of-year fields. 316 * 317 * @param prolepticYear the chronology proleptic-year 318 * @param dayOfYear the chronology day-of-year 319 * @return the local date _in this chronology, not null 320 * @throws DateTimeException if unable to create the date 321 */ 322 ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); 323 324 /** 325 * Obtains a local date _in this chronology from the epoch-day. 326 * !(p) 327 * The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same 328 * for all calendar systems, thus it can be used for conversion. 329 * 330 * @param epochDay the epoch day 331 * @return the local date _in this chronology, not null 332 * @throws DateTimeException if unable to create the date 333 */ 334 ChronoLocalDate dateEpochDay(long epochDay); 335 336 //----------------------------------------------------------------------- 337 /** 338 * Obtains the current local date _in this chronology from the system clock _in the time-zone. 339 * !(p) 340 * This will query the {@link Clock#systemDefaultZone() system clock} _in the 341 * time-zone to obtain the current date. 342 * !(p) 343 * Using this method will prevent the ability to use an alternate clock for testing 344 * because the clock is hard-coded. 345 * 346 * @implSpec 347 * The implementation invokes {@link #dateNow(Clock)}. 348 * 349 * @return the current local date using the system clock and time-zone, not null 350 * @throws DateTimeException if unable to create the date 351 */ 352 ChronoLocalDate dateNow(); 353 // ChronoLocalDate dateNow() { 354 // return dateNow(Clock.systemDefaultZone()); 355 // } 356 357 /** 358 * Obtains the current local date _in this chronology from the system clock _in the specified time-zone. 359 * !(p) 360 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. 361 * Specifying the time-zone avoids dependence on the time-zone. 362 * !(p) 363 * Using this method will prevent the ability to use an alternate clock for testing 364 * because the clock is hard-coded. 365 * 366 * @implSpec 367 * The implementation invokes {@link #dateNow(Clock)}. 368 * 369 * @param zone the zone ID to use, not null 370 * @return the current local date using the system clock, not null 371 * @throws DateTimeException if unable to create the date 372 */ 373 ChronoLocalDate dateNow(ZoneId zone); 374 // ChronoLocalDate dateNow(ZoneId zone) { 375 // return dateNow(Clock.system(zone)); 376 // } 377 378 /** 379 * Obtains the current local date _in this chronology from the specified clock. 380 * !(p) 381 * This will query the specified clock to obtain the current date - today. 382 * Using this method allows the use of an alternate clock for testing. 383 * The alternate clock may be introduced using {@link Clock dependency injection}. 384 * 385 * @implSpec 386 * The implementation invokes {@link #date(TemporalAccessor)}. 387 * 388 * @param clock the clock to use, not null 389 * @return the current local date, not null 390 * @throws DateTimeException if unable to create the date 391 */ 392 ChronoLocalDate dateNow(Clock clock); 393 // ChronoLocalDate dateNow(Clock clock) { 394 // assert(clock, "clock"); 395 // return date(LocalDate.now(clock)); 396 // } 397 398 //----------------------------------------------------------------------- 399 /** 400 * Obtains a local date _in this chronology from another temporal object. 401 * !(p) 402 * This obtains a date _in this chronology based on the specified temporal. 403 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 404 * which this factory converts to an instance of {@code ChronoLocalDate}. 405 * !(p) 406 * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY} 407 * field, which is standardized across calendar systems. 408 * !(p) 409 * This method matches the signature of the functional interface {@link TemporalQuery} 410 * allowing it to be used as a query via method reference, {@code aChronology::date}. 411 * 412 * @param temporal the temporal object to convert, not null 413 * @return the local date _in this chronology, not null 414 * @throws DateTimeException if unable to create the date 415 * @see ChronoLocalDate#from(TemporalAccessor) 416 */ 417 ChronoLocalDate date(TemporalAccessor temporal); 418 419 /** 420 * Obtains a local date-time _in this chronology from another temporal object. 421 * !(p) 422 * This obtains a date-time _in this chronology based on the specified temporal. 423 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 424 * which this factory converts to an instance of {@code ChronoLocalDateTime}. 425 * !(p) 426 * The conversion extracts and combines the {@code ChronoLocalDate} and the 427 * {@code LocalTime} from the temporal object. 428 * Implementations are permitted to perform optimizations such as accessing 429 * those fields that are equivalent to the relevant objects. 430 * The result uses this chronology. 431 * !(p) 432 * This method matches the signature of the functional interface {@link TemporalQuery} 433 * allowing it to be used as a query via method reference, {@code aChronology::localDateTime}. 434 * 435 * @param temporal the temporal object to convert, not null 436 * @return the local date-time _in this chronology, not null 437 * @throws DateTimeException if unable to create the date-time 438 * @see ChronoLocalDateTime#from(TemporalAccessor) 439 */ 440 ChronoLocalDateTime!(ChronoLocalDate) localDateTime(TemporalAccessor temporal); 441 // ChronoLocalDateTime!(ChronoLocalDate) localDateTime(TemporalAccessor temporal) { 442 // try { 443 // return date(temporal).atTime(LocalTime.from(temporal)); 444 // } catch (DateTimeException ex) { 445 // throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " ~ typeid(temporal).stringof, ex); 446 // } 447 // } 448 449 /** 450 * Obtains a {@code ChronoZonedDateTime} _in this chronology from another temporal object. 451 * !(p) 452 * This obtains a zoned date-time _in this chronology based on the specified temporal. 453 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 454 * which this factory converts to an instance of {@code ChronoZonedDateTime}. 455 * !(p) 456 * The conversion will first obtain a {@code ZoneId} from the temporal object, 457 * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain 458 * an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary. 459 * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset} 460 * with {@code Instant} or {@code ChronoLocalDateTime}. 461 * Implementations are permitted to perform optimizations such as accessing 462 * those fields that are equivalent to the relevant objects. 463 * The result uses this chronology. 464 * !(p) 465 * This method matches the signature of the functional interface {@link TemporalQuery} 466 * allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}. 467 * 468 * @param temporal the temporal object to convert, not null 469 * @return the zoned date-time _in this chronology, not null 470 * @throws DateTimeException if unable to create the date-time 471 * @see ChronoZonedDateTime#from(TemporalAccessor) 472 */ 473 ChronoZonedDateTime!(ChronoLocalDate) zonedDateTime(TemporalAccessor temporal); 474 // ChronoZonedDateTime!(ChronoLocalDate) zonedDateTime(TemporalAccessor temporal) { 475 // try { 476 // ZoneId zone = ZoneId.from(temporal); 477 // try { 478 // Instant instant = Instant.from(temporal); 479 // return zonedDateTime(instant, zone); 480 481 // } catch (DateTimeException ex1) { 482 // ChronoLocalDateTimeImpl!(Object) cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal)); 483 // return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null); 484 // } 485 // } catch (DateTimeException ex) { 486 // throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " ~ typeid(temporal).stringof, ex); 487 // } 488 // } 489 490 /** 491 * Obtains a {@code ChronoZonedDateTime} _in this chronology from an {@code Instant}. 492 * !(p) 493 * This obtains a zoned date-time with the same instant as that specified. 494 * 495 * @param instant the instant to create the date-time from, not null 496 * @param zone the time-zone, not null 497 * @return the zoned date-time, not null 498 * @throws DateTimeException if the result exceeds the supported range 499 */ 500 ChronoZonedDateTime!(ChronoLocalDate) zonedDateTime(Instant instant, ZoneId zone); 501 // ChronoZonedDateTime!(ChronoLocalDate) zonedDateTime(Instant instant, ZoneId zone) { 502 // return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone); 503 // } 504 505 //----------------------------------------------------------------------- 506 /** 507 * Checks if the specified year is a leap year. 508 * !(p) 509 * A leap-year is a year of a longer length than normal. 510 * The exact meaning is determined by the chronology according to the following constraints. 511 * !(ul) 512 * !(li)a leap-year must imply a year-length longer than a non leap-year. 513 * !(li)a chronology that does not support the concept of a year must return false. 514 * !(li)the correct result must be returned for all years within the 515 * valid range of years for the chronology. 516 * </ul> 517 * !(p) 518 * Outside the range of valid years an implementation is free to return 519 * either a best guess or false. 520 * An implementation must not throw an exception, even if the year is 521 * outside the range of valid years. 522 * 523 * @param prolepticYear the proleptic-year to check, not validated for range 524 * @return true if the year is a leap year 525 */ 526 bool isLeapYear(long prolepticYear); 527 528 /** 529 * Calculates the proleptic-year given the era and year-of-era. 530 * !(p) 531 * This combines the era and year-of-era into the single proleptic-year field. 532 * !(p) 533 * If the chronology makes active use of eras, such as {@code JapaneseChronology} 534 * then the year-of-era will be validated against the era. 535 * For other chronologies, validation is optional. 536 * 537 * @param era the era of the correct type for the chronology, not null 538 * @param yearOfEra the chronology year-of-era 539 * @return the proleptic-year 540 * @throws DateTimeException if unable to convert to a proleptic-year, 541 * such as if the year is invalid for the era 542 * @throws ClassCastException if the {@code era} is not of the correct type for the chronology 543 */ 544 int prolepticYear(Era era, int yearOfEra); 545 546 /** 547 * Creates the chronology era object from the numeric value. 548 * !(p) 549 * The era is, conceptually, the largest division of the time-line. 550 * Most calendar systems have a single epoch dividing the time-line into two eras. 551 * However, some have multiple eras, such as one for the reign of each leader. 552 * The exact meaning is determined by the chronology according to the following constraints. 553 * !(p) 554 * The era _in use at 1970-01-01 must have the value 1. 555 * Later eras must have sequentially higher values. 556 * Earlier eras must have sequentially lower values. 557 * Each chronology must refer to an enum or similar singleton to provide the era values. 558 * !(p) 559 * This method returns the singleton era of the correct type for the specified era value. 560 * 561 * @param eraValue the era value 562 * @return the calendar system era, not null 563 * @throws DateTimeException if unable to create the era 564 */ 565 Era eraOf(int eraValue); 566 567 /** 568 * Gets the list of eras for the chronology. 569 * !(p) 570 * Most calendar systems have an era, within which the year has meaning. 571 * If the calendar system does not support the concept of eras, an empty 572 * list must be returned. 573 * 574 * @return the list of eras for the chronology, may be immutable, not null 575 */ 576 List!(Era) eras(); 577 578 //----------------------------------------------------------------------- 579 /** 580 * Gets the range of valid values for the specified field. 581 * !(p) 582 * All fields can be expressed as a {@code long} integer. 583 * This method returns an object that describes the valid range for that value. 584 * !(p) 585 * Note that the result only describes the minimum and maximum valid values 586 * and it is important not to read too much into them. For example, there 587 * could be values within the range that are invalid for the field. 588 * !(p) 589 * This method will return a result whether or not the chronology supports the field. 590 * 591 * @param field the field to get the range for, not null 592 * @return the range of valid values for the field, not null 593 * @throws DateTimeException if the range for the field cannot be obtained 594 */ 595 ValueRange range(ChronoField field); 596 597 //----------------------------------------------------------------------- 598 /** 599 * Gets the textual representation of this chronology. 600 * !(p) 601 * This returns the textual name used to identify the chronology, 602 * suitable for presentation to the user. 603 * The parameters control the style of the returned text and the locale. 604 * 605 * @implSpec 606 * The implementation behaves as though the formatter was used to 607 * format the chronology textual name. 608 * 609 * @param style the style of the text required, not null 610 * @param locale the locale to use, not null 611 * @return the text value of the chronology, not null 612 */ 613 // string getDisplayName(TextStyle style, Locale locale); 614 // string getDisplayName(TextStyle style, Locale locale) { 615 // TemporalAccessor temporal = new class TemporalAccessor{ 616 // override 617 // public bool isSupported(TemporalField field) { 618 // return false; 619 // } 620 // override 621 // public long getLong(TemporalField field) { 622 // throw new UnsupportedTemporalTypeException("Unsupported field: " ~ field); 623 // } 624 // /*@SuppressWarnings("unchecked")*/ 625 // override 626 // public R query(TemporalQuery!(R) query) { 627 // if (query == TemporalQueries.chronology()) { 628 // return cast(R) /* Chronology. */this; 629 // } 630 // return /* TemporalAccessor. */super.query(query); 631 // } 632 // }; 633 // return new DateTimeFormatterBuilder().appendChronologyText(style).toFormatter(locale).format(temporal); 634 // } 635 636 //----------------------------------------------------------------------- 637 /** 638 * Resolves parsed {@code ChronoField} values into a date during parsing. 639 * !(p) 640 * Most {@code TemporalField} implementations are resolved using the 641 * resolve method on the field. By contrast, the {@code ChronoField} class 642 * defines fields that only have meaning relative to the chronology. 643 * As such, {@code ChronoField} date fields are resolved here _in the 644 * context of a specific chronology. 645 * !(p) 646 * The implementation, which explains typical resolve behaviour, 647 * is provided _in {@link AbstractChronology}. 648 * 649 * @param fieldValues the map of fields to values, which can be updated, not null 650 * @param resolverStyle the requested type of resolve, not null 651 * @return the resolved date, null if insufficient information to create a date 652 * @throws DateTimeException if the date cannot be resolved, typically 653 * because of a conflict _in the input data 654 */ 655 ChronoLocalDate resolveDate(Map!(TemporalField, Long) fieldValues, ResolverStyle resolverStyle); 656 657 //----------------------------------------------------------------------- 658 /** 659 * Obtains a period for this chronology based on years, months and days. 660 * !(p) 661 * This returns a period tied to this chronology using the specified 662 * years, months and days. All supplied chronologies use periods 663 * based on years, months and days, however the {@code ChronoPeriod} API 664 * allows the period to be represented using other units. 665 * 666 * @implSpec 667 * The implementation returns an implementation class suitable 668 * for most calendar systems. It is based solely on the three units. 669 * Normalization, addition and subtraction derive the number of months 670 * _in a year from the {@link #range(ChronoField)}. If the number of 671 * months within a year is fixed, then the calculation approach for 672 * addition, subtraction and normalization is slightly different. 673 * !(p) 674 * If implementing an unusual calendar system that is not based on 675 * years, months and days, or where you want direct control, then 676 * the {@code ChronoPeriod} interface must be directly implemented. 677 * !(p) 678 * The returned period is immutable and thread-safe. 679 * 680 * @param years the number of years, may be negative 681 * @param months the number of years, may be negative 682 * @param days the number of years, may be negative 683 * @return the period _in terms of this chronology, not null 684 */ 685 ChronoPeriod period(int years, int months, int days); 686 // ChronoPeriod period(int years, int months, int days) { 687 // return new ChronoPeriodImpl(this, years, months, days); 688 // } 689 690 //--------------------------------------------------------------------- 691 692 /** 693 * Gets the number of seconds from the epoch of 1970-01-01T00:00:00Z. 694 * !(p) 695 * The number of seconds is calculated using the proleptic-year, 696 * month, day-of-month, hour, minute, second, and zoneOffset. 697 * 698 * @param prolepticYear the chronology proleptic-year 699 * @param month the chronology month-of-year 700 * @param dayOfMonth the chronology day-of-month 701 * @param hour the hour-of-day, from 0 to 23 702 * @param minute the minute-of-hour, from 0 to 59 703 * @param second the second-of-minute, from 0 to 59 704 * @param zoneOffset the zone offset, not null 705 * @return the number of seconds relative to 1970-01-01T00:00:00Z, may be negative 706 * @throws DateTimeException if any of the values are _out of range 707 * @since 9 708 */ 709 long epochSecond(int prolepticYear, int month, int dayOfMonth, 710 int hour, int minute, int second, ZoneOffset zoneOffset) ; 711 // public long epochSecond(int prolepticYear, int month, int dayOfMonth, 712 // int hour, int minute, int second, ZoneOffset zoneOffset) { 713 // assert(zoneOffset, "zoneOffset"); 714 // HOUR_OF_DAY.checkValidValue(hour); 715 // MINUTE_OF_HOUR.checkValidValue(minute); 716 // SECOND_OF_MINUTE.checkValidValue(second); 717 // long daysInSec = Math.multiplyExact(date(prolepticYear, month, dayOfMonth).toEpochDay(), 86400); 718 // long timeinSec = (hour * 60 + minute) * 60 + second; 719 // return Math.addExact(daysInSec, timeinSec - zoneOffset.getTotalSeconds()); 720 // } 721 722 /** 723 * Gets the number of seconds from the epoch of 1970-01-01T00:00:00Z. 724 * !(p) 725 * The number of seconds is calculated using the era, year-of-era, 726 * month, day-of-month, hour, minute, second, and zoneOffset. 727 * 728 * @param era the era of the correct type for the chronology, not null 729 * @param yearOfEra the chronology year-of-era 730 * @param month the chronology month-of-year 731 * @param dayOfMonth the chronology day-of-month 732 * @param hour the hour-of-day, from 0 to 23 733 * @param minute the minute-of-hour, from 0 to 59 734 * @param second the second-of-minute, from 0 to 59 735 * @param zoneOffset the zone offset, not null 736 * @return the number of seconds relative to 1970-01-01T00:00:00Z, may be negative 737 * @throws DateTimeException if any of the values are _out of range 738 * @since 9 739 */ 740 long epochSecond(Era era, int yearOfEra, int month, int dayOfMonth, 741 int hour, int minute, int second, ZoneOffset zoneOffset); 742 // public long epochSecond(Era era, int yearOfEra, int month, int dayOfMonth, 743 // int hour, int minute, int second, ZoneOffset zoneOffset) { 744 // assert(era, "era"); 745 // return epochSecond(prolepticYear(era, yearOfEra), month, dayOfMonth, hour, minute, second, zoneOffset); 746 // } 747 //----------------------------------------------------------------------- 748 /** 749 * Compares this chronology to another chronology. 750 * !(p) 751 * The comparison order first by the chronology ID string, then by any 752 * additional information specific to the subclass. 753 * It is "consistent with equals", as defined by {@link Comparable}. 754 * 755 * @param other the other chronology to compare to, not null 756 * @return the comparator value, negative if less, positive if greater 757 */ 758 // override 759 int compareTo(Chronology other); 760 761 /** 762 * Checks if this chronology is equal to another chronology. 763 * !(p) 764 * The comparison is based on the entire state of the object. 765 * 766 * @param obj the object to check, null returns false 767 * @return true if this is equal to the other chronology 768 */ 769 // override 770 // bool opEquals(Object obj); 771 772 // bool opEquals(const(Object) obj); 773 774 /** 775 * A hash code for this chronology. 776 * !(p) 777 * The hash code should be based on the entire state of the object. 778 * 779 * @return a suitable hash code 780 */ 781 // override 782 size_t toHash() @trusted nothrow ; 783 // size_t toHash() @trusted nothrow; 784 785 //----------------------------------------------------------------------- 786 /** 787 * Outputs this chronology as a {@code string}. 788 * !(p) 789 * The format should include the entire state of the object. 790 * 791 * @return a string representation of this chronology, not null 792 */ 793 // override 794 string toString(); 795 796 797 }