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.ChronoZonedDateTime; 13 14 import hunt.time.temporal.ChronoField; 15 import hunt.time.temporal.ChronoUnit; 16 17 import hunt.stream.Common; 18 import hunt.time.Exceptions; 19 import hunt.time.Instant; 20 import hunt.time.LocalTime; 21 import hunt.time.ZoneId; 22 import hunt.time.ZoneOffset; 23 import hunt.time.ZonedDateTime; 24 // import hunt.time.format.DateTimeFormatter; 25 import hunt.time.temporal.ChronoField; 26 import hunt.time.temporal.ChronoUnit; 27 import hunt.time.temporal.Temporal; 28 import hunt.time.temporal.TemporalAccessor; 29 import hunt.time.temporal.TemporalAdjuster; 30 import hunt.time.temporal.TemporalAmount; 31 import hunt.time.temporal.TemporalField; 32 import hunt.time.temporal.TemporalQueries; 33 import hunt.time.temporal.TemporalQuery; 34 import hunt.time.temporal.TemporalUnit; 35 import hunt.time.Exceptions; 36 import hunt.time.temporal.ValueRange; 37 import hunt.util.Common; 38 import hunt.util.Comparator; 39 import hunt.time.chrono.ChronoLocalDate; 40 import hunt.Functions; 41 import hunt.time.chrono.ChronoLocalDateTime; 42 import hunt.time.chrono.Chronology; 43 import hunt.time.util.QueryHelper; 44 45 /** 46 * A date-time with a time-zone _in an arbitrary chronology, 47 * intended for advanced globalization use cases. 48 * !(p) 49 * !(b)Most applications should declare method signatures, fields and variables 50 * as {@link ZonedDateTime}, not this interface.</b> 51 * !(p) 52 * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time 53 * where the {@code Chronology chronology}, or calendar system, is pluggable. 54 * The date-time is defined _in terms of fields expressed by {@link TemporalField}, 55 * where most common implementations are defined _in {@link ChronoField}. 56 * The chronology defines how the calendar system operates and the meaning of 57 * the standard fields. 58 * 59 * !(h3)When to use this interface</h3> 60 * The design of the API encourages the use of {@code ZonedDateTime} rather than this 61 * interface, even _in the case where the application needs to deal with multiple 62 * calendar systems. The rationale for this is explored _in detail _in {@link ChronoLocalDate}. 63 * !(p) 64 * Ensure that the discussion _in {@code ChronoLocalDate} has been read and understood 65 * before using this interface. 66 * 67 * @implSpec 68 * This interface must be implemented with care to ensure other classes operate correctly. 69 * All implementations that can be instantiated must be final, immutable and thread-safe. 70 * Subclasses should be Serializable wherever possible. 71 * 72 * @param !(D) the concrete type for the date of this date-time 73 * @since 1.8 74 */ 75 public interface ChronoZonedDateTime(D = ChronoLocalDate) if(is(D : ChronoLocalDate)) 76 : Temporal, Comparable!(ChronoZonedDateTime!(D)) { 77 78 /** 79 * Gets a comparator that compares {@code ChronoZonedDateTime} _in 80 * time-line order ignoring the chronology. 81 * !(p) 82 * This comparator differs from the comparison _in {@link #compareTo} _in that it 83 * only compares the underlying instant and not the chronology. 84 * This allows dates _in different calendar systems to be compared based 85 * on the position of the date-time on the instant time-line. 86 * The underlying comparison is equivalent to comparing the epoch-second and nano-of-second. 87 * 88 * @return a comparator that compares _in time-line order ignoring the chronology 89 * @see #isAfter 90 * @see #isBefore 91 * @see #isEqual 92 */ 93 static Comparator!(ChronoZonedDateTime!(ChronoLocalDate)) timeLineOrder() { 94 return new class Comparator!(ChronoZonedDateTime!(ChronoLocalDate)) { 95 int compare(ChronoZonedDateTime!(ChronoLocalDate) dateTime1, 96 ChronoZonedDateTime!(ChronoLocalDate) dateTime2) nothrow { 97 try { 98 int cmp = hunt.util.Comparator.compare(dateTime1.toEpochSecond(), dateTime2.toEpochSecond()); 99 if (cmp == 0) { 100 cmp = hunt.util.Comparator.compare(dateTime1.toLocalTime().getNano(), dateTime2.toLocalTime().getNano()); 101 } 102 return cmp; 103 } catch(Exception) { 104 // FIXME: Needing refactor or cleanup -@zxp at 12/29/2018, 11:30:49 PM 105 // 106 return 0; 107 } 108 }; 109 }; 110 } 111 112 //----------------------------------------------------------------------- 113 /** 114 * Obtains an instance of {@code ChronoZonedDateTime} from a temporal object. 115 * !(p) 116 * This creates a zoned date-time based on the specified temporal. 117 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 118 * which this factory converts to an instance of {@code ChronoZonedDateTime}. 119 * !(p) 120 * The conversion extracts and combines the chronology, date, time and zone 121 * from the temporal object. The behavior is equivalent to using 122 * {@link Chronology#zonedDateTime(TemporalAccessor)} with the extracted chronology. 123 * Implementations are permitted to perform optimizations such as accessing 124 * those fields that are equivalent to the relevant objects. 125 * !(p) 126 * This method matches the signature of the functional interface {@link TemporalQuery} 127 * allowing it to be used as a query via method reference, {@code ChronoZonedDateTime::from}. 128 * 129 * @param temporal the temporal object to convert, not null 130 * @return the date-time, not null 131 * @throws DateTimeException if unable to convert to a {@code ChronoZonedDateTime} 132 * @see Chronology#zonedDateTime(TemporalAccessor) 133 */ 134 static ChronoZonedDateTime!(ChronoLocalDate) from(TemporalAccessor temporal) { 135 if (cast(ChronoZonedDateTime)(temporal) !is null) { 136 return cast(ChronoZonedDateTime!(ChronoLocalDate)) temporal; 137 } 138 assert(temporal, "temporal"); 139 Chronology chrono = QueryHelper.query!Chronology(temporal,TemporalQueries.chronology()); 140 if (chrono is null) { 141 throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " ~ typeid(temporal).stringof); 142 } 143 return chrono.zonedDateTime(temporal); 144 } 145 146 //----------------------------------------------------------------------- 147 ValueRange range(TemporalField field); 148 // override 149 // ValueRange range(TemporalField field) { 150 // if (cast(ChronoField)(field) !is null) { 151 // if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { 152 // return field.range(); 153 // } 154 // return toLocalDateTime().range(field); 155 // } 156 // return field.rangeRefinedBy(this); 157 // } 158 int get(TemporalField field); 159 // override 160 // int get(TemporalField field) { 161 // if (cast(ChronoField)(field) !is null) { 162 // switch (cast(ChronoField) field) { 163 // case INSTANT_SECONDS: 164 // throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead"); 165 // case OFFSET_SECONDS: 166 // return getOffset().getTotalSeconds(); 167 // } 168 // return toLocalDateTime().get(field); 169 // } 170 // return /* Temporal. */super.get(field); 171 // } 172 long getLong(TemporalField field); 173 // override 174 // long getLong(TemporalField field) { 175 // if (cast(ChronoField)(field) !is null) { 176 // switch (cast(ChronoField) field) { 177 // case INSTANT_SECONDS: return toEpochSecond(); 178 // case OFFSET_SECONDS: return getOffset().getTotalSeconds(); 179 // } 180 // return toLocalDateTime().getLong(field); 181 // } 182 // return field.getFrom(this); 183 // } 184 185 /** 186 * Gets the local date part of this date-time. 187 * !(p) 188 * This returns a local date with the same year, month and day 189 * as this date-time. 190 * 191 * @return the date part of this date-time, not null 192 */ 193 D toLocalDate(); 194 // D toLocalDate() { 195 // return toLocalDateTime().toLocalDate(); 196 // } 197 198 /** 199 * Gets the local time part of this date-time. 200 * !(p) 201 * This returns a local time with the same hour, minute, second and 202 * nanosecond as this date-time. 203 * 204 * @return the time part of this date-time, not null 205 */ 206 LocalTime toLocalTime(); 207 // LocalTime toLocalTime() { 208 // return toLocalDateTime().toLocalTime(); 209 // } 210 211 /** 212 * Gets the local date-time part of this date-time. 213 * !(p) 214 * This returns a local date with the same year, month and day 215 * as this date-time. 216 * 217 * @return the local date-time part of this date-time, not null 218 */ 219 ChronoLocalDateTime!(D) toLocalDateTime(); 220 221 /** 222 * Gets the chronology of this date-time. 223 * !(p) 224 * The {@code Chronology} represents the calendar system _in use. 225 * The era and other fields _in {@link ChronoField} are defined by the chronology. 226 * 227 * @return the chronology, not null 228 */ 229 Chronology getChronology(); 230 // Chronology getChronology() { 231 // return toLocalDate().getChronology(); 232 // } 233 234 /** 235 * Gets the zone offset, such as '+01:00'. 236 * !(p) 237 * This is the offset of the local date-time from UTC/Greenwich. 238 * 239 * @return the zone offset, not null 240 */ 241 ZoneOffset getOffset(); 242 243 /** 244 * Gets the zone ID, such as 'Europe/Paris'. 245 * !(p) 246 * This returns the stored time-zone id used to determine the time-zone rules. 247 * 248 * @return the zone ID, not null 249 */ 250 ZoneId getZone(); 251 252 //----------------------------------------------------------------------- 253 /** 254 * Returns a copy of this date-time changing the zone offset to the 255 * earlier of the two valid offsets at a local time-line overlap. 256 * !(p) 257 * This method only has any effect when the local time-line overlaps, such as 258 * at an autumn daylight savings cutover. In this scenario, there are two 259 * valid offsets for the local date-time. Calling this method will return 260 * a zoned date-time with the earlier of the two selected. 261 * !(p) 262 * If this method is called when it is not an overlap, {@code this} 263 * is returned. 264 * !(p) 265 * This instance is immutable and unaffected by this method call. 266 * 267 * @return a {@code ChronoZonedDateTime} based on this date-time with the earlier offset, not null 268 * @throws DateTimeException if no rules can be found for the zone 269 * @throws DateTimeException if no rules are valid for this date-time 270 */ 271 ChronoZonedDateTime!(D) withEarlierOffsetAtOverlap(); 272 273 /** 274 * Returns a copy of this date-time changing the zone offset to the 275 * later of the two valid offsets at a local time-line overlap. 276 * !(p) 277 * This method only has any effect when the local time-line overlaps, such as 278 * at an autumn daylight savings cutover. In this scenario, there are two 279 * valid offsets for the local date-time. Calling this method will return 280 * a zoned date-time with the later of the two selected. 281 * !(p) 282 * If this method is called when it is not an overlap, {@code this} 283 * is returned. 284 * !(p) 285 * This instance is immutable and unaffected by this method call. 286 * 287 * @return a {@code ChronoZonedDateTime} based on this date-time with the later offset, not null 288 * @throws DateTimeException if no rules can be found for the zone 289 * @throws DateTimeException if no rules are valid for this date-time 290 */ 291 ChronoZonedDateTime!(D) withLaterOffsetAtOverlap(); 292 293 /** 294 * Returns a copy of this date-time with a different time-zone, 295 * retaining the local date-time if possible. 296 * !(p) 297 * This method changes the time-zone and retains the local date-time. 298 * The local date-time is only changed if it is invalid for the new zone. 299 * !(p) 300 * To change the zone and adjust the local date-time, 301 * use {@link #withZoneSameInstant(ZoneId)}. 302 * !(p) 303 * This instance is immutable and unaffected by this method call. 304 * 305 * @param zone the time-zone to change to, not null 306 * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null 307 */ 308 ChronoZonedDateTime!(D) withZoneSameLocal(ZoneId zone); 309 310 /** 311 * Returns a copy of this date-time with a different time-zone, 312 * retaining the instant. 313 * !(p) 314 * This method changes the time-zone and retains the instant. 315 * This normally results _in a change to the local date-time. 316 * !(p) 317 * This method is based on retaining the same instant, thus gaps and overlaps 318 * _in the local time-line have no effect on the result. 319 * !(p) 320 * To change the offset while keeping the local time, 321 * use {@link #withZoneSameLocal(ZoneId)}. 322 * 323 * @param zone the time-zone to change to, not null 324 * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null 325 * @throws DateTimeException if the result exceeds the supported date range 326 */ 327 ChronoZonedDateTime!(D) withZoneSameInstant(ZoneId zone); 328 329 /** 330 * Checks if the specified field is supported. 331 * !(p) 332 * This checks if the specified field can be queried on this date-time. 333 * If false, then calling the {@link #range(TemporalField) range}, 334 * {@link #get(TemporalField) get} and {@link #_with(TemporalField, long)} 335 * methods will throw an exception. 336 * !(p) 337 * The set of supported fields is defined by the chronology and normally includes 338 * all {@code ChronoField} fields. 339 * !(p) 340 * If the field is not a {@code ChronoField}, then the result of this method 341 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 342 * passing {@code this} as the argument. 343 * Whether the field is supported is determined by the field. 344 * 345 * @param field the field to check, null returns false 346 * @return true if the field can be queried, false if not 347 */ 348 override 349 bool isSupported(TemporalField field); 350 351 /** 352 * Checks if the specified unit is supported. 353 * !(p) 354 * This checks if the specified unit can be added to or subtracted from this date-time. 355 * If false, then calling the {@link #plus(long, TemporalUnit)} and 356 * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. 357 * !(p) 358 * The set of supported units is defined by the chronology and normally includes 359 * all {@code ChronoUnit} units except {@code FOREVER}. 360 * !(p) 361 * If the unit is not a {@code ChronoUnit}, then the result of this method 362 * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} 363 * passing {@code this} as the argument. 364 * Whether the unit is supported is determined by the unit. 365 * 366 * @param unit the unit to check, null returns false 367 * @return true if the unit can be added/subtracted, false if not 368 */ 369 bool isSupported(TemporalUnit unit); 370 // override 371 // bool isSupported(TemporalUnit unit) { 372 // if (cast(ChronoUnit)(unit) !is null) { 373 // return unit != FOREVER; 374 // } 375 // return unit !is null && unit.isSupportedBy(this); 376 // } 377 378 //----------------------------------------------------------------------- 379 // override for covariant return type 380 /** 381 * {@inheritDoc} 382 * @throws DateTimeException {@inheritDoc} 383 * @throws ArithmeticException {@inheritDoc} 384 */ 385 ChronoZonedDateTime!(D) _with(TemporalAdjuster adjuster); 386 // override 387 // ChronoZonedDateTime!(D) _with(TemporalAdjuster adjuster) { 388 // return ChronoZonedDateTimeImpl.ensureValid(getChronology(), /* Temporal. */super._with(adjuster)); 389 // } 390 391 /** 392 * {@inheritDoc} 393 * @throws DateTimeException {@inheritDoc} 394 * @throws ArithmeticException {@inheritDoc} 395 */ 396 override 397 ChronoZonedDateTime!(D) _with(TemporalField field, long newValue); 398 399 /** 400 * {@inheritDoc} 401 * @throws DateTimeException {@inheritDoc} 402 * @throws ArithmeticException {@inheritDoc} 403 */ 404 ChronoZonedDateTime!(D) plus(TemporalAmount amount); 405 // override 406 // ChronoZonedDateTime!(D) plus(TemporalAmount amount) { 407 // return ChronoZonedDateTimeImpl.ensureValid(getChronology(), /* Temporal. */super.plus(amount)); 408 // } 409 410 /** 411 * {@inheritDoc} 412 * @throws DateTimeException {@inheritDoc} 413 * @throws ArithmeticException {@inheritDoc} 414 */ 415 override 416 ChronoZonedDateTime!(D) plus(long amountToAdd, TemporalUnit unit); 417 418 /** 419 * {@inheritDoc} 420 * @throws DateTimeException {@inheritDoc} 421 * @throws ArithmeticException {@inheritDoc} 422 */ 423 ChronoZonedDateTime!(D) minus(TemporalAmount amount); 424 // override 425 // ChronoZonedDateTime!(D) minus(TemporalAmount amount) { 426 // return ChronoZonedDateTimeImpl.ensureValid(getChronology(), /* Temporal. */super.minus(amount)); 427 // } 428 429 /** 430 * {@inheritDoc} 431 * @throws DateTimeException {@inheritDoc} 432 * @throws ArithmeticException {@inheritDoc} 433 */ 434 override 435 ChronoZonedDateTime!(D) minus(long amountToSubtract, TemporalUnit unit); 436 // override 437 // ChronoZonedDateTime!(D) minus(long amountToSubtract, TemporalUnit unit) { 438 // return ChronoZonedDateTimeImpl.ensureValid(getChronology(), /* Temporal. */super.minus(amountToSubtract, unit)); 439 // } 440 441 //----------------------------------------------------------------------- 442 /** 443 * Queries this date-time using the specified query. 444 * !(p) 445 * This queries this date-time using the specified query strategy object. 446 * The {@code TemporalQuery} object defines the logic to be used to 447 * obtain the result. Read the documentation of the query to understand 448 * what the result of this method will be. 449 * !(p) 450 * The result of this method is obtained by invoking the 451 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 452 * specified query passing {@code this} as the argument. 453 * 454 * @param !(R) the type of the result 455 * @param query the query to invoke, not null 456 * @return the query result, null may be returned (defined by the query) 457 * @throws DateTimeException if unable to query (defined by the query) 458 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 459 */ 460 /*@SuppressWarnings("unchecked")*/ 461 override 462 R query(R)(TemporalQuery!(R) query); 463 // override 464 // R query(R)(TemporalQuery!(R) query) { 465 // if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) { 466 // return cast(R) getZone(); 467 // } else if (query == TemporalQueries.offset()) { 468 // return cast(R) getOffset(); 469 // } else if (query == TemporalQueries.localTime()) { 470 // return cast(R) toLocalTime(); 471 // } else if (query == TemporalQueries.chronology()) { 472 // return cast(R) getChronology(); 473 // } else if (query == TemporalQueries.precision()) { 474 // return cast(R) NANOS; 475 // } 476 // // inline TemporalAccessor.super.query(query) as an optimization 477 // // non-JDK classes are not permitted to make this optimization 478 // return query.queryFrom(this); 479 // } 480 481 /** 482 * Formats this date-time using the specified formatter. 483 * !(p) 484 * This date-time will be passed to the formatter to produce a string. 485 * !(p) 486 * The implementation must behave as follows: 487 * !(pre) 488 * return formatter.format(this); 489 * </pre> 490 * 491 * @param formatter the formatter to use, not null 492 * @return the formatted date-time string, not null 493 * @throws DateTimeException if an error occurs during printing 494 */ 495 // string format(DateTimeFormatter formatter); 496 // string format(DateTimeFormatter formatter) { 497 // assert(formatter, "formatter"); 498 // return formatter.format(this); 499 // } 500 501 //----------------------------------------------------------------------- 502 /** 503 * Converts this date-time to an {@code Instant}. 504 * !(p) 505 * This returns an {@code Instant} representing the same point on the 506 * time-line as this date-time. The calculation combines the 507 * {@linkplain #toLocalDateTime() local date-time} and 508 * {@linkplain #getOffset() offset}. 509 * 510 * @return an {@code Instant} representing the same instant, not null 511 */ 512 Instant toInstant(); 513 // Instant toInstant() { 514 // return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano()); 515 // } 516 517 /** 518 * Converts this date-time to the number of seconds from the epoch 519 * of 1970-01-01T00:00:00Z. 520 * !(p) 521 * This uses the {@linkplain #toLocalDateTime() local date-time} and 522 * {@linkplain #getOffset() offset} to calculate the epoch-second value, 523 * which is the number of elapsed seconds from 1970-01-01T00:00:00Z. 524 * Instants on the time-line after the epoch are positive, earlier are negative. 525 * 526 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z 527 */ 528 long toEpochSecond(); 529 // long toEpochSecond() { 530 // long epochDay = toLocalDate().toEpochDay(); 531 // long secs = epochDay * 86400 + toLocalTime().toSecondOfDay(); 532 // secs -= getOffset().getTotalSeconds(); 533 // return secs; 534 // } 535 536 //----------------------------------------------------------------------- 537 /** 538 * Compares this date-time to another date-time, including the chronology. 539 * !(p) 540 * The comparison is based first on the instant, then on the local date-time, 541 * then on the zone ID, then on the chronology. 542 * It is "consistent with equals", as defined by {@link Comparable}. 543 * !(p) 544 * If all the date-time objects being compared are _in the same chronology, then the 545 * additional chronology stage is not required. 546 * !(p) 547 * This implementation performs the comparison defined above. 548 * 549 * @param other the other date-time to compare to, not null 550 * @return the comparator value, negative if less, positive if greater 551 */ 552 // override 553 int compareTo(ChronoZonedDateTime!(ChronoLocalDate) other); 554 // override 555 // int compareTo(ChronoZonedDateTime!(ChronoLocalDate) other) { 556 // int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); 557 // if (cmp == 0) { 558 // cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); 559 // if (cmp == 0) { 560 // cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); 561 // if (cmp == 0) { 562 // cmp = getZone().getId().compareTo(other.getZone().getId()); 563 // if (cmp == 0) { 564 // cmp = getChronology().compareTo(other.getChronology()); 565 // } 566 // } 567 // } 568 // } 569 // return cmp; 570 // } 571 572 /** 573 * Checks if the instant of this date-time is before that of the specified date-time. 574 * !(p) 575 * This method differs from the comparison _in {@link #compareTo} _in that it 576 * only compares the instant of the date-time. This is equivalent to using 577 * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. 578 * !(p) 579 * This implementation performs the comparison based on the epoch-second 580 * and nano-of-second. 581 * 582 * @param other the other date-time to compare to, not null 583 * @return true if this point is before the specified date-time 584 */ 585 bool isBefore(ChronoZonedDateTime!(ChronoLocalDate) other); 586 // bool isBefore(ChronoZonedDateTime!(Object) other) { 587 // long thisEpochSec = toEpochSecond(); 588 // long otherEpochSec = other.toEpochSecond(); 589 // return thisEpochSec < otherEpochSec || 590 // (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano()); 591 // } 592 593 /** 594 * Checks if the instant of this date-time is after that of the specified date-time. 595 * !(p) 596 * This method differs from the comparison _in {@link #compareTo} _in that it 597 * only compares the instant of the date-time. This is equivalent to using 598 * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. 599 * !(p) 600 * This implementation performs the comparison based on the epoch-second 601 * and nano-of-second. 602 * 603 * @param other the other date-time to compare to, not null 604 * @return true if this is after the specified date-time 605 */ 606 bool isAfter(ChronoZonedDateTime!(ChronoLocalDate) other); 607 // bool isAfter(ChronoZonedDateTime!(Object) other) { 608 // long thisEpochSec = toEpochSecond(); 609 // long otherEpochSec = other.toEpochSecond(); 610 // return thisEpochSec > otherEpochSec || 611 // (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano()); 612 // } 613 614 /** 615 * Checks if the instant of this date-time is equal to that of the specified date-time. 616 * !(p) 617 * This method differs from the comparison _in {@link #compareTo} and {@link #equals} 618 * _in that it only compares the instant of the date-time. This is equivalent to using 619 * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. 620 * !(p) 621 * This implementation performs the comparison based on the epoch-second 622 * and nano-of-second. 623 * 624 * @param other the other date-time to compare to, not null 625 * @return true if the instant equals the instant of the specified date-time 626 */ 627 bool isEqual(ChronoZonedDateTime!(ChronoLocalDate) other); 628 // bool isEqual(ChronoZonedDateTime!(Object) other) { 629 // return toEpochSecond() == other.toEpochSecond() && 630 // toLocalTime().getNano() == other.toLocalTime().getNano(); 631 // } 632 633 //----------------------------------------------------------------------- 634 /** 635 * Checks if this date-time is equal to another date-time. 636 * !(p) 637 * The comparison is based on the offset date-time and the zone. 638 * To compare for the same instant on the time-line, use {@link #compareTo}. 639 * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false. 640 * 641 * @param obj the object to check, null returns false 642 * @return true if this is equal to the other date-time 643 */ 644 // override 645 // bool opEquals(Object obj); 646 647 /** 648 * A hash code for this date-time. 649 * 650 * @return a suitable hash code 651 */ 652 // override 653 // size_t toHash() @trusted nothrow; 654 655 //----------------------------------------------------------------------- 656 /** 657 * Outputs this date-time as a {@code string}. 658 * !(p) 659 * The output will include the full zoned date-time. 660 * 661 * @return a string representation of this date-time, not null 662 */ 663 // override 664 // string toString(); 665 666 }