[threeten-dev] Instant.with(TemporalField, long) does not throw ArithmeticException for numeric overflow error
Stephen Colebourne
scolebourne at joda.org
Mon Feb 18 05:38:00 PST 2013
On 18 February 2013 12:20, Patrick Zhang <patrick.zhang at oracle.com> wrote:
> And Here I have another question for adjustInto() method in
> java.time.temporal.TemporalAdjuster interface.
>
> Actually, I am a bit confused by OffsetDateTime.adjustInto().
> From description in javadoc,
> ===============
> The adjustment is equivalent to using Temporal.with(TemporalField, long)
> three times, passing ChronoField.OFFSET_SECONDS, ChronoField.EPOCH_DAY and
> ChronoField.NANO_OF_DAY as the fields.
> ===============
>
> We can confirm OffsetDateTime.adjustInto(temporal) should work well if
> "temporal" object supports below 3 fileds:
> OFFSET_SECONDS
> EPOCH_DAY
> NANO_OF_DAY
>
> So I am trying to convert one OffsetDateTime to ZonedDateTime since it
> supports such 3 fields really:
> ============
> ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
> ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
> ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
>
> OffsetDateTime t1 = OffsetDateTime.of(LocalDateTime.of(2012,
> 3, 4, 23, 5), OFFSET_PONE);
> ZonedDateTime t2 = ZonedDateTime.of(LocalDateTime.of(2012,
> 3, 4, 1, 1, 1, 100), ZONE_GAZA) ;
> ZonedDateTime t3 = (ZonedDateTime)(t1.adjustInto(t2)) ;
> System.out.println(t1) ;
> System.out.println(t2) ;
> System.out.println(t3) ;
> ===========
>
> The output is below:
> ===========
> 2012-03-04T23:05+01:00
> 2012-03-04T01:01:01.000000100+02:00[Asia/Gaza]
> 2012-03-04T23:05+02:00[Asia/Gaza]
> ===========
>
> The date-time related fields are "adjustInto" really. But it looks
> ZoneOffset do not change. It still keeps "+02:00".
>
> Is it a bug? Personally I think the ZoneOffset should be modified to
> "+01:00" since OFFSET_SECONDS will be adjusted. :)
The trouble is that 2012-03-04T23:05+01:00[Asia/Gaza] would be an
invalid date-time in Gaza. Thus, we can't change the offset without
producing something invalid.
This is what setting the offset does on ZDT:
* <p>
* The {@code OFFSET_SECONDS} field will return a date-time
calculated using the specified offset.
* The local date-time is combined with the new offset to form an
{@code Instant}.
* The instant and original zone are then used to create the result.
* This algorithm means that it is quite likely that the output
has a different offset
* to the specified offset. It will however work correctly when
passing in the offset
* applicable for the instant of the zoned date-time, and will
work correctly if passing
* one of the two valid offsets during a daylight savings overlap
when the same local time
* occurs twice. If the new offset value is outside the valid range then a
* {@code DateTimeException} will be thrown.
which is fine, however the EPOCH_DAYS and NANO_OF_DAY fields will then
overwrite this ensuring that the local date-time is the same as that
from the ODT.
There is one edge case. If the ODT represents an instant in the middle
of a DST overlap for the target zone, then the ZDT that is created
should have the same offset as the ODT, rather than a "random" one.
(ie. there are two valid offsets, so in that case, the
ODT.adjustInto(ZDT) should be setting the correct offset.
Looking at the code, it doesn't perform correctly for the edge case,
and other cases where the ODT is in summer time, but the base ZDT is
in winter time, or vice versa. This code would be more effective at
delivering results, but is slower:
public Temporal adjustInto(Temporal temporal) {
return temporal
.with(EPOCH_DAY, toLocalDate().toEpochDay())
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay())
.with(OFFSET_SECONDS, getOffset().getTotalSeconds())
.with(EPOCH_DAY, toLocalDate().toEpochDay())
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
}
Stephen
More information about the threeten-dev
mailing list