This is an automated email from the ASF dual-hosted git repository.

yamer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/main by this push:
     new e744532642 [Incubator kie issues#2260]  Fix tests in tck due to 
failure in implicit conversion of Date Time (#6614)
e744532642 is described below

commit e74453264299cda7949864c07df8f1b0973d4b09
Author: AthiraHari77 <[email protected]>
AuthorDate: Mon Mar 9 21:39:10 2026 +0530

    [Incubator kie issues#2260]  Fix tests in tck due to failure in implicit 
conversion of Date Time (#6614)
    
    * [incubator-kie-issues#2260] fix date time issue
    
    * [incubator-kie-issues#2260] fix date time issue
    
    * [incubator-kie-issues#2260] fix date time issue
    
    * [incubator-kie-issues#2260] fix date time issue
    
    * [incubator-kie-issues#2260] fix review comments
    
    * [incubator-kie-issues#2260] update class name from CustomZonedDateTime to 
FormattedZonedDateTime
    
    * [incubator-kie-issues#2260] update test cases
    
    * [incubator-kie-issues#2260] update test cases
    
    * [incubator-kie-issues#2260] update test cases
    
    * [incubator-kie-issues#2260] update test cases
    
    ---------
    
    Co-authored-by: athira <[email protected]>
---
 .../ast/infixexecutors/InfixExecutorUtils.java     |   5 +-
 .../runtime/custom/FormattedZonedDateTime.java     | 212 ++++++++++++++++++
 .../runtime/functions/DateAndTimeFunction.java     |  26 ++-
 .../dmn/feel/runtime/functions/TimeFunction.java   |   2 +-
 .../org/kie/dmn/feel/util/BuiltInTypeUtils.java    |   3 +-
 .../java/org/kie/dmn/feel/util/CodegenUtils.java   |  36 ++--
 .../org/kie/dmn/feel/util/DateTimeEvalHelper.java  |  15 +-
 .../java/org/kie/dmn/feel/util/EvalHelper.java     |  15 +-
 .../main/java/org/kie/dmn/feel/util/TypeUtil.java  |   3 +
 .../runtime/custom/FormattedZonedDateTimeTest.java | 240 +++++++++++++++++++++
 .../runtime/functions/DateAndTimeFunctionTest.java |  39 +++-
 .../feel/runtime/functions/TimeFunctionTest.java   |   8 +-
 .../org/kie/dmn/feel/util/CodegenUtilsTest.java    |  53 +++++
 13 files changed, 604 insertions(+), 53 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
index 8220a8c96c..aafe156ad6 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/lang/ast/infixexecutors/InfixExecutorUtils.java
@@ -28,6 +28,7 @@ import java.util.function.BinaryOperator;
 import org.kie.dmn.api.feel.runtime.events.FEELEvent;
 import org.kie.dmn.feel.lang.EvaluationContext;
 import org.kie.dmn.feel.lang.FEELDialect;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 import org.kie.dmn.feel.util.BooleanEvalHelper;
 import org.kie.dmn.feel.util.Msg;
@@ -204,12 +205,12 @@ public class InfixExecutorUtils {
             final EvaluationContext ctx) {
         // Both datetimes have a timezone or both timezones don't have it. 
Cannot combine timezoned datetime and
         // datetime without a timezone.
-        if ((leftTemporal instanceof ZonedDateTime || leftTemporal instanceof 
OffsetDateTime)
+        if ((leftTemporal instanceof ZonedDateTime || leftTemporal instanceof 
FormattedZonedDateTime || leftTemporal instanceof OffsetDateTime)
                 && (rightTemporal instanceof LocalDateTime)) {
             ctx.notifyEvt(() -> new 
InvalidParametersEvent(FEELEvent.Severity.ERROR, Msg
                     .createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, "first", 
leftTemporal, "second", rightTemporal)));
             return false;
-        } else if ((rightTemporal instanceof ZonedDateTime || rightTemporal 
instanceof OffsetDateTime)
+        } else if ((rightTemporal instanceof ZonedDateTime || rightTemporal 
instanceof FormattedZonedDateTime || rightTemporal instanceof OffsetDateTime)
                 && (leftTemporal instanceof LocalDateTime)) {
             ctx.notifyEvt(() -> new 
InvalidParametersEvent(FEELEvent.Severity.ERROR, Msg
                     .createMessage(Msg.DATE_AND_TIME_TIMEZONE_NEEDED, 
"second", rightTemporal, "first", leftTemporal)));
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTime.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTime.java
new file mode 100644
index 0000000000..e4d1836551
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTime.java
@@ -0,0 +1,212 @@
+/*
+ * 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 org.kie.dmn.feel.runtime.functions.DateAndTimeFunction;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.util.Objects;
+
+/**
+ * This class is meant as sort-of <b>decorator</b> over 
<code>ZonedDateTime</code>, that is a final class.
+ * <p>
+ * <ul>
+ *   <li><b>String representation ({@link #toString()}):</b> Provides a custom 
string format that:
+ *     <ul>
+ *       <li>Always preserves seconds in the output, even when they are zero 
(e.g., "10:10:00" instead of "10:10")</li>
+ *       <li>Uses ISO_OFFSET_DATE_TIME format for ZoneOffset zones (e.g., 
"2021-01-01T10:10:10+11:00")</li>
+ *       <li>Uses REGION_DATETIME_FORMATTER for ZoneRegion zones, which 
properly handles extended years</li>
+ *     </ul>
+ *   </li>
+ *   <li><b>Equality semantics:</b> Can be compared with both 
formattedZonedDateTime and ZonedDateTime instances,
+ *       delegating to the underlying ZonedDateTime for actual comparison 
logic</li>
+ * </ul>
+ * <p>
+ * All temporal operations delegate to the wrapped ZonedDateTime instance, 
maintaining full compatibility
+ * with the Java Time API while providing the custom string representation 
required by FEEL specifications.
+ */
+public final class FormattedZonedDateTime
+        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {
+
+    private final ZonedDateTime zonedDateTime;
+    private final String stringRepresentation;
+
+    private FormattedZonedDateTime(ZonedDateTime zonedDateTime) {
+        this.zonedDateTime = zonedDateTime;
+        ZoneId zone = zonedDateTime.getZone();
+        if (zone instanceof ZoneOffset) {
+            // For ZoneOffset, use ISO format (e.g., 2021-01-01T10:10:10+11:00)
+            this.stringRepresentation = 
zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+        } else {
+            // For ZoneRegion, use REGION_DATETIME_FORMATTER which properly 
handles extended years
+            this.stringRepresentation = 
zonedDateTime.format(DateAndTimeFunction.REGION_DATETIME_FORMATTER);
+        }
+    }
+
+    public static FormattedZonedDateTime of(LocalDate date, LocalTime time, 
ZoneId zone) {
+        return new FormattedZonedDateTime(ZonedDateTime.of(date, time, zone));
+    }
+
+    public static FormattedZonedDateTime from(TemporalAccessor temporal) {
+        return new FormattedZonedDateTime(ZonedDateTime.from(temporal));
+    }
+
+    public static FormattedZonedDateTime of(int coercedYear, int coercedMonth, 
int coercedDay, int coercedHour, int coercedMinute, int coercedSecond, int 
nanoOfSecond, ZoneId zoneId) {
+        return new FormattedZonedDateTime(ZonedDateTime.of(coercedYear, 
coercedMonth, coercedDay, coercedHour, coercedMinute, coercedSecond, 
nanoOfSecond, zoneId));
+    }
+
+    @Override
+    public ChronoLocalDateTime<LocalDate> toLocalDateTime() {
+        return zonedDateTime.toLocalDateTime();
+    }
+
+    @Override
+    public ZoneOffset getOffset() {
+        return zonedDateTime.getOffset();
+    }
+
+    @Override
+    public ZoneId getZone() {
+        return zonedDateTime.getZone();
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> withEarlierOffsetAtOverlap() {
+        return new 
FormattedZonedDateTime(zonedDateTime.withEarlierOffsetAtOverlap());
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> withLaterOffsetAtOverlap() {
+        return new 
FormattedZonedDateTime(zonedDateTime.withLaterOffsetAtOverlap());
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> withZoneSameLocal(ZoneId zone) {
+        return new 
FormattedZonedDateTime(zonedDateTime.withZoneSameLocal(zone));
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> withZoneSameInstant(ZoneId zone) {
+        return new 
FormattedZonedDateTime(zonedDateTime.withZoneSameInstant(zone));
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> with(TemporalField field, long 
newValue) {
+        return new FormattedZonedDateTime(zonedDateTime.with(field, newValue));
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> plus(long amountToAdd, TemporalUnit 
unit) {
+        return new FormattedZonedDateTime(zonedDateTime.plus(amountToAdd, 
unit));
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> plus(TemporalAmount amount) {
+        return new FormattedZonedDateTime(zonedDateTime.plus(amount));
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> minus(TemporalAmount amount) {
+        return new FormattedZonedDateTime(zonedDateTime.minus(amount));
+    }
+
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        return zonedDateTime.until(endExclusive, unit);
+    }
+
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return zonedDateTime.isSupported(field);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        return zonedDateTime.getLong(field);
+    }
+
+    @Override
+    public boolean isSupported(TemporalUnit unit) {
+        return zonedDateTime.isSupported(unit);
+    }
+
+    @Override
+    public ChronoZonedDateTime<LocalDate> minus(long amountToSubtract, 
TemporalUnit unit) {
+        return new 
FormattedZonedDateTime(zonedDateTime.minus(amountToSubtract, unit));
+    }
+
+    public static FormattedZonedDateTime parse(CharSequence text) {
+        return new FormattedZonedDateTime(ZonedDateTime.parse(text));
+    }
+
+    @Override
+    public int compareTo(ChronoZonedDateTime<?> other) {
+        if (other instanceof FormattedZonedDateTime) {
+            return zonedDateTime.compareTo(((FormattedZonedDateTime) 
other).zonedDateTime);
+        }
+        return zonedDateTime.compareTo(other);
+    }
+
+    public FormattedZonedDateTime(ZonedDateTime zonedDateTime, String 
stringRepresentation) {
+        this.zonedDateTime = zonedDateTime;
+        this.stringRepresentation = stringRepresentation;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o instanceof FormattedZonedDateTime that) {
+            return Objects.equals(zonedDateTime, that.zonedDateTime);
+        }
+        if (o instanceof ZonedDateTime other) {
+            return Objects.equals(zonedDateTime, other);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(zonedDateTime);
+    }
+
+    @Override
+    public String toString() {
+        return stringRepresentation;
+    }
+
+    public ZonedDateTime getZonedDateTime() {
+        return zonedDateTime;
+    }
+
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
index f648035e89..66f217e781 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java
@@ -25,7 +25,6 @@ import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.temporal.TemporalAccessor;
@@ -36,6 +35,7 @@ import java.util.TimeZone;
 
 import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
 import org.kie.dmn.feel.runtime.FEELDateTimeFunction;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
 import static org.kie.dmn.feel.util.NumberEvalHelper.coerceIntegerNumber;
@@ -107,12 +107,12 @@ public class DateAndTimeFunction
             TemporalAccessor validatedTime = getValidTime(time);
             if (validatedDate instanceof LocalDate && validatedTime instanceof 
LocalTime) {
                 if (zoneId != null) {
-                    return FEELFnResult.ofResult(ZonedDateTime.of((LocalDate) 
validatedDate, (LocalTime) validatedTime, zoneId));
+                    return 
FEELFnResult.ofResult(FormattedZonedDateTime.of((LocalDate) validatedDate, 
(LocalTime) validatedTime, zoneId));
                 } else {
                     return FEELFnResult.ofResult(LocalDateTime.of((LocalDate) 
validatedDate, (LocalTime) validatedTime));
                 }
             } else if (validatedDate instanceof LocalDate && 
time.query(TemporalQueries.localTime()) != null && 
time.query(TemporalQueries.zone()) != null) {
-                return FEELFnResult.ofResult(ZonedDateTime.of((LocalDate) 
validatedDate, LocalTime.from(validatedTime), zoneId != null ? zoneId : 
ZoneId.from(validatedTime)));
+                return 
FEELFnResult.ofResult(FormattedZonedDateTime.of((LocalDate) validatedDate, 
LocalTime.from(validatedTime), zoneId != null ? zoneId : 
ZoneId.from(validatedTime)));
             }
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "cannot invoke function for the input 
parameters"));
         } catch (IllegalArgumentException e) {
@@ -136,10 +136,22 @@ public class DateAndTimeFunction
 
         try {
             if( val.contains( "T" ) ) {
-                return FEELFnResult.ofResult(FEEL_DATE_TIME.parseBest(val, 
ZonedDateTime::from, OffsetDateTime::from, LocalDateTime::from));
+                return FEELFnResult.ofResult(FEEL_DATE_TIME.parseBest(val, 
FormattedZonedDateTime::from, OffsetDateTime::from, LocalDateTime::from));
             } else {
-                LocalDate value = DateTimeFormatter.ISO_DATE.parse(val, 
LocalDate::from);
-                return FEELFnResult.ofResult( LocalDateTime.of(value, 
LocalTime.of(0, 0)));
+                TemporalAccessor parsed = 
DateTimeFormatter.ISO_DATE.parse(val);
+                LocalDate value = LocalDate.from(parsed);
+                ZoneId zoneId = parsed.query(TemporalQueries.zone());
+                if (zoneId == null) {
+                    ZoneOffset offset = parsed.query(TemporalQueries.offset());
+                    if (offset != null) {
+                        zoneId = ZoneId.ofOffset("UTC", offset);
+                    }
+                }
+                if (zoneId != null) {
+                    return 
FEELFnResult.ofResult(FormattedZonedDateTime.of(value, LocalTime.of(0, 0), 
zoneId));
+                } else {
+                    return FEELFnResult.ofResult(LocalDateTime.of(value, 
LocalTime.of(0, 0)));
+                }
             }
         } catch ( Exception e ) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "from", "date-parsing exception", e));
@@ -199,7 +211,7 @@ public class DateAndTimeFunction
             int coercedHour = coerceIntegerNumber(hour).orElseThrow(() -> new 
NoSuchElementException("hour"));
             int coercedMinute = coerceIntegerNumber(minute).orElseThrow(() -> 
new NoSuchElementException("minute"));
             int coercedSecond = coerceIntegerNumber(second).orElseThrow(() -> 
new NoSuchElementException("second"));
-            return FEELFnResult.ofResult(ZonedDateTime.of(coercedYear, 
coercedMonth, coercedDay,
+            return 
FEELFnResult.ofResult(FormattedZonedDateTime.of(coercedYear, coercedMonth, 
coercedDay,
                     coercedHour, coercedMinute, coercedSecond, 0, 
TimeZone.getTimeZone(timezone).toZoneId()));
         } catch (NoSuchElementException e) { // thrown by 
Optional.orElseThrow()
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, e.getMessage(), "could not be coerced to 
Integer: either null or not a valid Number."));
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
index 776d704f3a..db75e743b9 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/TimeFunction.java
@@ -168,7 +168,7 @@ public class TimeFunction
                 ZoneId zone = date.query(TemporalQueries.zoneId());
                 if (!(zone instanceof ZoneOffset)) {
                     // TZ is a ZoneRegion, so do NOT normalize (although the 
result will be unreversible, but will keep what was supplied originally).
-                    // Unfortunately java.time.Parsed is a package-private 
class, hence will need to re-parse in order to have it instantiated. 
+                    // Unfortunately java.time.Parsed is a package-private 
class, hence will need to re-parse in order to have it instantiated.
                     return 
invoke(getFormattedStringFromTemporalAccessorAndZone(date, zone));
                 } else {
                     return FEELFnResult.ofResult(OffsetTime.from(date));
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BuiltInTypeUtils.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BuiltInTypeUtils.java
index 7be6f7f95a..dba81654ed 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BuiltInTypeUtils.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/BuiltInTypeUtils.java
@@ -40,6 +40,7 @@ import org.kie.dmn.feel.lang.types.BuiltInType;
 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.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.custom.ZoneTime;
 
 public class BuiltInTypeUtils {
@@ -73,7 +74,7 @@ public class BuiltInTypeUtils {
             return BuiltInType.DATE;
         } else if (o instanceof LocalTime || o instanceof OffsetTime || o 
instanceof ZoneTime) {
             return BuiltInType.TIME;
-        } else if (o instanceof ZonedDateTime || o instanceof OffsetDateTime 
|| o instanceof LocalDateTime) {
+        } else if (o instanceof ZonedDateTime || o instanceof 
FormattedZonedDateTime || o instanceof OffsetDateTime || o instanceof 
LocalDateTime) {
             return BuiltInType.DATE_TIME;
         } else if (o instanceof Duration || o instanceof ChronoPeriod) {
             return BuiltInType.DURATION;
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CodegenUtils.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CodegenUtils.java
index 5c291f7ddb..94f8361180 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CodegenUtils.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/CodegenUtils.java
@@ -18,6 +18,8 @@
  */
 package org.kie.dmn.feel.util;
 
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
+
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -151,22 +153,10 @@ public class CodegenUtils {
         } else if (object instanceof String string) {
             return 
getVariableDeclaratorWithInitializerExpression(variableName, STRING_CT,
                                                                   new 
StringLiteralExpr(escapeJava(string)));
+        } else if (object instanceof FormattedZonedDateTime 
formattedZonedDateTime) {
+            return getVariableDeclaratorWithZonedDateTime(variableName, 
formattedZonedDateTime.getZonedDateTime());
         } else if (object instanceof ZonedDateTime zonedDateTime) {
-            Expression zoneIdExpression = new MethodCallExpr(ZONE_ID_N, OF_S,
-                                                             
NodeList.nodeList(new StringLiteralExpr(zonedDateTime.getZone().getId())));
-            NodeList arguments = NodeList.nodeList(new 
IntegerLiteralExpr(zonedDateTime.getYear()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getMonthValue()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getDayOfMonth()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getHour()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getMinute()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getSecond()),
-                                                   new 
IntegerLiteralExpr(zonedDateTime.getNano()),
-                                                   zoneIdExpression);
-            return getVariableDeclaratorWithMethodCall(variableName,
-                                                       ZONED_DATE_TIME_CT,
-                                                       OF_S,
-                                                       ZONED_DATE_TIME_N,
-                                                       arguments);
+            return getVariableDeclaratorWithZonedDateTime(variableName, 
zonedDateTime);
         } else if (object instanceof TemporalAccessor temporalAccessor) {
             // FallBack in case of Parse or other unmanaged classes - keep at 
the end
             String parsedString = 
DateTimeEvalHelper.toParsableString(temporalAccessor);
@@ -181,6 +171,22 @@ public class CodegenUtils {
         }
     }
 
+    static VariableDeclarationExpr 
getVariableDeclaratorWithZonedDateTime(String variableName, ZonedDateTime 
zonedDateTime) {
+        Expression zoneIdExpression = new MethodCallExpr(ZONE_ID_N, OF_S,
+                NodeList.nodeList(new 
StringLiteralExpr(zonedDateTime.getZone().getId())));
+        NodeList arguments = NodeList.nodeList(new 
IntegerLiteralExpr(zonedDateTime.getYear()),
+                new IntegerLiteralExpr(zonedDateTime.getMonthValue()),
+                new IntegerLiteralExpr(zonedDateTime.getDayOfMonth()),
+                new IntegerLiteralExpr(zonedDateTime.getHour()),
+                new IntegerLiteralExpr(zonedDateTime.getMinute()),
+                new IntegerLiteralExpr(zonedDateTime.getSecond()),
+                new IntegerLiteralExpr(zonedDateTime.getNano()),
+                zoneIdExpression);
+        return getVariableDeclaratorWithInitializerExpression(variableName,
+                ZONED_DATE_TIME_CT,
+                new MethodCallExpr(ZONED_DATE_TIME_N, OF_S, arguments));
+    }
+
     public static StringLiteralExpr getStringLiteralExpr(String text) {
         if (text.startsWith("\"") && text.endsWith("\"")) {
             String actualStringContent = text.substring(1, text.length() - 1); 
// remove start/end " from the FEEL text expression.
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java
 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java
index 9e3f895964..ca5cd7f6fe 100644
--- 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java
+++ 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/DateTimeEvalHelper.java
@@ -26,6 +26,7 @@ import java.util.Optional;
 import java.util.function.BiPredicate;
 
 import org.kie.dmn.feel.lang.EvaluationContext;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,12 +51,14 @@ public class DateTimeEvalHelper {
      */
     public static long valuedt(TemporalAccessor datetime, ZoneId 
otherTimezoneOffset) {
         ZoneId alternativeTZ = 
Optional.ofNullable(otherTimezoneOffset).orElse(ZoneOffset.UTC);
-        if (datetime instanceof LocalDateTime) {
-            return ((LocalDateTime) 
datetime).atZone(alternativeTZ).toEpochSecond();
-        } else if (datetime instanceof ZonedDateTime) {
-            return ((ZonedDateTime) datetime).toEpochSecond();
-        } else if (datetime instanceof OffsetDateTime) {
-            return ((OffsetDateTime) datetime).toEpochSecond();
+        if (datetime instanceof LocalDateTime localDateTime) {
+            return localDateTime.atZone(alternativeTZ).toEpochSecond();
+        } else if (datetime instanceof ZonedDateTime zonedDateTime) {
+            return zonedDateTime.toEpochSecond();
+        } else if (datetime instanceof OffsetDateTime offsetDateTime) {
+            return offsetDateTime.toEpochSecond();
+        } else if (datetime instanceof FormattedZonedDateTime 
formattedZonedDateTime) {
+            return formattedZonedDateTime.getZonedDateTime().toEpochSecond();
         } else {
             throw new RuntimeException("valuedt() for " + datetime + " but is 
not a FEEL date and time " + datetime.getClass());
         }
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
index 331b183bc3..9b9bb02e64 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/EvalHelper.java
@@ -42,6 +42,7 @@ import java.util.stream.Stream;
 
 import org.kie.dmn.api.core.FEELPropertyAccessible;
 import org.kie.dmn.feel.lang.FEELProperty;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.Range;
 import org.kie.dmn.feel.runtime.Range.RangeBoundary;
 import org.kie.dmn.feel.runtime.impl.UndefinedValueComparable;
@@ -181,15 +182,17 @@ public class EvalHelper {
                     break;
                 case "value":
                     result = null;
-                    if (current instanceof LocalTime) {
-                        result = BigDecimal.valueOf(((LocalTime) 
current).toSecondOfDay());
-                    } else if (current instanceof OffsetTime) {
-                        result = BigDecimal.valueOf(((OffsetTime) 
current).toLocalTime().toSecondOfDay());
+                    if (current instanceof LocalTime localTime) {
+                        result = BigDecimal.valueOf(localTime.toSecondOfDay());
+                    } else if (current instanceof OffsetTime offsetTime) {
+                        result = 
BigDecimal.valueOf(offsetTime.toLocalTime().toSecondOfDay());
                     } else if (current instanceof LocalDate date) {
                         ZonedDateTime dtAtMidnightUTC = 
date.atStartOfDay(ZoneOffset.UTC);
                         result = 
BigDecimal.valueOf(dtAtMidnightUTC.toEpochSecond());
-                    } else if (current instanceof ZonedDateTime) {
-                        result = BigDecimal.valueOf(((ZonedDateTime) 
current).toEpochSecond());
+                    } else if (current instanceof ZonedDateTime zonedDateTime) 
{
+                        result = 
BigDecimal.valueOf(zonedDateTime.toEpochSecond());
+                    } else if (current instanceof FormattedZonedDateTime 
formattedZonedDateTime) {
+                        result = 
BigDecimal.valueOf(formattedZonedDateTime.getZonedDateTime().toEpochSecond());
                     }
                     break;
                 default:
diff --git 
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java 
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
index 8c9eb1d649..46cf9323bc 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/TypeUtil.java
@@ -37,6 +37,7 @@ import java.util.Set;
 
 import org.kie.dmn.feel.lang.types.impl.ComparablePeriod;
 import org.kie.dmn.feel.runtime.Range;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.custom.ZoneTime;
 import org.kie.dmn.feel.runtime.functions.DateAndTimeFunction;
 import org.kie.dmn.feel.runtime.functions.DateFunction;
@@ -86,6 +87,8 @@ public final class TypeUtil {
         } else if (val instanceof LocalDateTime || val instanceof 
OffsetDateTime) {
             return 
formatDateTimeString(DateAndTimeFunction.FEEL_DATE_TIME.format((TemporalAccessor)
 val),
                                         wrapForCodeUsage);
+        } else if (val instanceof FormattedZonedDateTime) {
+            return formatDateTimeString(val.toString(), wrapForCodeUsage);
         } else if (val instanceof ZonedDateTime) {
             TemporalAccessor ta = (TemporalAccessor) val;
             ZoneId zone = ta.query(TemporalQueries.zone());
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTimeTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTimeTest.java
new file mode 100644
index 0000000000..4ce7de0530
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/custom/FormattedZonedDateTimeTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalQueries;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class FormattedZonedDateTimeTest {
+
+    private static final String REFERENCED_DATE = "2024-08-10";
+    private static final String REFERENCED_TIME = "10:15:00";
+    private static final String REFERENCED_ZONE = "Europe/Paris";
+    private static LocalDate localDate;
+    private static LocalTime localTime;
+    private static ZoneId zoneId;
+    private static ZonedDateTime zonedDateTime;
+    private static FormattedZonedDateTime formattedZonedDateTime;
+
+    @BeforeAll
+    static void setUpClass() {
+        localDate = DateTimeFormatter.ISO_DATE.parse(REFERENCED_DATE, 
LocalDate::from);
+        localTime = DateTimeFormatter.ISO_TIME.parse(REFERENCED_TIME, 
LocalTime::from);
+        zoneId = ZoneId.of(REFERENCED_ZONE);
+        zonedDateTime = ZonedDateTime.of(localDate, localTime, zoneId);
+        formattedZonedDateTime = FormattedZonedDateTime.of(localDate, 
localTime, zoneId);
+    }
+
+    @Test
+    void ofLocalDateLocalTimeZoneId() {
+        FormattedZonedDateTime retrieved = 
FormattedZonedDateTime.of(localDate, localTime, zoneId);
+        assertThat(retrieved).isNotNull();
+        assertThat(retrieved.getZonedDateTime()).isEqualTo(zonedDateTime);
+        assertThat(retrieved.getZone()).isEqualTo(zoneId);
+    }
+
+    @Test
+    void ofIntegers() {
+        FormattedZonedDateTime retrieved = FormattedZonedDateTime.of(2024, 8, 
10, 10, 15, 0, 0, zoneId);
+        assertThat(retrieved).isNotNull();
+        assertThat(retrieved.getZonedDateTime()).isEqualTo(zonedDateTime);
+        assertThat(retrieved.getZone()).isEqualTo(zoneId);
+    }
+
+    @Test
+    void from() {
+        FormattedZonedDateTime retrieved = 
FormattedZonedDateTime.from(zonedDateTime);
+        assertThat(retrieved).isNotNull();
+        assertThat(retrieved.getZonedDateTime()).isEqualTo(zonedDateTime);
+    }
+
+    @Test
+    void getZone() {
+        assertThat(formattedZonedDateTime.getZone()).isEqualTo(zoneId);
+    }
+
+    @Test
+    void getOffset() {
+        
assertThat(formattedZonedDateTime.getOffset()).isEqualTo(zonedDateTime.getOffset());
+    }
+
+    @Test
+    void toLocalDateTime() {
+        
assertThat(formattedZonedDateTime.toLocalDateTime()).isEqualTo(zonedDateTime.toLocalDateTime());
+    }
+
+    @Test
+    void compareTo() {
+        FormattedZonedDateTime toCompare = FormattedZonedDateTime.of(2024, 8, 
10, 9, 30, 0, 0, zoneId);
+        
assertThat(formattedZonedDateTime.compareTo(toCompare)).isEqualTo(zonedDateTime.compareTo(toCompare.getZonedDateTime()));
+    }
+
+    @Test
+    void withTemporalField() {
+        FormattedZonedDateTime expected = 
FormattedZonedDateTime.from(zonedDateTime.with(ChronoField.HOUR_OF_DAY, 3));
+        assertThat(formattedZonedDateTime.with(ChronoField.HOUR_OF_DAY, 
3)).isEqualTo(expected);
+    }
+
+    @Test
+    void plusLong() {
+        FormattedZonedDateTime expected = 
FormattedZonedDateTime.from(zonedDateTime.plus(3, ChronoUnit.HOURS));
+        assertThat(formattedZonedDateTime.plus(3, 
ChronoUnit.HOURS)).isEqualTo(expected);
+    }
+
+    @Test
+    void plusTemporalAmount() {
+        TemporalAmount amount = Duration.of(23, ChronoUnit.MINUTES);
+        FormattedZonedDateTime expected = 
FormattedZonedDateTime.from(zonedDateTime.plus(amount));
+        assertThat(formattedZonedDateTime.plus(amount)).isEqualTo(expected);
+    }
+
+    @Test
+    void minusLong() {
+        FormattedZonedDateTime expected = 
FormattedZonedDateTime.from(zonedDateTime.minus(3, ChronoUnit.HOURS));
+        assertThat(formattedZonedDateTime.minus(3, 
ChronoUnit.HOURS)).isEqualTo(expected);
+    }
+
+    @Test
+    void minusTemporalAmount() {
+        TemporalAmount amount = Duration.of(23, ChronoUnit.MINUTES);
+        FormattedZonedDateTime expected = 
FormattedZonedDateTime.from(zonedDateTime.minus(amount));
+        assertThat(formattedZonedDateTime.minus(amount)).isEqualTo(expected);
+    }
+
+    @Test
+    void until() {
+        FormattedZonedDateTime endExclusive = FormattedZonedDateTime.of(2024, 
8, 10, 9, 30, 0, 0, zoneId);
+        long expected = zonedDateTime.until(endExclusive.getZonedDateTime(), 
ChronoUnit.SECONDS);
+        long retrieved = formattedZonedDateTime.until(endExclusive, 
ChronoUnit.SECONDS);
+        assertThat(retrieved).isEqualTo(expected);
+    }
+
+    @Test
+    void isSupportedTemporalUnit() {
+        assertThat(ChronoUnit.values()).allMatch(unit -> 
formattedZonedDateTime.isSupported(unit) == zonedDateTime.isSupported(unit));
+    }
+
+    @Test
+    void isSupportedTemporalField() {
+        assertThat(ChronoField.values()).allMatch(field -> 
formattedZonedDateTime.isSupported(field) == zonedDateTime.isSupported(field));
+    }
+
+    @Test
+    void getLong() {
+        assertThat(ChronoField.values()).filteredOn(zonedDateTime::isSupported)
+                .allMatch(field -> zonedDateTime.getLong(field) == 
formattedZonedDateTime.getLong(field));
+    }
+
+    @Test
+    void query() {
+        
assertThat(formattedZonedDateTime.query(TemporalQueries.zoneId())).isEqualTo(zoneId);
+        
assertThat(formattedZonedDateTime.query(TemporalQueries.zone())).isEqualTo(zoneId);
+        
assertThat(formattedZonedDateTime.query(TemporalQueries.localDate())).isEqualTo(zonedDateTime.query(TemporalQueries.localDate()));
+        
assertThat(formattedZonedDateTime.query(TemporalQueries.localTime())).isEqualTo(zonedDateTime.query(TemporalQueries.localTime()));
+        
assertThat(formattedZonedDateTime.query(TemporalQueries.offset())).isEqualTo(zonedDateTime.query(TemporalQueries.offset()));
+    }
+
+    @Test
+    void testEquals() {
+        FormattedZonedDateTime toCompare = FormattedZonedDateTime.of(2024, 8, 
10, 9, 30, 0, 0, zoneId);
+        assertThat(toCompare).isNotEqualTo(formattedZonedDateTime);
+        toCompare = FormattedZonedDateTime.of(localDate, localTime, zoneId);
+        assertThat(toCompare).isEqualTo(formattedZonedDateTime);
+    }
+
+    @Test
+    void testToStringWithZeroHoursMinutesAndSeconds() {
+        // Test that toString() preserves hours, minutes and seconds when they 
are 0
+        ZonedDateTime zdt = ZonedDateTime.of(2000, 12, 1, 0, 0, 0, 0, 
ZoneOffset.UTC);
+        FormattedZonedDateTime formatted = FormattedZonedDateTime.from(zdt);
+        String expected = "2000-12-01T00:00:00Z";
+        assertThat(formatted.toString()).isEqualTo(expected);
+    }
+
+    @Test
+    void testToStringWithZeroSeconds() {
+        // Test that toString() preserves seconds even when they are 0 with 
ZoneRegion
+        ZonedDateTime zdt = ZonedDateTime.of(2000, 12, 1, 14, 30, 0, 0, 
ZoneOffset.UTC);
+        FormattedZonedDateTime formatted = FormattedZonedDateTime.from(zdt);
+        String expected = "2000-12-01T14:30:00Z";
+        assertThat(formatted.toString()).isEqualTo(expected);
+    }
+
+    @Test
+    void testToStringWithZeroMinutesAndZeroSeconds() {
+        // Test that toString() preserves both minutes and seconds when they 
are 0
+        ZonedDateTime zdt = ZonedDateTime.of(2000, 12, 1, 10, 0, 0, 0, 
ZoneOffset.UTC);
+        FormattedZonedDateTime formatted = FormattedZonedDateTime.from(zdt);
+        String expected = "2000-12-01T10:00:00Z";
+        assertThat(formatted.toString()).isEqualTo(expected);
+    }
+
+    @Test
+    void testToStringWithNonZeroSeconds() {
+        // Test with non-zero seconds to ensure normal behavior
+        ZonedDateTime zdt = ZonedDateTime.of(2000, 12, 1, 18, 45, 30, 0, 
ZoneOffset.UTC);
+        FormattedZonedDateTime formatted = FormattedZonedDateTime.from(zdt);
+        String expected = "2000-12-01T18:45:30Z";
+        assertThat(formatted.toString()).isEqualTo(expected);
+    }
+
+    @Test
+    void testToStringWithDifferentTimezones() {
+        // Test various timezone formats to ensure seconds are always preserved
+
+        // UTC - uses ZoneRegion format with @
+        ZonedDateTime utc = ZonedDateTime.of(2000, 12, 1, 9, 15, 0, 0, 
ZoneId.of("UTC"));
+        FormattedZonedDateTime formattedUtc = FormattedZonedDateTime.from(utc);
+        
assertThat(formattedUtc.toString()).isEqualTo("2000-12-01T09:15:00@UTC");
+        // ZoneOffset.UTC - uses ISO format with Z
+        ZonedDateTime zdtWithZoneOffsetUTC = ZonedDateTime.of(2000, 12, 1, 0, 
0, 0, 0, ZoneOffset.UTC);
+        FormattedZonedDateTime formatted = 
FormattedZonedDateTime.from(zdtWithZoneOffsetUTC);
+        assertThat(formatted.toString()).isEqualTo("2000-12-01T00:00:00Z");
+
+        // Positive offset - uses ISO format
+        ZonedDateTime plusOffset = ZonedDateTime.of(2000, 12, 1, 9, 15, 0, 0, 
ZoneId.of("+10:00"));
+        FormattedZonedDateTime formattedPlus = 
FormattedZonedDateTime.from(plusOffset);
+        
assertThat(formattedPlus.toString()).isEqualTo("2000-12-01T09:15:00+10:00");
+
+        // Negative offset - uses ISO format
+        ZonedDateTime minusOffset = ZonedDateTime.of(2000, 12, 1, 9, 15, 0, 0, 
ZoneId.of("-05:00"));
+        FormattedZonedDateTime formattedMinus = 
FormattedZonedDateTime.from(minusOffset);
+        
assertThat(formattedMinus.toString()).isEqualTo("2000-12-01T09:15:00-05:00");
+
+        // Named timezone - uses @ format
+        ZonedDateTime named = ZonedDateTime.of(2000, 12, 1, 9, 15, 0, 0, 
ZoneId.of("Asia/Tokyo"));
+        FormattedZonedDateTime formattedNamed = 
FormattedZonedDateTime.from(named);
+        
assertThat(formattedNamed.toString()).isEqualTo("2000-12-01T09:15:00@Asia/Tokyo");
+    }
+
+}
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunctionTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunctionTest.java
index 081394b15b..084038717f 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunctionTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunctionTest.java
@@ -33,8 +33,8 @@ import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.temporal.Temporal;
 import java.time.temporal.TemporalAccessor;
-import java.util.NoSuchElementException;
 import org.junit.jupiter.api.Test;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
 class DateAndTimeFunctionTest {
@@ -47,14 +47,14 @@ class DateAndTimeFunctionTest {
         assertThat(retrievedResult).isNotNull();
         assertThat(retrievedResult.isRight()).isTrue();
         TemporalAccessor retrieved = retrievedResult.getOrElse(null);
-        assertThat(retrieved).isNotNull().isInstanceOf(ZonedDateTime.class);
-        ZonedDateTime retrievedZonedDateTime = (ZonedDateTime) retrieved;
-        assertThat(retrievedZonedDateTime.getYear()).isEqualTo(2017);
-        assertThat(retrievedZonedDateTime.getMonthValue()).isEqualTo(8);
-        assertThat(retrievedZonedDateTime.getDayOfMonth()).isEqualTo(10);
-        assertThat(retrievedZonedDateTime.getHour()).isEqualTo(10);
-        assertThat(retrievedZonedDateTime.getMinute()).isEqualTo(20);
-        assertThat(retrievedZonedDateTime.getSecond()).isZero();
+        
assertThat(retrieved).isNotNull().isInstanceOf(FormattedZonedDateTime.class);
+        FormattedZonedDateTime retrievedZonedDateTime = 
(FormattedZonedDateTime) retrieved;
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getYear()).isEqualTo(2017);
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getMonthValue()).isEqualTo(8);
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getDayOfMonth()).isEqualTo(10);
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getHour()).isEqualTo(10);
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getMinute()).isEqualTo(20);
+        
assertThat((retrievedZonedDateTime).getZonedDateTime().getSecond()).isZero();
         
assertThat(retrievedZonedDateTime.getZone()).isEqualTo(ZoneId.of("Europe/Paris"));
     }
 
@@ -164,8 +164,8 @@ class DateAndTimeFunctionTest {
         FEELFnResult<TemporalAccessor> result = 
dateTimeFunction.invoke(LocalDate.of(2024, 12, 24), LocalTime.of(23, 59, 0), 
"Z");
         assertThat(result.isRight()).isTrue();
         assertThat(result.getOrElse(null)).isNotNull();
-        ZonedDateTime actualDateTime = (ZonedDateTime) result.getOrElse(null);
-        ZonedDateTime expectedDateTime = ZonedDateTime.of(2024, 12, 24, 23, 
59, 0, 0, ZoneOffset.UTC);
+        FormattedZonedDateTime actualDateTime = (FormattedZonedDateTime) 
result.getOrElse(null);
+        FormattedZonedDateTime expectedDateTime = 
FormattedZonedDateTime.of(2024, 12, 24, 23, 59, 0, 0, ZoneOffset.UTC);
         assertThat(expectedDateTime).isEqualTo(actualDateTime);
         FEELFnResult<TemporalAccessor> retrievedResult = 
dateTimeFunction.invoke("2024-12-24T23:59:00Z");
         assertThat(retrievedResult.isRight()).isTrue();
@@ -268,4 +268,21 @@ class DateAndTimeFunctionTest {
         
assertResultError(DateAndTimeFunction.generateDateTimeAndTimezone(null,null, 
ZoneId.of("America/Costa_Rica")), InvalidParametersEvent.class);
     }
 
+    @Test
+    void invokeParamStringDateWithOffset() {
+        // Test case to verify date string with offset returns 
formattedZonedDateTime
+        FEELFnResult<TemporalAccessor> result = 
dateTimeFunction.invoke("2017-09-07+02:00");
+        assertThat(result).isNotNull();
+        assertThat(result.isRight()).isTrue();
+        TemporalAccessor retrieved = result.getOrElse(null);
+        assertThat(retrieved).isNotNull();
+
+        // Verify it returns formattedZonedDateTime with timezone preserved
+        assertThat(retrieved).isInstanceOf(FormattedZonedDateTime.class);
+        FormattedZonedDateTime formattedZonedDateTime = 
(FormattedZonedDateTime) retrieved;
+        
assertThat(formattedZonedDateTime.getZonedDateTime().toLocalDate()).isEqualTo(LocalDate.of(2017,
 9, 7));
+        
assertThat(formattedZonedDateTime.getZonedDateTime().toLocalTime()).isEqualTo(LocalTime.of(0,
 0, 0));
+        
assertThat(formattedZonedDateTime.getZone()).isEqualTo(ZoneOffset.of("+02:00"));
+    }
+
 }
\ No newline at end of file
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/TimeFunctionTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/TimeFunctionTest.java
index c4985c8ccc..85d9831332 100644
--- 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/TimeFunctionTest.java
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/runtime/functions/TimeFunctionTest.java
@@ -27,11 +27,11 @@ import java.time.LocalTime;
 import java.time.OffsetTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalQueries;
 import org.junit.jupiter.api.Test;
 import org.kie.dmn.feel.runtime.custom.ZoneTime;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
 import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -188,7 +188,7 @@ class TimeFunctionTest {
 
     @Test
     void invokeWithZonedDateTime() {
-        ZonedDateTime from = (ZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:00@Europe/Paris")
+        FormattedZonedDateTime from = (FormattedZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:00@Europe/Paris")
                 .getOrElse(null);
         assertThat(from).isNotNull();
         FEELFnResult<TemporalAccessor> retrievedResult = 
timeFunction.invoke(from);
@@ -212,13 +212,13 @@ class TimeFunctionTest {
 
     @Test
     void getFormattedStringFromTemporalAccessorAndZone() {
-        ZonedDateTime date = (ZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:10@Europe/Paris")
+        FormattedZonedDateTime date = (FormattedZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:10@Europe/Paris")
                 .getOrElse(null);
         assertThat(date).isNotNull();
         ZoneId zone = date.query(TemporalQueries.zoneId());
         
assertThat(TimeFunction.getFormattedStringFromTemporalAccessorAndZone(date, 
zone))
                 .isEqualTo("10:20:10@Europe/Paris");
-        date = (ZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:00@Europe/Paris").getOrElse(null);
+        date = (FormattedZonedDateTime) 
DateAndTimeFunction.INSTANCE.invoke("2017-08-10T10:20:00@Europe/Paris").getOrElse(null);
         assertThat(date).isNotNull();
         zone = date.query(TemporalQueries.zoneId());
         
assertThat(TimeFunction.getFormattedStringFromTemporalAccessorAndZone(date, 
zone))
diff --git 
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CodegenUtilsTest.java
 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CodegenUtilsTest.java
new file mode 100644
index 0000000000..830299b2e1
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/CodegenUtilsTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import org.junit.jupiter.api.Test;
+import org.kie.dmn.feel.runtime.custom.FormattedZonedDateTime;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CodegenUtilsTest {
+
+    @Test
+    void testGetVariableDeclaratorWithZonedDateTime() {
+        ZonedDateTime zonedDateTime = ZonedDateTime.of(2024, 3, 15, 10, 30, 
45, 123456789, ZoneId.of("America/New_York"));
+        String variableName = "testZdt";
+        
+        VariableDeclarationExpr result = 
CodegenUtils.getVariableDeclaratorWithZonedDateTime(variableName, 
zonedDateTime);
+        
+        assertThat(result).isNotNull();
+        assertThat(result.toString()).contains(variableName);
+        assertThat(result.toString()).contains("ZonedDateTime.of");
+        assertThat(result.toString()).contains("2024");
+        assertThat(result.toString()).contains("3");
+        assertThat(result.toString()).contains("15");
+        assertThat(result.toString()).contains("10");
+        assertThat(result.toString()).contains("30");
+        assertThat(result.toString()).contains("45");
+        assertThat(result.toString()).contains("123456789");
+        assertThat(result.toString()).contains("America/New_York");
+    }
+
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to