Skip to content

Commit

Permalink
[incubator-kie-issues#69] Creating ZonedOffsetTime decorator and rela…
Browse files Browse the repository at this point in the history
…ted tests
  • Loading branch information
Gabriele-Cardosi committed Jun 18, 2024
1 parent 974628b commit d170ad3
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.kie.dmn.feel.runtime.FEELFunction;
import org.kie.dmn.feel.runtime.Range;
import org.kie.dmn.feel.runtime.UnaryTest;
import org.kie.dmn.feel.runtime.custom.ZonedOffsetTime;

public enum BuiltInType implements SimpleType {

Expand Down Expand Up @@ -124,7 +125,7 @@ public static Type determineTypeFromInstance( Object o ) {
return STRING;
} else if( o instanceof LocalDate ) {
return DATE;
} else if( o instanceof LocalTime || o instanceof OffsetTime ) {
} else if( o instanceof LocalTime || o instanceof OffsetTime || o instanceof ZonedOffsetTime) {
return TIME;
} else if( o instanceof ZonedDateTime || o instanceof OffsetDateTime || o instanceof LocalDateTime ) {
return DATE_TIME;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.kie.dmn.feel.runtime.custom;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.util.Objects;

/**
* This class is meant as sort-of <b>decorator</b> over <code>OffsetTime</code>, that is a final class.
* It is used to provide both offset and zoneid information, replacing the <code>Parsed</code> instance that would be returned otherwise by
* {@link org.kie.dmn.feel.runtime.functions.TimeFunction#invoke(String)}
*/
public final class ZonedOffsetTime
implements Temporal,
TemporalAdjuster,
Comparable<ZonedOffsetTime>,
Serializable {

private final OffsetTime offset;
private final ZoneId zoneId;

public static ZonedOffsetTime of(LocalTime localTime, ZoneId zoneId) {
return new ZonedOffsetTime(localTime, zoneId);
}

public OffsetTime getOffset() {
return offset;
}

public ZoneId getZoneId() {
return zoneId;
}

public String getTimezone() {
return zoneId.getId();
}



private ZonedOffsetTime(LocalTime localTime, ZoneId zoneId) {
ZoneOffset offset = zoneId.getRules().getOffset(LocalDateTime.now());
this.offset = OffsetTime.of(localTime, offset);
this.zoneId = zoneId;
}

@Override
public int compareTo(ZonedOffsetTime o) {
return offset.compareTo(offset);
}

@Override
public boolean isSupported(TemporalUnit unit) {
return offset.isSupported(unit);
}

@Override
public Temporal with(TemporalField field, long newValue) {
return offset.with(field, newValue);
}

@Override
public Temporal plus(long amountToAdd, TemporalUnit unit) {
return offset.plus(amountToAdd, unit);
}

@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
return offset.until(endExclusive, unit);
}

@Override
public boolean isSupported(TemporalField field) {
return offset.isSupported(field);
}

@Override
public long getLong(TemporalField field) {
return offset.getLong(field);
}

@Override
public Temporal adjustInto(Temporal temporal) {
return offset.adjustInto(temporal);
}

@Override
public <R> R query(TemporalQuery<R> query) {
if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone()) {
return (R) zoneId;
} else {
return offset.query(query);
}
}

@Override
public String toString() {
return offset.toString();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ZonedOffsetTime that)) {
return false;
}
return Objects.equals(offset, that.offset) && Objects.equals(zoneId, that.zoneId);
}

@Override
public int hashCode() {
return Objects.hash(offset, zoneId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.math.RoundingMode;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
Expand All @@ -35,6 +36,7 @@

import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.runtime.custom.ZonedOffsetTime;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;

public class TimeFunction
Expand Down Expand Up @@ -77,6 +79,11 @@ public FEELFnResult<TemporalAccessor> invoke(@ParameterName("from") String val)
// if it does not contain any zone information at all, then I know for certain is a local time.
LocalTime asLocalTime = parsed.query(LocalTime::from);
return FEELFnResult.ofResult(asLocalTime);
} else if (parsed.query(TemporalQueries.zone()) != null) {
LocalTime asLocalTime = parsed.query(LocalTime::from);
ZoneId zoneId = parsed.query(TemporalQueries.zone());
ZonedOffsetTime zonedOffsetTime = ZonedOffsetTime.of(asLocalTime, zoneId);
return FEELFnResult.ofResult(zonedOffsetTime);
}

return FEELFnResult.ofResult(parsed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
import org.kie.dmn.feel.runtime.Range;
import org.kie.dmn.feel.runtime.custom.ZonedOffsetTime;
import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction;
import org.kie.dmn.feel.runtime.functions.DateFunction;
import org.kie.dmn.feel.runtime.functions.TimeFunction;
Expand Down Expand Up @@ -72,7 +73,7 @@ public static String formatValue(final Object val, final boolean wrapForCodeUsag
return formatString(val.toString(), wrapForCodeUsage);
} else if (val instanceof LocalDate) {
return formatDate((LocalDate) val, wrapForCodeUsage);
} else if (val instanceof LocalTime || val instanceof OffsetTime) {
} else if (val instanceof LocalTime || val instanceof OffsetTime || val instanceof ZonedOffsetTime) {
return formatTimeString(TimeFunction.FEEL_TIME.format((TemporalAccessor) val), wrapForCodeUsage);
} else if (val instanceof LocalDateTime || val instanceof OffsetDateTime) {
return formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor) val), wrapForCodeUsage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.feel.lang.FEELDialect;
import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
import org.kie.dmn.feel.runtime.custom.ZonedOffsetTime;

public class FEELDateTimeDurationTest extends BaseFEELTest {

Expand Down Expand Up @@ -88,6 +89,9 @@ private static Collection<Object[]> data() {
{ "(@\"13:20:00@Etc/UTC\").timezone", "Etc/UTC" , null},
{ "(@\"13:20:00@Etc/GMT\").timezone", "Etc/GMT" , null},
{ "-duration( \"P2Y2M\" )", ComparablePeriod.parse( "-P2Y2M" ) , null},
{"@\"2023-10-10T10:31:00@Australia/Melbourne\"", DateTimeFormatter.ISO_DATE_TIME.parse("2023-10-10T10" +
":31+11:00[Australia/Melbourne]", ZonedDateTime::from), null},
{"@\"10:15:00@Australia/Melbourne\"", ZonedOffsetTime.of(LocalTime.of(10, 15), ZoneId.of("Australia/Melbourne")), null},

// comparison operators
{ "duration( \"P1Y6M\" ) = duration( \"P1Y6M\" )", Boolean.TRUE , null},
Expand Down Expand Up @@ -184,6 +188,16 @@ private static Collection<Object[]> data() {
{ "time( 22, 57, 00, duration(\"PT5H\")) + duration( \"PT1H1M\" )", OffsetTime.of( 23, 58, 0, 0, ZoneOffset.ofHours( 5 ) ) , null},
{ "duration( \"PT1H1M\" ) + time( 22, 57, 00, duration(\"PT5H\"))", OffsetTime.of( 23, 58, 0, 0, ZoneOffset.ofHours( 5 ) ) , null},

{ "@\"P1D\" + @\"2023-10-10T10:31:00@Australia/Melbourne\"", DateTimeFormatter.ISO_DATE_TIME.parse("2023-10-11T10" +
":31+11:00[Australia/Melbourne]", ZonedDateTime::from), null},
{ "@\"-P1D\" + @\"2023-10-10T10:31:00@Australia/Melbourne\"", DateTimeFormatter.ISO_DATE_TIME.parse("2023-10-09T10" +
":31+11:00[Australia/Melbourne]", ZonedDateTime::from), null},
{ "@\"P1D\" + @\"10:15:00@Australia/Melbourne\"", DateTimeFormatter.ISO_TIME.parse( "10:15+10:00", OffsetTime::from ), null},
{ "@\"-P1D\" + @\"10:15:00@Australia/Melbourne\"", DateTimeFormatter.ISO_TIME.parse( "10:15+10:00", OffsetTime::from ), null},
{ "@\"PT1H\" + @\"10:15:00@Australia/Melbourne\"", DateTimeFormatter.ISO_TIME.parse( "11:15+10:00", OffsetTime::from ), null},
{ "@\"-PT1H\" + @\"10:15:00@Australia/Melbourne\"", DateTimeFormatter.ISO_TIME.parse( "09:15+10:00", OffsetTime::from ), null},


// TODO support for zones - fix when timezones solved out (currently returns ZonedDateTime)
// { "date and time(\"2016-07-29T05:48:23.765-05:00\") + duration( \"P1Y1M\" ) ", OffsetDateTime.of(2017, 8, 29, 5, 48, 23, 765000000, ZoneOffset.ofHours( -5 )), null},
// { "date and time(\"2016-07-29T05:48:23.765-05:00\") + duration( \"P1DT1H1M\" ) ", OffsetDateTime.of(2016, 7, 30, 6, 49, 23, 765000000, ZoneOffset.ofHours( -5 )), null},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,6 @@ void composite5() {
assertThat(timeOnDateTime.query(TemporalQueries.localTime())).isEqualTo(LocalTime.of(10, 20, 0));
assertThat(timeOnDateTime.query(TemporalQueries.zone())).isEqualTo(ZoneId.of("Europe/Paris"));

FunctionTestUtil.assertResult(stringFunction.invoke(timeOnDateTime), "10:20:00@Europe/Paris");
FunctionTestUtil.assertResult(stringFunction.invoke(timeOnDateTime), "10:20:00+02:00");
}
}

0 comments on commit d170ad3

Please sign in to comment.