diff --git a/common/internal/BUILD.bazel b/common/internal/BUILD.bazel
index a39bb9365..c69f26b3e 100644
--- a/common/internal/BUILD.bazel
+++ b/common/internal/BUILD.bazel
@@ -137,3 +137,13 @@ cel_android_library(
name = "proto_time_utils_android",
exports = ["//common/src/main/java/dev/cel/common/internal:proto_time_utils_android"],
)
+
+java_library(
+ name = "date_time_helpers",
+ exports = ["//common/src/main/java/dev/cel/common/internal:date_time_helpers"],
+)
+
+cel_android_library(
+ name = "date_time_helpers_android",
+ exports = ["//common/src/main/java/dev/cel/common/internal:date_time_helpers_android"],
+)
diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel
index 255ae5d8d..460a07f13 100644
--- a/common/src/main/java/dev/cel/common/BUILD.bazel
+++ b/common/src/main/java/dev/cel/common/BUILD.bazel
@@ -205,6 +205,7 @@ java_library(
tags = [
],
deps = [
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//common/values",
"//common/values:cel_byte_string",
diff --git a/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java b/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java
index e0afb8c4e..e74d52f7a 100644
--- a/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java
+++ b/common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java
@@ -26,8 +26,10 @@
import com.google.protobuf.Struct;
import com.google.protobuf.Timestamp;
import com.google.protobuf.Value;
+import dev.cel.common.internal.DateTimeHelpers;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.values.CelByteString;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
@@ -118,6 +120,14 @@ public static Value adaptValueToJsonValue(Object value) {
String duration = ProtoTimeUtils.toString((Duration) value);
return json.setStringValue(duration).build();
}
+ if (value instanceof Instant) {
+ // Instant's toString follows RFC 3339
+ return json.setStringValue(value.toString()).build();
+ }
+ if (value instanceof java.time.Duration) {
+ String duration = DateTimeHelpers.toString((java.time.Duration) value);
+ return json.setStringValue(duration).build();
+ }
if (value instanceof FieldMask) {
String fieldMaskStr = toJsonString((FieldMask) value);
return json.setStringValue(fieldMaskStr).build();
diff --git a/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel
index c508649a3..85b5df9a4 100644
--- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel
+++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel
@@ -195,9 +195,11 @@ java_library(
deps = [
":well_known_proto",
"//common:error_codes",
+ "//common:options",
"//common:proto_json_adapter",
"//common:runtime_exception",
"//common/annotations",
+ "//common/internal:proto_time_utils",
"//common/values",
"//common/values:cel_byte_string",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -429,3 +431,31 @@ cel_android_library(
"@maven_android//:com_google_protobuf_protobuf_javalite",
],
)
+
+java_library(
+ name = "date_time_helpers",
+ srcs = ["DateTimeHelpers.java"],
+ tags = [
+ ],
+ deps = [
+ "//common:error_codes",
+ "//common:runtime_exception",
+ "//common/annotations",
+ "@maven//:com_google_guava_guava",
+ "@maven//:com_google_protobuf_protobuf_java",
+ ],
+)
+
+cel_android_library(
+ name = "date_time_helpers_android",
+ srcs = ["DateTimeHelpers.java"],
+ tags = [
+ ],
+ deps = [
+ "//common:error_codes",
+ "//common:runtime_exception",
+ "//common/annotations",
+ "@maven_android//:com_google_guava_guava",
+ "@maven_android//:com_google_protobuf_protobuf_javalite",
+ ],
+)
diff --git a/common/src/main/java/dev/cel/common/internal/DateTimeHelpers.java b/common/src/main/java/dev/cel/common/internal/DateTimeHelpers.java
new file mode 100644
index 000000000..9abe39b4b
--- /dev/null
+++ b/common/src/main/java/dev/cel/common/internal/DateTimeHelpers.java
@@ -0,0 +1,261 @@
+// Copyright 2025 Google LLC
+//
+// Licensed 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
+//
+// https://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 dev.cel.common.internal;
+
+import com.google.common.base.Strings;
+import com.google.protobuf.Timestamp;
+import dev.cel.common.CelErrorCode;
+import dev.cel.common.CelRuntimeException;
+import dev.cel.common.annotations.Internal;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.util.Locale;
+
+/** Collection of utility methods for CEL datetime handlings. */
+@Internal
+@SuppressWarnings("JavaInstantGetSecondsGetNano") // Intended within CEL.
+public final class DateTimeHelpers {
+ public static final String UTC = "UTC";
+
+ // Timestamp for "0001-01-01T00:00:00Z"
+ private static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
+ // Timestamp for "9999-12-31T23:59:59Z"
+ private static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
+
+ private static final long DURATION_SECONDS_MIN = -315576000000L;
+ private static final long DURATION_SECONDS_MAX = 315576000000L;
+ private static final int NANOS_PER_SECOND = 1000000000;
+
+ /**
+ * Constructs a new {@link LocalDateTime} instance
+ *
+ * @param ts Timestamp protobuf object
+ * @param tz Timezone based on the CEL specification. This is either the canonical name from tz
+ * database or a standard offset represented in (+/-)HH:MM. Few valid examples are:
+ *
+ * - UTC
+ *
- America/Los_Angeles
+ *
- -09:30 or -9:30 (Leading zeroes can be omitted though not allowed by spec)
+ *
+ *
+ * @return If an Invalid timezone is supplied.
+ */
+ public static LocalDateTime newLocalDateTime(Timestamp ts, String tz) {
+ return Instant.ofEpochSecond(ts.getSeconds(), ts.getNanos())
+ .atZone(timeZone(tz))
+ .toLocalDateTime();
+ }
+
+ /**
+ * Constructs a new {@link LocalDateTime} instance from a Java Instant.
+ *
+ * @param instant Instant object
+ * @param tz Timezone based on the CEL specification. This is either the canonical name from tz
+ * database or a standard offset represented in (+/-)HH:MM. Few valid examples are:
+ *
+ * - UTC
+ *
- America/Los_Angeles
+ *
- -09:30 or -9:30 (Leading zeroes can be omitted though not allowed by spec)
+ *
+ *
+ * @return A new {@link LocalDateTime} instance.
+ */
+ public static LocalDateTime newLocalDateTime(Instant instant, String tz) {
+ return instant.atZone(timeZone(tz)).toLocalDateTime();
+ }
+
+ /**
+ * Parse from RFC 3339 date string to {@link java.time.Instant}.
+ *
+ * Example of accepted format: "1972-01-01T10:00:20.021-05:00"
+ */
+ public static Instant parse(String text) {
+ OffsetDateTime offsetDateTime = OffsetDateTime.parse(text);
+ Instant instant = offsetDateTime.toInstant();
+ checkValid(instant);
+
+ return instant;
+ }
+
+ /** Adds a duration to an instant. */
+ public static Instant add(Instant ts, Duration dur) {
+ Instant newInstant = ts.plus(dur);
+ checkValid(newInstant);
+
+ return newInstant;
+ }
+
+ /** Adds two durations */
+ public static Duration add(Duration d1, Duration d2) {
+ Duration newDuration = d1.plus(d2);
+ checkValid(newDuration);
+
+ return newDuration;
+ }
+
+ /** Subtracts a duration to an instant. */
+ public static Instant subtract(Instant ts, Duration dur) {
+ Instant newInstant = ts.minus(dur);
+ checkValid(newInstant);
+
+ return newInstant;
+ }
+
+ /** Subtract a duration from another. */
+ public static Duration subtract(Duration d1, Duration d2) {
+ Duration newDuration = d1.minus(d2);
+ checkValid(newDuration);
+
+ return newDuration;
+ }
+
+ /**
+ * Formats a {@link Duration} into a minimal seconds-based representation.
+ *
+ *
Note: follows {@code ProtoTimeUtils#toString(Duration)} implementation
+ */
+ public static String toString(Duration duration) {
+ if (duration.isZero()) {
+ return "0s";
+ }
+
+ long totalNanos = duration.toNanos();
+ StringBuilder sb = new StringBuilder();
+
+ if (totalNanos < 0) {
+ sb.append('-');
+ totalNanos = -totalNanos;
+ }
+
+ long seconds = totalNanos / 1_000_000_000;
+ int nanos = (int) (totalNanos % 1_000_000_000);
+
+ sb.append(seconds);
+
+ // Follows ProtoTimeUtils.toString(Duration) implementation
+ if (nanos > 0) {
+ sb.append('.');
+ if (nanos % 1_000_000 == 0) {
+ // Millisecond precision (3 digits)
+ int millis = nanos / 1_000_000;
+ sb.append(String.format(Locale.US, "%03d", millis));
+ } else if (nanos % 1_000 == 0) {
+ // Microsecond precision (6 digits)
+ int micros = nanos / 1_000;
+ sb.append(String.format(Locale.US, "%06d", micros));
+ } else {
+ // Nanosecond precision (9 digits)
+ sb.append(String.format(Locale.US, "%09d", nanos));
+ }
+ }
+
+ sb.append('s');
+ return sb.toString();
+ }
+
+ /**
+ * Get the DateTimeZone Instance.
+ *
+ * @param tz the ID of the datetime zone
+ * @return the ZoneId object
+ */
+ private static ZoneId timeZone(String tz) {
+ try {
+ return ZoneId.of(tz);
+ } catch (DateTimeException e) {
+ // If timezone is not a string name (for example, 'US/Central'), it should be a numerical
+ // offset from UTC in the format [+/-]HH:MM.
+ try {
+ int ind = tz.indexOf(":");
+ if (ind == -1) {
+ throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ }
+
+ int hourOffset = Integer.parseInt(tz.substring(0, ind));
+ int minOffset = Integer.parseInt(tz.substring(ind + 1));
+ // Ensures that the offset are properly formatted in [+/-]HH:MM to conform with
+ // ZoneOffset's format requirements.
+ // Example: "-9:30" -> "-09:30" and "9:30" -> "+09:30"
+ String formattedOffset =
+ ((hourOffset < 0) ? "-" : "+")
+ + String.format(Locale.US, "%02d:%02d", Math.abs(hourOffset), minOffset);
+
+ return ZoneId.of(formattedOffset);
+
+ } catch (DateTimeException e2) {
+ throw new CelRuntimeException(e2, CelErrorCode.BAD_FORMAT);
+ }
+ }
+ }
+
+ /** Throws an {@link IllegalArgumentException} if the given {@link Timestamp} is not valid. */
+ private static void checkValid(Instant instant) {
+ long seconds = instant.getEpochSecond();
+
+ if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
+ throw new IllegalArgumentException(
+ Strings.lenientFormat(
+ "Timestamp is not valid. "
+ + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
+ + "Nanos (%s) must be in range [0, +999,999,999].",
+ seconds, instant.getNano()));
+ }
+ }
+
+ /** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
+ private static void checkValid(Duration duration) {
+ long seconds = duration.getSeconds();
+ int nanos = duration.getNano();
+ if (!isDurationValid(seconds, nanos)) {
+ throw new IllegalArgumentException(
+ Strings.lenientFormat(
+ "Duration is not valid. "
+ + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
+ + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+ + "Nanos must have the same sign as seconds",
+ seconds, nanos));
+ }
+ }
+
+ /**
+ * Returns true if the given number of seconds and nanos is a valid {@link Duration}. The {@code
+ * seconds} value must be in the range [-315,576,000,000, +315,576,000,000]. The {@code nanos}
+ * value must be in the range [-999,999,999, +999,999,999].
+ *
+ *
Note: Durations less than one second are represented with a 0 {@code seconds} field
+ * and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
+ * value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+ */
+ private static boolean isDurationValid(long seconds, int nanos) {
+ if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
+ return false;
+ }
+ if (nanos < -999999999L || nanos >= NANOS_PER_SECOND) {
+ return false;
+ }
+ if (seconds < 0 || nanos < 0) {
+ if (seconds > 0 || nanos > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private DateTimeHelpers() {}
+}
diff --git a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
index 3461106ae..cd4be2f5e 100644
--- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
+++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
@@ -125,7 +125,7 @@ public final class ProtoAdapter {
public ProtoAdapter(DynamicProto dynamicProto, CelOptions celOptions) {
this.dynamicProto = checkNotNull(dynamicProto);
- this.protoLiteAdapter = new ProtoLiteAdapter(celOptions.enableUnsignedLongs());
+ this.protoLiteAdapter = new ProtoLiteAdapter(celOptions);
this.celOptions = celOptions;
}
diff --git a/common/src/main/java/dev/cel/common/internal/ProtoLiteAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoLiteAdapter.java
index eb8c42862..e05d92f68 100644
--- a/common/src/main/java/dev/cel/common/internal/ProtoLiteAdapter.java
+++ b/common/src/main/java/dev/cel/common/internal/ProtoLiteAdapter.java
@@ -43,10 +43,12 @@
import com.google.protobuf.UInt64Value;
import com.google.protobuf.Value;
import dev.cel.common.CelErrorCode;
+import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoJsonAdapter;
import dev.cel.common.CelRuntimeException;
import dev.cel.common.annotations.Internal;
import dev.cel.common.values.CelByteString;
+import java.time.Instant;
import java.util.Map;
import java.util.Map.Entry;
@@ -63,7 +65,7 @@
@Immutable
public final class ProtoLiteAdapter {
- private final boolean enableUnsignedLongs;
+ private final CelOptions celOptions;
@SuppressWarnings("unchecked")
public MessageLite adaptValueToWellKnownProto(Object value, WellKnownProto wellKnownProto) {
@@ -94,9 +96,9 @@ public MessageLite adaptValueToWellKnownProto(Object value, WellKnownProto wellK
case UINT64_VALUE:
return adaptValueToUint64(value);
case DURATION:
- return (Duration) value;
+ return adaptValueToProtoDuration(value);
case TIMESTAMP:
- return (Timestamp) value;
+ return adaptValueToProtoTimestamp(value);
case EMPTY:
case FIELD_MASK:
// These two WKTs are typically used in context of JSON conversions, in which they are
@@ -114,7 +116,6 @@ public Any adaptValueToAny(Object value, String typeName) {
return packAnyMessage((MessageLite) value, typeName);
}
- // if (value instanceof NullValue) {
if (value instanceof dev.cel.common.values.NullValue) {
return packAnyMessage(
Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(), WellKnownProto.JSON_VALUE);
@@ -140,6 +141,10 @@ public Any adaptValueToAny(Object value, String typeName) {
wellKnownProto = WellKnownProto.JSON_LIST_VALUE;
} else if (value instanceof Map) {
wellKnownProto = WellKnownProto.JSON_STRUCT_VALUE;
+ } else if (value instanceof Instant) {
+ wellKnownProto = WellKnownProto.TIMESTAMP;
+ } else if (value instanceof java.time.Duration) {
+ wellKnownProto = WellKnownProto.DURATION;
} else {
throw new IllegalArgumentException("Unsupported value conversion to any: " + value);
}
@@ -175,16 +180,26 @@ public Object adaptWellKnownProtoToValue(
case STRING_VALUE:
return ((StringValue) proto).getValue();
case UINT32_VALUE:
- if (enableUnsignedLongs) {
+ if (celOptions.enableUnsignedLongs()) {
return UnsignedLong.fromLongBits(
Integer.toUnsignedLong(((UInt32Value) proto).getValue()));
}
return (long) ((UInt32Value) proto).getValue();
case UINT64_VALUE:
- if (enableUnsignedLongs) {
+ if (celOptions.enableUnsignedLongs()) {
return UnsignedLong.fromLongBits(((UInt64Value) proto).getValue());
}
return ((UInt64Value) proto).getValue();
+ case TIMESTAMP:
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return ProtoTimeUtils.toJavaInstant((Timestamp) proto);
+ }
+ return proto;
+ case DURATION:
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return ProtoTimeUtils.toJavaDuration((Duration) proto);
+ }
+ return proto;
default:
return proto;
}
@@ -324,7 +339,23 @@ private static Any packAnyMessage(MessageLite msg, String typeUrl) {
.build();
}
- public ProtoLiteAdapter(boolean enableUnsignedLongs) {
- this.enableUnsignedLongs = enableUnsignedLongs;
+ private Timestamp adaptValueToProtoTimestamp(Object value) {
+ if (!celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return (Timestamp) value;
+ }
+
+ return ProtoTimeUtils.toProtoTimestamp((Instant) value);
+ }
+
+ private Duration adaptValueToProtoDuration(Object value) {
+ if (!celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return (Duration) value;
+ }
+
+ return ProtoTimeUtils.toProtoDuration((java.time.Duration) value);
+ }
+
+ public ProtoLiteAdapter(CelOptions celOptions) {
+ this.celOptions = celOptions;
}
}
diff --git a/common/src/main/java/dev/cel/common/values/BaseProtoCelValueConverter.java b/common/src/main/java/dev/cel/common/values/BaseProtoCelValueConverter.java
index 38741f555..450b273c2 100644
--- a/common/src/main/java/dev/cel/common/values/BaseProtoCelValueConverter.java
+++ b/common/src/main/java/dev/cel/common/values/BaseProtoCelValueConverter.java
@@ -53,23 +53,6 @@ public abstract class BaseProtoCelValueConverter extends CelValueConverter {
public abstract CelValue fromProtoMessageToCelValue(MessageLite msg);
- /**
- * Adapts a {@link CelValue} to a native Java object. The CelValue is adapted into protobuf object
- * when an equivalent exists.
- */
- @Override
- public Object fromCelValueToJavaObject(CelValue celValue) {
- Preconditions.checkNotNull(celValue);
-
- if (celValue instanceof TimestampValue) {
- return ProtoTimeUtils.toProtoTimestamp(((TimestampValue) celValue).value());
- } else if (celValue instanceof DurationValue) {
- return ProtoTimeUtils.toProtoDuration(((DurationValue) celValue).value());
- }
-
- return super.fromCelValueToJavaObject(celValue);
- }
-
/** {@inheritDoc} Protobuf semantics take precedence for conversion. */
@Override
public CelValue fromJavaObjectToCelValue(Object value) {
diff --git a/common/src/test/java/dev/cel/common/values/ProtoCelValueConverterTest.java b/common/src/test/java/dev/cel/common/values/ProtoCelValueConverterTest.java
index b7e72c6b8..234411ce7 100644
--- a/common/src/test/java/dev/cel/common/values/ProtoCelValueConverterTest.java
+++ b/common/src/test/java/dev/cel/common/values/ProtoCelValueConverterTest.java
@@ -16,12 +16,10 @@
import static com.google.common.truth.Truth.assertThat;
-import com.google.protobuf.Duration;
-import com.google.protobuf.Timestamp;
import dev.cel.common.internal.DefaultDescriptorPool;
import dev.cel.common.internal.DefaultMessageFactory;
import dev.cel.common.internal.DynamicProto;
-import dev.cel.common.internal.ProtoTimeUtils;
+import java.time.Duration;
import java.time.Instant;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,13 +33,13 @@ public class ProtoCelValueConverterTest {
DefaultDescriptorPool.INSTANCE, DynamicProto.create(DefaultMessageFactory.INSTANCE));
@Test
- public void fromCelValueToJavaObject_returnsTimestampValue() {
- Timestamp timestamp =
- (Timestamp)
+ public void fromCelValueToJavaObject_returnsInstantValue() {
+ Instant timestamp =
+ (Instant)
PROTO_CEL_VALUE_CONVERTER.fromCelValueToJavaObject(
TimestampValue.create(Instant.ofEpochSecond(50)));
- assertThat(timestamp).isEqualTo(ProtoTimeUtils.fromSecondsToTimestamp(50));
+ assertThat(timestamp).isEqualTo(Instant.ofEpochSecond(50));
}
@Test
@@ -49,9 +47,9 @@ public void fromCelValueToJavaObject_returnsDurationValue() {
Duration duration =
(Duration)
PROTO_CEL_VALUE_CONVERTER.fromCelValueToJavaObject(
- DurationValue.create(java.time.Duration.ofSeconds(10)));
+ DurationValue.create(Duration.ofSeconds(10)));
- assertThat(duration).isEqualTo(ProtoTimeUtils.fromSecondsToDuration(10));
+ assertThat(duration).isEqualTo(Duration.ofSeconds(10));
}
@Test
diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
index a384b09e2..6ed4d1491 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
@@ -50,6 +50,7 @@
import dev.cel.runtime.CelInternalRuntimeLibrary;
import dev.cel.runtime.CelRuntimeBuilder;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -394,6 +395,10 @@ private static boolean isZeroValue(Object val) {
} else if (val instanceof NullValue) {
// A null value always represents an absent value
return true;
+ } else if (val instanceof Instant) {
+ return val.equals(Instant.EPOCH);
+ } else if (val instanceof java.time.Duration) {
+ return val.equals(java.time.Duration.ZERO);
}
// Unknown. Assume that it is non-zero.
diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
index a806037da..a51fbedbf 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
@@ -34,7 +34,6 @@
import dev.cel.common.CelOverloadDecl;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelVarDecl;
-import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.types.CelType;
import dev.cel.common.types.ListType;
import dev.cel.common.types.MapType;
@@ -52,6 +51,8 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.InterpreterUtil;
+import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -70,16 +71,12 @@ private enum ConstantTestCases {
UINT("5u", "0u", SimpleType.UINT, UnsignedLong.valueOf(5)),
BOOL("true", "false", SimpleType.BOOL, true),
BYTES("b'abc'", "b''", SimpleType.BYTES, CelByteString.copyFromUtf8("abc")),
- DURATION(
- "duration('180s')",
- "duration('0s')",
- SimpleType.DURATION,
- ProtoTimeUtils.fromSecondsToDuration(180)),
+ DURATION("duration('180s')", "duration('0s')", SimpleType.DURATION, Duration.ofMinutes(3)),
TIMESTAMP(
"timestamp(1685552643)",
"timestamp(0)",
SimpleType.TIMESTAMP,
- ProtoTimeUtils.fromSecondsToTimestamp(1685552643));
+ Instant.ofEpochSecond(1685552643));
private final String sourceWithNonZeroValue;
private final String sourceWithZeroValue;
diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java b/runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java
index 37247f3d3..0e02af273 100644
--- a/runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java
+++ b/runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java
@@ -55,16 +55,23 @@ public static RuntimeHelpers create() {
// Functions
// =========
- /** Convert a string to a Duration. */
+ /** Convert a string to a Protobuf Duration. */
@SuppressWarnings("AndroidJdkLibsChecker") // DateTimeParseException added in 26
public static Duration createDurationFromString(String d) {
+ java.time.Duration dv = createJavaDurationFromString(d);
+ return Duration.newBuilder().setSeconds(dv.getSeconds()).setNanos(dv.getNano()).build();
+ }
+
+ /** Convert a string to a native Java Duration. */
+ @SuppressWarnings("AndroidJdkLibsChecker") // DateTimeParseException added in 26
+ public static java.time.Duration createJavaDurationFromString(String d) {
try {
java.time.Duration dv = AmountFormats.parseUnitBasedDuration(d);
// Ensure that the duration value can be adequately represented within a protobuf.Duration.
checkArgument(
dv.compareTo(DURATION_MAX) <= 0 && dv.compareTo(DURATION_MIN) >= 0,
"invalid duration range");
- return Duration.newBuilder().setSeconds(dv.getSeconds()).setNanos(dv.getNano()).build();
+ return dv;
} catch (DateTimeParseException e) {
throw new IllegalArgumentException("invalid duration format", e);
}
diff --git a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java b/runtime/src/main/java/dev/cel/runtime/TypeResolver.java
index b9cc42cc1..905120988 100644
--- a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java
+++ b/runtime/src/main/java/dev/cel/runtime/TypeResolver.java
@@ -35,6 +35,7 @@
import dev.cel.common.types.StructTypeReference;
import dev.cel.common.types.TypeType;
import dev.cel.common.values.CelByteString;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -64,8 +65,17 @@ static TypeResolver create() {
.put(UnsignedLong.class, TypeType.create(SimpleType.UINT))
.put(String.class, TypeType.create(SimpleType.STRING))
.put(NullValue.class, TypeType.create(SimpleType.NULL_TYPE))
- .put(Duration.class, TypeType.create(SimpleType.DURATION))
- .put(Timestamp.class, TypeType.create(SimpleType.TIMESTAMP))
+ .put(java.time.Duration.class, TypeType.create(SimpleType.DURATION))
+ .put(Instant.class, TypeType.create(SimpleType.TIMESTAMP))
+ .put(
+ Duration.class,
+ TypeType.create(
+ SimpleType.DURATION)) // TODO: Remove once clients have been migrated
+ .put(
+ Timestamp.class,
+ TypeType.create(
+ SimpleType
+ .TIMESTAMP)) // TODO: Remove once clients have been migrated
.put(ArrayList.class, TypeType.create(ListType.create(SimpleType.DYN)))
.put(HashMap.class, TypeType.create(MapType.create(SimpleType.DYN, SimpleType.DYN)))
.put(Optional.class, TypeType.create(OptionalType.create(SimpleType.DYN)))
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java
index 9d75b15ce..42386a942 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java
@@ -23,11 +23,13 @@
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.common.CelRuntimeException;
+import dev.cel.common.internal.DateTimeHelpers;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.values.CelByteString;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
import java.util.List;
@@ -104,24 +106,51 @@ public enum AddOverload implements CelStandardOverload {
(celOptions, runtimeEquality) ->
CelFunctionBinding.from("add_double", Double.class, Double.class, Double::sum)),
ADD_DURATION_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "add_duration_duration", Duration.class, Duration.class, ProtoTimeUtils::add)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "add_duration_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ DateTimeHelpers::add);
+ } else {
+ return CelFunctionBinding.from(
+ "add_duration_duration", Duration.class, Duration.class, ProtoTimeUtils::add);
+ }
+ }),
ADD_TIMESTAMP_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "add_timestamp_duration", Timestamp.class, Duration.class, ProtoTimeUtils::add)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "add_timestamp_duration",
+ Instant.class,
+ java.time.Duration.class,
+ DateTimeHelpers::add);
+ } else {
+ return CelFunctionBinding.from(
+ "add_timestamp_duration", Timestamp.class, Duration.class, ProtoTimeUtils::add);
+ }
+ }),
ADD_STRING(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
"add_string", String.class, String.class, (String x, String y) -> x + y)),
ADD_DURATION_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "add_duration_timestamp",
+ java.time.Duration.class,
+ Instant.class,
+ (java.time.Duration d, Instant i) -> DateTimeHelpers.add(i, d));
+ } else {
+ return CelFunctionBinding.from(
"add_duration_timestamp",
Duration.class,
Timestamp.class,
- (Duration x, Timestamp y) -> ProtoTimeUtils.add(y, x))),
+ (Duration d, Timestamp t) -> ProtoTimeUtils.add(t, d));
+ }
+ }),
@SuppressWarnings({"unchecked"})
ADD_LIST(
(celOptions, runtimeEquality) ->
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel
index bac80475d..08177a474 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel
+++ b/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel
@@ -50,6 +50,7 @@ java_library(
":standard_overload",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//common/values:cel_byte_string",
"//runtime:function_binding",
@@ -71,6 +72,7 @@ cel_android_library(
":standard_overload_android",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//common/values:cel_byte_string",
"//runtime:function_binding_android",
@@ -92,6 +94,7 @@ java_library(
":standard_overload",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -112,6 +115,7 @@ cel_android_library(
":standard_overload_android",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -389,9 +393,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -406,10 +410,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -423,9 +427,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -440,10 +444,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -457,9 +461,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -474,10 +478,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -491,9 +495,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -508,10 +512,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -525,9 +529,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -542,10 +546,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -559,9 +563,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -577,10 +581,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -595,9 +599,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -613,10 +617,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -631,9 +635,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -649,10 +653,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -667,9 +671,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//runtime:function_binding",
"//runtime:runtime_equality",
"//runtime/standard:standard_function",
@@ -684,10 +688,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
"@maven_android//:com_google_guava_guava",
@@ -701,9 +705,9 @@ java_library(
tags = [
],
deps = [
- ":date_time_helpers",
":standard_overload",
"//common:options",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -719,10 +723,10 @@ cel_android_library(
tags = [
],
deps = [
- ":date_time_helpers_android",
":standard_function_android",
":standard_overload_android",
"//common:options",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -1307,6 +1311,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//common/values:cel_byte_string",
"//runtime:function_binding",
@@ -1328,6 +1333,7 @@ cel_android_library(
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//common/values:cel_byte_string",
"//runtime:function_binding_android",
@@ -1347,6 +1353,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers",
"//common/internal:proto_time_utils",
"//runtime:function_binding",
"//runtime:runtime_equality",
@@ -1367,6 +1374,7 @@ cel_android_library(
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
+ "//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//runtime:function_binding_android",
"//runtime:runtime_equality_android",
@@ -1444,25 +1452,3 @@ java_library(
"//common:error_codes",
],
)
-
-java_library(
- name = "date_time_helpers",
- srcs = ["DateTimeHelpers.java"],
- visibility = ["//visibility:private"],
- deps = [
- "//common:error_codes",
- "//common:runtime_exception",
- "@maven//:com_google_protobuf_protobuf_java",
- ],
-)
-
-cel_android_library(
- name = "date_time_helpers_android",
- srcs = ["DateTimeHelpers.java"],
- visibility = ["//visibility:private"],
- deps = [
- "//common:error_codes",
- "//common:runtime_exception",
- "@maven_android//:com_google_protobuf_protobuf_javalite",
- ],
-)
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DateTimeHelpers.java b/runtime/src/main/java/dev/cel/runtime/standard/DateTimeHelpers.java
deleted file mode 100644
index d05125ed1..000000000
--- a/runtime/src/main/java/dev/cel/runtime/standard/DateTimeHelpers.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2025 Google LLC
-//
-// Licensed 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
-//
-// https://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 dev.cel.runtime.standard;
-
-import com.google.protobuf.Timestamp;
-import dev.cel.common.CelErrorCode;
-import dev.cel.common.CelRuntimeException;
-import java.time.DateTimeException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.Locale;
-
-final class DateTimeHelpers {
- static final String UTC = "UTC";
-
- /**
- * Constructs a new {@link LocalDateTime} instance
- *
- * @param ts Timestamp protobuf object
- * @param tz Timezone based on the CEL specification. This is either the canonical name from tz
- * database or a standard offset represented in (+/-)HH:MM. Few valid examples are:
- *
- * - UTC
- *
- America/Los_Angeles
- *
- -09:30 or -9:30 (Leading zeroes can be omitted though not allowed by spec)
- *
- *
- * @return If an Invalid timezone is supplied.
- */
- static LocalDateTime newLocalDateTime(Timestamp ts, String tz) {
- return Instant.ofEpochSecond(ts.getSeconds(), ts.getNanos())
- .atZone(timeZone(tz))
- .toLocalDateTime();
- }
-
- /**
- * Get the DateTimeZone Instance.
- *
- * @param tz the ID of the datetime zone
- * @return the ZoneId object
- */
- private static ZoneId timeZone(String tz) {
- try {
- return ZoneId.of(tz);
- } catch (DateTimeException e) {
- // If timezone is not a string name (for example, 'US/Central'), it should be a numerical
- // offset from UTC in the format [+/-]HH:MM.
- try {
- int ind = tz.indexOf(":");
- if (ind == -1) {
- throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
- }
-
- int hourOffset = Integer.parseInt(tz.substring(0, ind));
- int minOffset = Integer.parseInt(tz.substring(ind + 1));
- // Ensures that the offset are properly formatted in [+/-]HH:MM to conform with
- // ZoneOffset's format requirements.
- // Example: "-9:30" -> "-09:30" and "9:30" -> "+09:30"
- String formattedOffset =
- ((hourOffset < 0) ? "-" : "+")
- + String.format(Locale.getDefault(), "%02d:%02d", Math.abs(hourOffset), minOffset);
-
- return ZoneId.of(formattedOffset);
-
- } catch (DateTimeException e2) {
- throw new CelRuntimeException(e2, CelErrorCode.BAD_FORMAT);
- }
- }
- }
-
- private DateTimeHelpers() {}
-}
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java
index d54e2999b..b17a9871e 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java
@@ -43,18 +43,33 @@ public static DurationFunction create(Iterable
- CelFunctionBinding.from("duration_to_duration", Duration.class, (Duration x) -> x)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_duration", java.time.Duration.class, (java.time.Duration d) -> d);
+ } else {
+ return CelFunctionBinding.from(
+ "duration_to_duration", Duration.class, (Duration d) -> d);
+ }
+ }),
STRING_TO_DURATION(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
"string_to_duration",
String.class,
(String d) -> {
- try {
- return RuntimeHelpers.createDurationFromString(d);
- } catch (IllegalArgumentException e) {
- throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ try {
+ return RuntimeHelpers.createJavaDurationFromString(d);
+ } catch (IllegalArgumentException e) {
+ throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ }
+ } else {
+ try {
+ return RuntimeHelpers.createDurationFromString(d);
+ } catch (IllegalArgumentException e) {
+ throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ }
}
})),
;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java
index bd48ec7da..1c1b7ffd4 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java
@@ -14,14 +14,15 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getDate}. */
@@ -43,18 +44,35 @@ public static GetDateFunction create(Iterable o
/** Overloads for the standard function. */
public enum GetDateOverload implements CelStandardOverload {
TIMESTAMP_TO_DAY_OF_MONTH_1_BASED(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_month_1_based",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_month_1_based",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth())),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth());
+ }
+ }),
TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_month_1_based_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_month_1_based_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth())),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth());
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java
index 171353c04..1efa43620 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java
@@ -14,14 +14,15 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getDayOfMonth}. */
@@ -45,18 +46,35 @@ public static GetDayOfMonthFunction create(
/** Overloads for the standard function. */
public enum GetDayOfMonthOverload implements CelStandardOverload {
TIMESTAMP_TO_DAY_OF_MONTH(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_month",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_month",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth() - 1)),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth() - 1);
+ }
+ }),
TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_month_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_month_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth() - 1)),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth() - 1);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java
index 92ef90e79..4fa7000eb 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java
@@ -14,8 +14,8 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
@@ -23,6 +23,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import java.time.DayOfWeek;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getDayOfWeek}. */
@@ -46,18 +47,41 @@ public static GetDayOfWeekFunction create(
/** Overloads for the standard function. */
public enum GetDayOfWeekOverload implements CelStandardOverload {
TIMESTAMP_TO_DAY_OF_WEEK(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_week",
+ Instant.class,
+ (Instant ts) -> {
+ // CEL treats Sunday as day 0, but Java.time treats it as day 7.
+ DayOfWeek dayOfWeek = newLocalDateTime(ts, UTC).getDayOfWeek();
+ return (long) dayOfWeek.getValue() % 7;
+ });
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_week",
Timestamp.class,
(Timestamp ts) -> {
// CEL treats Sunday as day 0, but Java.time treats it as day 7.
DayOfWeek dayOfWeek = newLocalDateTime(ts, UTC).getDayOfWeek();
return (long) dayOfWeek.getValue() % 7;
- })),
+ });
+ }
+ }),
TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_week_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> {
+ // CEL treats Sunday as day 0, but Java.time treats it as day 7.
+ DayOfWeek dayOfWeek = newLocalDateTime(ts, tz).getDayOfWeek();
+ return (long) dayOfWeek.getValue() % 7;
+ });
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_week_with_tz",
Timestamp.class,
String.class,
@@ -65,7 +89,9 @@ public enum GetDayOfWeekOverload implements CelStandardOverload {
// CEL treats Sunday as day 0, but Java.time treats it as day 7.
DayOfWeek dayOfWeek = newLocalDateTime(ts, tz).getDayOfWeek();
return (long) dayOfWeek.getValue() % 7;
- }));
+ });
+ }
+ });
private final FunctionBindingCreator bindingCreator;
@Override
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java
index 8c4d90e64..c74a85c1c 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java
@@ -14,14 +14,15 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getDayOfYear}. */
@@ -45,18 +46,35 @@ public static GetDayOfYearFunction create(
/** Overloads for the standard function. */
public enum GetDayOfYearOverload implements CelStandardOverload {
TIMESTAMP_TO_DAY_OF_YEAR(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_year",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getDayOfYear() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_year",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfYear() - 1)),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfYear() - 1);
+ }
+ }),
TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_day_of_year_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfYear() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_day_of_year_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfYear() - 1)),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfYear() - 1);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java
index 61fe189cb..ca816eb80 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java
@@ -14,14 +14,15 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getFullYear}. */
@@ -44,18 +45,35 @@ public static GetFullYearFunction create(
/** Overloads for the standard function. */
public enum GetFullYearOverload implements CelStandardOverload {
TIMESTAMP_TO_YEAR(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_year",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getYear());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_year",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getYear())),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getYear());
+ }
+ }),
TIMESTAMP_TO_YEAR_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_year_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getYear());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_year_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getYear())),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getYear());
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java
index ee36bfbb0..28d559248 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java
@@ -14,8 +14,8 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Duration;
@@ -24,6 +24,7 @@
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getHours}. */
@@ -45,21 +46,45 @@ public static GetHoursFunction create(Iterable
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_hours",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getHour());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_hours",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getHour())),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getHour());
+ }
+ }),
TIMESTAMP_TO_HOURS_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_hours_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getHour());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_hours_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getHour())),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getHour());
+ }
+ }),
DURATION_TO_HOURS(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from("duration_to_hours", Duration.class, ProtoTimeUtils::toHours)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_hours", java.time.Duration.class, java.time.Duration::toHours);
+ } else {
+ return CelFunctionBinding.from(
+ "duration_to_hours", Duration.class, ProtoTimeUtils::toHours);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java
index 369cd9ea2..53ec92a82 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java
@@ -14,8 +14,8 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Duration;
@@ -24,6 +24,7 @@
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getMilliseconds}. */
@@ -51,27 +52,51 @@ public enum GetMillisecondsOverload implements CelStandardOverload {
// timestamp_to_milliseconds overload
@SuppressWarnings("JavaLocalDateTimeGetNano")
TIMESTAMP_TO_MILLISECONDS(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_milliseconds",
+ Instant.class,
+ (Instant ts) -> (long) (newLocalDateTime(ts, UTC).getNano() / 1e+6));
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_milliseconds",
Timestamp.class,
- (Timestamp ts) -> (long) (newLocalDateTime(ts, UTC).getNano() / 1e+6))),
-
+ (Timestamp ts) -> (long) (newLocalDateTime(ts, UTC).getNano() / 1e+6));
+ }
+ }),
@SuppressWarnings("JavaLocalDateTimeGetNano")
TIMESTAMP_TO_MILLISECONDS_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_milliseconds_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) (newLocalDateTime(ts, tz).getNano() / 1e+6));
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_milliseconds_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) (newLocalDateTime(ts, tz).getNano() / 1e+6))),
+ (Timestamp ts, String tz) -> (long) (newLocalDateTime(ts, tz).getNano() / 1e+6));
+ }
+ }),
DURATION_TO_MILLISECONDS(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_milliseconds",
+ java.time.Duration.class,
+ (java.time.Duration d) -> d.toMillis() % 1_000);
+ } else {
+ return CelFunctionBinding.from(
"duration_to_milliseconds",
Duration.class,
(Duration arg) ->
- ProtoTimeUtils.toMillis(arg) % java.time.Duration.ofSeconds(1).toMillis()));
+ ProtoTimeUtils.toMillis(arg) % java.time.Duration.ofSeconds(1).toMillis());
+ }
+ });
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java
index 24c285c46..62ee130b6 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java
@@ -14,8 +14,8 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Duration;
@@ -24,6 +24,7 @@
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getMinutes}. */
@@ -46,22 +47,45 @@ public static GetMinutesFunction create(
/** Overloads for the standard function. */
public enum GetMinutesOverload implements CelStandardOverload {
TIMESTAMP_TO_MINUTES(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_minutes",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getMinute());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_minutes",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMinute())),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMinute());
+ }
+ }),
TIMESTAMP_TO_MINUTES_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_minutes_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getMinute());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_minutes_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getMinute())),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getMinute());
+ }
+ }),
DURATION_TO_MINUTES(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "duration_to_minutes", Duration.class, ProtoTimeUtils::toMinutes)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_minutes", java.time.Duration.class, java.time.Duration::toMinutes);
+ } else {
+ return CelFunctionBinding.from(
+ "duration_to_minutes", Duration.class, ProtoTimeUtils::toMinutes);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java
index 34a33815d..99770e69f 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java
@@ -14,14 +14,15 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function runtime definition for {@code getMonth}. */
@@ -43,18 +44,35 @@ public static GetMonthFunction create(Iterable
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_month",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getMonthValue() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_month",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMonthValue() - 1)),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMonthValue() - 1);
+ }
+ }),
TIMESTAMP_TO_MONTH_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_month_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getMonthValue() - 1);
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_month_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getMonthValue() - 1)),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getMonthValue() - 1);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java
index e40fc62c5..f0357990b 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java
@@ -14,8 +14,8 @@
package dev.cel.runtime.standard;
-import static dev.cel.runtime.standard.DateTimeHelpers.UTC;
-import static dev.cel.runtime.standard.DateTimeHelpers.newLocalDateTime;
+import static dev.cel.common.internal.DateTimeHelpers.UTC;
+import static dev.cel.common.internal.DateTimeHelpers.newLocalDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Duration;
@@ -24,6 +24,7 @@
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code getSeconds}. */
@@ -47,22 +48,56 @@ public static GetSecondsFunction create(
/** Overloads for the standard function. */
public enum GetSecondsOverload implements CelStandardOverload {
TIMESTAMP_TO_SECONDS(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_seconds",
+ Instant.class,
+ (Instant ts) -> (long) newLocalDateTime(ts, UTC).getSecond());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_seconds",
Timestamp.class,
- (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getSecond())),
+ (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getSecond());
+ }
+ }),
TIMESTAMP_TO_SECONDS_WITH_TZ(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_seconds_with_tz",
+ Instant.class,
+ String.class,
+ (Instant ts, String tz) -> (long) newLocalDateTime(ts, tz).getSecond());
+ } else {
+ return CelFunctionBinding.from(
"timestamp_to_seconds_with_tz",
Timestamp.class,
String.class,
- (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getSecond())),
+ (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getSecond());
+ }
+ }),
DURATION_TO_SECONDS(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "duration_to_seconds", Duration.class, ProtoTimeUtils::toSeconds)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_seconds",
+ java.time.Duration.class,
+ dur -> {
+ long truncatedSeconds = dur.getSeconds();
+ // Preserve the existing behavior from protobuf where seconds is truncated towards
+ // 0 when negative.
+ if (dur.isNegative() && dur.getNano() > 0) {
+ truncatedSeconds++;
+ }
+
+ return truncatedSeconds;
+ });
+ } else {
+ return CelFunctionBinding.from(
+ "duration_to_seconds", Duration.class, ProtoTimeUtils::toSeconds);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java
index 1eaced251..03be9c41b 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java
@@ -26,6 +26,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for the greater equals (>=) operator. */
@@ -81,12 +82,21 @@ public enum GreaterEqualsOverload implements CelStandardOverload {
Double.class,
(Double x, Double y) -> x >= y)),
GREATER_EQUALS_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "greater_equals_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ (java.time.Duration d1, java.time.Duration d2) -> d1.compareTo(d2) >= 0);
+ } else {
+ return CelFunctionBinding.from(
"greater_equals_duration",
Duration.class,
Duration.class,
- (Duration x, Duration y) -> ProtoTimeUtils.compare(x, y) >= 0)),
+ (Duration d1, Duration d2) -> ProtoTimeUtils.compare(d1, d2) >= 0);
+ }
+ }),
GREATER_EQUALS_INT64(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
@@ -99,12 +109,21 @@ public enum GreaterEqualsOverload implements CelStandardOverload {
String.class,
(String x, String y) -> x.compareTo(y) >= 0)),
GREATER_EQUALS_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "greater_equals_timestamp",
+ Instant.class,
+ Instant.class,
+ (Instant i1, Instant i2) -> i1.compareTo(i2) >= 0);
+ } else {
+ return CelFunctionBinding.from(
"greater_equals_timestamp",
Timestamp.class,
Timestamp.class,
- (Timestamp x, Timestamp y) -> ProtoTimeUtils.compare(x, y) >= 0)),
+ (Timestamp t1, Timestamp t2) -> ProtoTimeUtils.compare(t1, t2) >= 0);
+ }
+ }),
GREATER_EQUALS_UINT64(
(celOptions, runtimeEquality) -> {
if (celOptions.enableUnsignedLongs()) {
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java
index 9eed5747b..f0db202a8 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java
@@ -26,6 +26,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for the greater (>) operator. */
@@ -73,12 +74,21 @@ public enum GreaterOverload implements CelStandardOverload {
CelFunctionBinding.from(
"greater_double", Double.class, Double.class, (Double x, Double y) -> x > y)),
GREATER_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "greater_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ (java.time.Duration d1, java.time.Duration d2) -> d1.compareTo(d2) > 0);
+ } else {
+ return CelFunctionBinding.from(
"greater_duration",
Duration.class,
Duration.class,
- (Duration x, Duration y) -> ProtoTimeUtils.compare(x, y) > 0)),
+ (Duration d1, Duration d2) -> ProtoTimeUtils.compare(d1, d2) > 0);
+ }
+ }),
GREATER_INT64(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
@@ -91,12 +101,21 @@ public enum GreaterOverload implements CelStandardOverload {
String.class,
(String x, String y) -> x.compareTo(y) > 0)),
GREATER_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "greater_timestamp",
+ Instant.class,
+ Instant.class,
+ (Instant i1, Instant i2) -> i1.isAfter(i2));
+ } else {
+ return CelFunctionBinding.from(
"greater_timestamp",
Timestamp.class,
Timestamp.class,
- (Timestamp x, Timestamp y) -> ProtoTimeUtils.compare(x, y) > 0)),
+ (Timestamp t1, Timestamp t2) -> ProtoTimeUtils.compare(t1, t2) > 0);
+ }
+ }),
GREATER_UINT64(
(celOptions, runtimeEquality) -> {
if (celOptions.enableUnsignedLongs()) {
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java
index b29ca37a6..17ad835cb 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java
@@ -24,6 +24,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code int} conversion function. */
@@ -104,9 +105,15 @@ public enum IntOverload implements CelStandardOverload {
}
})),
TIMESTAMP_TO_INT64(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "timestamp_to_int64", Timestamp.class, ProtoTimeUtils::toSeconds)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_int64", Instant.class, Instant::getEpochSecond);
+ } else {
+ return CelFunctionBinding.from(
+ "timestamp_to_int64", Timestamp.class, ProtoTimeUtils::toSeconds);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java
index 3da852f8a..8ff6f5248 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java
@@ -26,6 +26,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for the less equals (<=) operator. */
@@ -77,12 +78,21 @@ public enum LessEqualsOverload implements CelStandardOverload {
CelFunctionBinding.from(
"less_equals_double", Double.class, Double.class, (Double x, Double y) -> x <= y)),
LESS_EQUALS_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "less_equals_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ (java.time.Duration d1, java.time.Duration d2) -> d1.compareTo(d2) <= 0);
+ } else {
+ return CelFunctionBinding.from(
"less_equals_duration",
Duration.class,
Duration.class,
- (Duration x, Duration y) -> ProtoTimeUtils.compare(x, y) <= 0)),
+ (Duration d1, Duration d2) -> ProtoTimeUtils.compare(d1, d2) <= 0);
+ }
+ }),
LESS_EQUALS_INT64(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
@@ -95,12 +105,21 @@ public enum LessEqualsOverload implements CelStandardOverload {
String.class,
(String x, String y) -> x.compareTo(y) <= 0)),
LESS_EQUALS_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "less_equals_timestamp",
+ Instant.class,
+ Instant.class,
+ (Instant i1, Instant i2) -> i1.compareTo(i2) <= 0);
+ } else {
+ return CelFunctionBinding.from(
"less_equals_timestamp",
Timestamp.class,
Timestamp.class,
- (Timestamp x, Timestamp y) -> ProtoTimeUtils.compare(x, y) <= 0)),
+ (Timestamp t1, Timestamp t2) -> ProtoTimeUtils.compare(t1, t2) <= 0);
+ }
+ }),
LESS_EQUALS_UINT64(
(celOptions, runtimeEquality) -> {
if (celOptions.enableUnsignedLongs()) {
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java
index 8bae06a85..d348555b7 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java
@@ -26,6 +26,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for the less (<) operator. */
@@ -135,12 +136,21 @@ public enum LessOverload implements CelStandardOverload {
Double.class,
(UnsignedLong x, Double y) -> ComparisonFunctions.compareUintDouble(x, y) == -1)),
LESS_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "less_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ (java.time.Duration d1, java.time.Duration d2) -> d1.compareTo(d2) < 0);
+ } else {
+ return CelFunctionBinding.from(
"less_duration",
Duration.class,
Duration.class,
- (Duration x, Duration y) -> ProtoTimeUtils.compare(x, y) < 0)),
+ (Duration d1, Duration d2) -> ProtoTimeUtils.compare(d1, d2) < 0);
+ }
+ }),
LESS_STRING(
(celOptions, runtimeEquality) ->
CelFunctionBinding.from(
@@ -149,12 +159,21 @@ public enum LessOverload implements CelStandardOverload {
String.class,
(String x, String y) -> x.compareTo(y) < 0)),
LESS_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "less_timestamp",
+ Instant.class,
+ Instant.class,
+ (Instant i1, Instant i2) -> i1.isBefore(i2));
+ } else {
+ return CelFunctionBinding.from(
"less_timestamp",
Timestamp.class,
Timestamp.class,
- (Timestamp x, Timestamp y) -> ProtoTimeUtils.compare(x, y) < 0)),
+ (Timestamp t1, Timestamp t2) -> ProtoTimeUtils.compare(t1, t2) < 0);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java
index 3525ba5e0..aa1935876 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java
@@ -23,10 +23,12 @@
import dev.cel.common.CelErrorCode;
import dev.cel.common.CelOptions;
import dev.cel.common.CelRuntimeException;
+import dev.cel.common.internal.DateTimeHelpers;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.values.CelByteString;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for {@code string} conversion function. */
@@ -90,13 +92,24 @@ public enum StringOverload implements CelStandardOverload {
}
}),
TIMESTAMP_TO_STRING(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "timestamp_to_string", Timestamp.class, ProtoTimeUtils::toString)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from("timestamp_to_string", Instant.class, Instant::toString);
+ } else {
+ return CelFunctionBinding.from(
+ "timestamp_to_string", Timestamp.class, ProtoTimeUtils::toString);
+ }
+ }),
DURATION_TO_STRING(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "duration_to_string", Duration.class, ProtoTimeUtils::toString)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "duration_to_string", java.time.Duration.class, DateTimeHelpers::toString);
+ } else {
+ return CelFunctionBinding.from(
+ "duration_to_string", Duration.class, ProtoTimeUtils::toString);
+ }
+ }),
UINT64_TO_STRING(
(celOptions, runtimeEquality) -> {
if (celOptions.enableUnsignedLongs()) {
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java
index 695650390..a5d1359cc 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java
@@ -22,10 +22,12 @@
import com.google.protobuf.Timestamp;
import dev.cel.common.CelOptions;
import dev.cel.common.CelRuntimeException;
+import dev.cel.common.internal.DateTimeHelpers;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import dev.cel.runtime.RuntimeHelpers;
+import java.time.Instant;
import java.util.Arrays;
/** Standard function for the subtraction (-) operator. */
@@ -60,19 +62,37 @@ public enum SubtractOverload implements CelStandardOverload {
}
})),
SUBTRACT_TIMESTAMP_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "subtract_timestamp_timestamp",
+ Instant.class,
+ Instant.class,
+ (Instant i1, Instant i2) -> java.time.Duration.between(i2, i1));
+ } else {
+ return CelFunctionBinding.from(
"subtract_timestamp_timestamp",
Timestamp.class,
Timestamp.class,
- (Timestamp x, Timestamp y) -> ProtoTimeUtils.between(y, x))),
+ (Timestamp t1, Timestamp t2) -> ProtoTimeUtils.between(t2, t1));
+ }
+ }),
SUBTRACT_TIMESTAMP_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "subtract_timestamp_duration",
+ Instant.class,
+ java.time.Duration.class,
+ DateTimeHelpers::subtract);
+ } else {
+ return CelFunctionBinding.from(
"subtract_timestamp_duration",
Timestamp.class,
Duration.class,
- ProtoTimeUtils::subtract)),
+ ProtoTimeUtils::subtract);
+ }
+ }),
SUBTRACT_UINT64(
(celOptions, runtimeEquality) -> {
if (celOptions.enableUnsignedLongs()) {
@@ -106,12 +126,21 @@ public enum SubtractOverload implements CelStandardOverload {
CelFunctionBinding.from(
"subtract_double", Double.class, Double.class, (Double x, Double y) -> x - y)),
SUBTRACT_DURATION_DURATION(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "subtract_duration_duration",
+ java.time.Duration.class,
+ java.time.Duration.class,
+ DateTimeHelpers::subtract);
+ } else {
+ return CelFunctionBinding.from(
"subtract_duration_duration",
Duration.class,
Duration.class,
- ProtoTimeUtils::subtract)),
+ ProtoTimeUtils::subtract);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java
index 9b64b78cb..8ed250143 100644
--- a/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java
+++ b/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java
@@ -19,10 +19,13 @@
import dev.cel.common.CelErrorCode;
import dev.cel.common.CelOptions;
import dev.cel.common.CelRuntimeException;
+import dev.cel.common.internal.DateTimeHelpers;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.RuntimeEquality;
import java.text.ParseException;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
import java.util.Arrays;
/** Standard function for {@code timestamp} conversion function. */
@@ -42,6 +45,7 @@ public static TimestampFunction create(Iterable
@@ -49,19 +53,41 @@ public enum TimestampOverload implements CelStandardOverload {
"string_to_timestamp",
String.class,
(String ts) -> {
- try {
- return ProtoTimeUtils.parse(ts);
- } catch (ParseException e) {
- throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ try {
+ return DateTimeHelpers.parse(ts);
+ } catch (DateTimeParseException e) {
+ throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ }
+
+ } else {
+ try {
+ return ProtoTimeUtils.parse(ts);
+ } catch (ParseException e) {
+ throw new CelRuntimeException(e, CelErrorCode.BAD_FORMAT);
+ }
}
})),
TIMESTAMP_TO_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from("timestamp_to_timestamp", Timestamp.class, (Timestamp x) -> x)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "timestamp_to_timestamp", Instant.class, (Instant x) -> x);
+ } else {
+ return CelFunctionBinding.from(
+ "timestamp_to_timestamp", Timestamp.class, (Timestamp x) -> x);
+ }
+ }),
INT64_TO_TIMESTAMP(
- (celOptions, runtimeEquality) ->
- CelFunctionBinding.from(
- "int64_to_timestamp", Long.class, ProtoTimeUtils::fromSecondsToTimestamp)),
+ (celOptions, runtimeEquality) -> {
+ if (celOptions.evaluateCanonicalTypesToNativeValues()) {
+ return CelFunctionBinding.from(
+ "int64_to_timestamp", Long.class, Instant::ofEpochSecond);
+ } else {
+ return CelFunctionBinding.from(
+ "int64_to_timestamp", Long.class, ProtoTimeUtils::fromSecondsToTimestamp);
+ }
+ }),
;
private final FunctionBindingCreator bindingCreator;
diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
index 2896e36f4..a960b6249 100644
--- a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
+++ b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
@@ -51,6 +51,8 @@
import dev.cel.runtime.standard.EqualsOperator;
import dev.cel.runtime.standard.IntFunction;
import dev.cel.runtime.standard.IntFunction.IntOverload;
+import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import org.junit.Test;
@@ -705,16 +707,8 @@ public void eval_protoMessage_mapFields(String checkedExpr) throws Exception {
ImmutableMap.of(true, 9.1d, false, 10.2d),
ImmutableMap.of(true, 11.3d, false, 12.4d),
ImmutableMap.of(true, 1L, false, 2L), // Note: Enums are converted into integers
- ImmutableMap.of(
- true,
- ProtoTimeUtils.fromSecondsToDuration(15),
- false,
- ProtoTimeUtils.fromSecondsToDuration(16)),
- ImmutableMap.of(
- true,
- ProtoTimeUtils.fromSecondsToTimestamp(17),
- false,
- ProtoTimeUtils.fromSecondsToTimestamp(18)))
+ ImmutableMap.of(true, Duration.ofSeconds(15), false, Duration.ofSeconds(16)),
+ ImmutableMap.of(true, Instant.ofEpochSecond(17), false, Instant.ofEpochSecond(18)))
.inOrder();
}
diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java
index 4083ae494..4ffe0941c 100644
--- a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java
+++ b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java
@@ -25,14 +25,12 @@
import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.DoubleValue;
-import com.google.protobuf.Duration;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
import com.google.protobuf.ListValue;
import com.google.protobuf.StringValue;
import com.google.protobuf.Struct;
-import com.google.protobuf.Timestamp;
import com.google.protobuf.UInt32Value;
import com.google.protobuf.UInt64Value;
import com.google.protobuf.util.Values;
@@ -63,6 +61,8 @@
import dev.cel.testing.testdata.SimpleEnum;
import dev.cel.testing.testdata.SingleFileCelDescriptor;
import dev.cel.testing.testdata.SingleFileProto.SingleFile;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -301,7 +301,7 @@ public void fieldSelection_duration() throws Exception {
Duration result = (Duration) CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", msg));
- assertThat(result).isEqualTo(ProtoTimeUtils.fromSecondsToDuration(600));
+ assertThat(result).isEqualTo(Duration.ofMinutes(10));
}
@Test
@@ -313,9 +313,9 @@ public void fieldSelection_timestamp() throws Exception {
.setSingleTimestamp(ProtoTimeUtils.fromSecondsToTimestamp(50))
.build();
- Timestamp result = (Timestamp) CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", msg));
+ Instant result = (Instant) CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", msg));
- assertThat(result).isEqualTo(ProtoTimeUtils.fromSecondsToTimestamp(50));
+ assertThat(result).isEqualTo(Instant.ofEpochSecond(50));
}
@Test
diff --git a/runtime/src/test/resources/arithmDuration.baseline b/runtime/src/test/resources/arithmDuration.baseline
index 3422aced4..9aa73405d 100644
--- a/runtime/src/test/resources/arithmDuration.baseline
+++ b/runtime/src/test/resources/arithmDuration.baseline
@@ -9,13 +9,7 @@ declare d3 {
value google.protobuf.Duration
}
=====>
-bindings: {d3=seconds: 25
-nanos: 45
-} +> {d2=seconds: 10
-nanos: 20
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {d3=PT25.000000045S} +> {d2=PT10.00000002S} +> {d1=PT15.000000025S}
result: true
Source: d3 - d1 == d2
@@ -29,11 +23,5 @@ declare d3 {
value google.protobuf.Duration
}
=====>
-bindings: {d3=seconds: 25
-nanos: 45
-} +> {d2=seconds: 10
-nanos: 20
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {d3=PT25.000000045S} +> {d2=PT10.00000002S} +> {d1=PT15.000000025S}
result: true
\ No newline at end of file
diff --git a/runtime/src/test/resources/arithmTimestamp.baseline b/runtime/src/test/resources/arithmTimestamp.baseline
index d7a1f318c..7ddf702ae 100644
--- a/runtime/src/test/resources/arithmTimestamp.baseline
+++ b/runtime/src/test/resources/arithmTimestamp.baseline
@@ -9,13 +9,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {ts2=seconds: 10
-nanos: 10
-} +> {ts1=seconds: 25
-nanos: 35
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {ts2=1970-01-01T00:00:10.000000010Z} +> {ts1=1970-01-01T00:00:25.000000035Z} +> {d1=PT15.000000025S}
result: true
Source: ts1 - d1 == ts2
@@ -29,13 +23,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {ts2=seconds: 10
-nanos: 10
-} +> {ts1=seconds: 25
-nanos: 35
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {ts2=1970-01-01T00:00:10.000000010Z} +> {ts1=1970-01-01T00:00:25.000000035Z} +> {d1=PT15.000000025S}
result: true
Source: ts2 + d1 == ts1
@@ -49,13 +37,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {ts2=seconds: 10
-nanos: 10
-} +> {ts1=seconds: 25
-nanos: 35
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {ts2=1970-01-01T00:00:10.000000010Z} +> {ts1=1970-01-01T00:00:25.000000035Z} +> {d1=PT15.000000025S}
result: true
Source: d1 + ts2 == ts1
@@ -69,11 +51,5 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {ts2=seconds: 10
-nanos: 10
-} +> {ts1=seconds: 25
-nanos: 35
-} +> {d1=seconds: 15
-nanos: 25
-}
+bindings: {ts2=1970-01-01T00:00:10.000000010Z} +> {ts1=1970-01-01T00:00:25.000000035Z} +> {d1=PT15.000000025S}
result: true
\ No newline at end of file
diff --git a/runtime/src/test/resources/duration.baseline b/runtime/src/test/resources/duration.baseline
index 9737a23c7..89d058086 100644
--- a/runtime/src/test/resources/duration.baseline
+++ b/runtime/src/test/resources/duration.baseline
@@ -6,11 +6,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 9
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.000000009S} +> {d1=PT10.00000001S}
result: false
Source: d1 < d2
@@ -21,11 +17,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 9
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT9.00000001S} +> {d1=PT10.00000001S}
result: false
Source: d1 < d2
@@ -36,11 +28,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.00000001S}
result: false
Source: d1 < d2
@@ -51,11 +39,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 9
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.000000009S}
result: true
Source: d1 < d2
@@ -66,11 +50,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 9
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT9.00000001S}
result: true
Source: d1 <= d2
@@ -81,11 +61,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 9
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.000000009S} +> {d1=PT10.00000001S}
result: false
Source: d1 <= d2
@@ -96,11 +72,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 9
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT9.00000001S} +> {d1=PT10.00000001S}
result: false
Source: d1 <= d2
@@ -111,11 +83,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.00000001S}
result: true
Source: d1 <= d2
@@ -126,11 +94,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 9
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.000000009S}
result: true
Source: d1 <= d2
@@ -141,11 +105,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 9
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT9.00000001S}
result: true
Source: d1 > d2
@@ -156,11 +116,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 9
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.000000009S} +> {d1=PT10.00000001S}
result: true
Source: d1 > d2
@@ -171,11 +127,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 9
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT9.00000001S} +> {d1=PT10.00000001S}
result: true
Source: d1 > d2
@@ -186,11 +138,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.00000001S}
result: false
Source: d1 > d2
@@ -201,11 +149,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 9
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.000000009S}
result: false
Source: d1 > d2
@@ -216,11 +160,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 9
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT9.00000001S}
result: false
Source: d1 >= d2
@@ -231,11 +171,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 9
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.000000009S} +> {d1=PT10.00000001S}
result: true
Source: d1 >= d2
@@ -246,11 +182,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 9
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT9.00000001S} +> {d1=PT10.00000001S}
result: true
Source: d1 >= d2
@@ -261,11 +193,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.00000001S}
result: true
Source: d1 >= d2
@@ -276,11 +204,7 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 10
-nanos: 9
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT10.000000009S}
result: false
Source: d1 >= d2
@@ -291,9 +215,5 @@ declare d2 {
value google.protobuf.Duration
}
=====>
-bindings: {d2=seconds: 10
-nanos: 10
-} +> {d1=seconds: 9
-nanos: 10
-}
+bindings: {d2=PT10.00000001S} +> {d1=PT9.00000001S}
result: false
\ No newline at end of file
diff --git a/runtime/src/test/resources/durationFunctions.baseline b/runtime/src/test/resources/durationFunctions.baseline
index 8e942e0d8..9bc61d4ae 100644
--- a/runtime/src/test/resources/durationFunctions.baseline
+++ b/runtime/src/test/resources/durationFunctions.baseline
@@ -3,9 +3,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {d1=PT25H59M1.011S}
result: 25
Source: d1.getHours()
@@ -13,9 +11,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: -93541
-nanos: -11000000
-}
+bindings: {d1=PT-25H-59M-1.011S}
result: -25
Source: d1.getMinutes()
@@ -23,9 +19,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {d1=PT25H59M1.011S}
result: 1559
Source: d1.getMinutes()
@@ -33,9 +27,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: -93541
-nanos: -11000000
-}
+bindings: {d1=PT-25H-59M-1.011S}
result: -1559
Source: d1.getSeconds()
@@ -43,9 +35,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {d1=PT25H59M1.011S}
result: 93541
Source: d1.getSeconds()
@@ -53,9 +43,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: -93541
-nanos: -11000000
-}
+bindings: {d1=PT-25H-59M-1.011S}
result: -93541
Source: d1.getMilliseconds()
@@ -63,9 +51,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {d1=PT25H59M1.011S}
result: 11
Source: d1.getMilliseconds()
@@ -73,9 +59,7 @@ declare d1 {
value google.protobuf.Duration
}
=====>
-bindings: {d1=seconds: -93541
-nanos: -11000000
-}
+bindings: {d1=PT-25H-59M-1.011S}
result: -11
Source: d1.getHours() < val
@@ -86,9 +70,7 @@ declare val {
value int
}
=====>
-bindings: {val=30} +> {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {val=30} +> {d1=PT25H59M1.011S}
result: true
Source: d1.getMinutes() > val
@@ -99,9 +81,7 @@ declare val {
value int
}
=====>
-bindings: {val=30} +> {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {val=30} +> {d1=PT25H59M1.011S}
result: true
Source: d1.getSeconds() > val
@@ -112,9 +92,7 @@ declare val {
value int
}
=====>
-bindings: {val=30} +> {d1=seconds: 93541
-nanos: 11000000
-}
+bindings: {val=30} +> {d1=PT25H59M1.011S}
result: true
Source: d1.getMilliseconds() < val
@@ -125,7 +103,5 @@ declare val {
value int
}
=====>
-bindings: {val=30} +> {d1=seconds: 93541
-nanos: 11000000
-}
-result: true
\ No newline at end of file
+bindings: {val=30} +> {d1=PT25H59M1.011S}
+result: true
diff --git a/runtime/src/test/resources/dynamicMessage_adapted.baseline b/runtime/src/test/resources/dynamicMessage_adapted.baseline
index 789a39488..b012c3727 100644
--- a/runtime/src/test/resources/dynamicMessage_adapted.baseline
+++ b/runtime/src/test/resources/dynamicMessage_adapted.baseline
@@ -690,9 +690,7 @@ list_value {
}
}
}
-result: seconds: 10
-nanos: 20
-
+result: PT10.00000002S
Source: msg.single_timestamp
declare msg {
@@ -755,9 +753,7 @@ list_value {
}
}
}
-result: seconds: 100
-nanos: 200
-
+result: 1970-01-01T00:01:40.000000200Z
Source: msg.single_value
declare msg {
diff --git a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline
index 36dac04c3..8f91353b4 100644
--- a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline
+++ b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline
@@ -103,8 +103,7 @@ declare dur {
bindings: {dur=type_url: "type.googleapis.com/google.protobuf.Duration"
value: "\bd"
}
-result: seconds: 100
-
+result: PT1M40S
Source: TestAllTypes { single_any: any_packed_test_msg }.single_any
declare any_packed_test_msg {
diff --git a/runtime/src/test/resources/timeConversions.baseline b/runtime/src/test/resources/timeConversions.baseline
index 68892ee2d..12a521441 100644
--- a/runtime/src/test/resources/timeConversions.baseline
+++ b/runtime/src/test/resources/timeConversions.baseline
@@ -4,9 +4,7 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 63126020
-nanos: 21000000
-
+result: 1972-01-01T15:00:20.021Z
Source: timestamp(123)
declare t1 {
@@ -14,8 +12,7 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 123
-
+result: 1970-01-01T00:02:03Z
Source: duration("15.11s")
declare t1 {
@@ -23,17 +20,14 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 15
-nanos: 110000000
-
+result: PT15.11S
Source: int(t1) == 100
declare t1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t1=seconds: 100
-}
+bindings: {t1=1970-01-01T00:01:40Z}
result: true
Source: duration("1h2m3.4s")
@@ -42,9 +36,7 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 3723
-nanos: 400000000
-
+result: PT1H2M3.4S
Source: duration(duration('15.0s'))
declare t1 {
@@ -52,8 +44,7 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 15
-
+result: PT15S
Source: timestamp(timestamp(123))
declare t1 {
@@ -61,4 +52,4 @@ declare t1 {
}
=====>
bindings: {}
-result: seconds: 123
\ No newline at end of file
+result: 1970-01-01T00:02:03Z
\ No newline at end of file
diff --git a/runtime/src/test/resources/timestamp.baseline b/runtime/src/test/resources/timestamp.baseline
index c215b581f..828e7f912 100644
--- a/runtime/src/test/resources/timestamp.baseline
+++ b/runtime/src/test/resources/timestamp.baseline
@@ -6,11 +6,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 9
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000009Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 < t2
@@ -21,11 +17,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 9
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:09.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 < t2
@@ -36,11 +28,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 < t2
@@ -51,11 +39,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 9
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000009Z}
result: true
Source: t1 < t2
@@ -66,11 +50,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 9
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:09.000000010Z}
result: true
Source: t1 <= t2
@@ -81,11 +61,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 9
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000009Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 <= t2
@@ -96,11 +72,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 9
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:09.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 <= t2
@@ -111,11 +83,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 <= t2
@@ -126,11 +94,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 9
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000009Z}
result: true
Source: t1 <= t2
@@ -141,11 +105,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 9
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:09.000000010Z}
result: true
Source: t1 > t2
@@ -156,11 +116,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 9
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000009Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 > t2
@@ -171,11 +127,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 9
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:09.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 > t2
@@ -186,11 +138,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: false
Source: t1 > t2
@@ -201,11 +149,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 9
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000009Z}
result: false
Source: t1 > t2
@@ -216,11 +160,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 9
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:09.000000010Z}
result: false
Source: t1 >= t2
@@ -231,11 +171,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 9
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000009Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 >= t2
@@ -246,11 +182,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 9
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:09.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 >= t2
@@ -261,11 +193,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 10
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000010Z}
result: true
Source: t1 >= t2
@@ -276,11 +204,7 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 10
-nanos: 9
-}
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:10.000000009Z}
result: false
Source: t1 >= t2
@@ -291,9 +215,5 @@ declare t2 {
value google.protobuf.Timestamp
}
=====>
-bindings: {t2=seconds: 10
-nanos: 10
-} +> {t1=seconds: 9
-nanos: 10
-}
-result: false
+bindings: {t2=1970-01-01T00:00:10.000000010Z} +> {t1=1970-01-01T00:00:09.000000010Z}
+result: false
\ No newline at end of file
diff --git a/runtime/src/test/resources/timestampFunctions.baseline b/runtime/src/test/resources/timestampFunctions.baseline
index 322137892..e932867e8 100644
--- a/runtime/src/test/resources/timestampFunctions.baseline
+++ b/runtime/src/test/resources/timestampFunctions.baseline
@@ -3,9 +3,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1969
Source: ts1.getFullYear()
@@ -13,9 +11,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1970
Source: ts1.getFullYear()
@@ -23,8 +19,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 1969
Source: ts1.getFullYear("Indian/Cocos")
@@ -32,9 +27,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1970
Source: ts1.getFullYear("2:00")
@@ -42,9 +35,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1970
Source: ts1.getMonth("America/Los_Angeles")
@@ -52,9 +43,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getMonth()
@@ -62,9 +51,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getMonth()
@@ -72,8 +59,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 11
Source: ts1.getMonth("Indian/Cocos")
@@ -81,9 +67,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getMonth("-8:15")
@@ -91,9 +75,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getDayOfYear("America/Los_Angeles")
@@ -101,9 +83,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 364
Source: ts1.getDayOfYear()
@@ -111,9 +91,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getDayOfYear()
@@ -121,8 +99,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 364
Source: ts1.getDayOfYear("Indian/Cocos")
@@ -130,9 +107,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getDayOfYear("-9:00")
@@ -140,9 +115,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 364
Source: ts1.getDayOfMonth("America/Los_Angeles")
@@ -150,9 +123,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 30
Source: ts1.getDayOfMonth()
@@ -160,9 +131,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getDayOfMonth()
@@ -170,8 +139,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 30
Source: ts1.getDayOfMonth("Indian/Cocos")
@@ -179,9 +147,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getDayOfMonth("8:00")
@@ -189,9 +155,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getDate("America/Los_Angeles")
@@ -199,9 +163,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 31
Source: ts1.getDate()
@@ -209,9 +171,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getDate()
@@ -219,8 +179,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 31
Source: ts1.getDate("Indian/Cocos")
@@ -228,9 +187,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getDate("9:30")
@@ -238,9 +195,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getDayOfWeek("America/Los_Angeles")
@@ -248,8 +203,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 259200
-}
+bindings: {ts1=1970-01-04T00:00:00Z}
result: 6
Source: ts1.getDayOfWeek()
@@ -257,8 +211,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 259200
-}
+bindings: {ts1=1970-01-04T00:00:00Z}
result: 0
Source: ts1.getDayOfWeek()
@@ -266,8 +219,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 3
Source: ts1.getDayOfWeek("Indian/Cocos")
@@ -275,8 +227,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 259200
-}
+bindings: {ts1=1970-01-04T00:00:00Z}
result: 0
Source: ts1.getDayOfWeek("-9:30")
@@ -284,8 +235,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 259200
-}
+bindings: {ts1=1970-01-04T00:00:00Z}
result: 6
Source: ts1.getHours("America/Los_Angeles")
@@ -293,9 +243,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 16
Source: ts1.getHours()
@@ -303,9 +251,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getHours()
@@ -313,8 +259,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 23
Source: ts1.getHours("Indian/Cocos")
@@ -322,9 +267,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 6
Source: ts1.getHours("6:30")
@@ -332,9 +275,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 6
Source: ts1.getMinutes("America/Los_Angeles")
@@ -342,9 +283,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getMinutes()
@@ -352,9 +291,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getMinutes()
@@ -362,8 +299,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 59
Source: ts1.getMinutes("Indian/Cocos")
@@ -371,9 +307,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 30
Source: ts1.getMinutes("-8:00")
@@ -381,9 +315,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 0
Source: ts1.getSeconds("America/Los_Angeles")
@@ -391,9 +323,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getSeconds()
@@ -401,9 +331,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getSeconds()
@@ -411,8 +339,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: -1
-}
+bindings: {ts1=1969-12-31T23:59:59Z}
result: 59
Source: ts1.getSeconds("Indian/Cocos")
@@ -420,9 +347,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getSeconds("-8:00")
@@ -430,9 +355,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 1
Source: ts1.getMilliseconds("America/Los_Angeles")
@@ -440,9 +363,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getMilliseconds()
@@ -450,9 +371,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getMilliseconds("Indian/Cocos")
@@ -460,9 +379,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getMilliseconds("-8:00")
@@ -470,9 +387,7 @@ declare ts1 {
value google.protobuf.Timestamp
}
=====>
-bindings: {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {ts1=1970-01-01T00:00:01.011Z}
result: 11
Source: ts1.getFullYear() < val
@@ -483,9 +398,7 @@ declare val {
value int
}
=====>
-bindings: {val=2013} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=2013} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getMonth() < val
@@ -496,9 +409,7 @@ declare val {
value int
}
=====>
-bindings: {val=12} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=12} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getDayOfYear() < val
@@ -509,9 +420,7 @@ declare val {
value int
}
=====>
-bindings: {val=13} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=13} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getDayOfMonth() < val
@@ -522,9 +431,7 @@ declare val {
value int
}
=====>
-bindings: {val=10} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=10} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getDate() < val
@@ -535,9 +442,7 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getDayOfWeek() < val
@@ -548,9 +453,7 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getHours() < val
@@ -561,9 +464,7 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getMinutes() < val
@@ -574,9 +475,7 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getSeconds() < val
@@ -587,9 +486,7 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
Source: ts1.getMilliseconds() < val
@@ -600,7 +497,5 @@ declare val {
value int
}
=====>
-bindings: {val=15} +> {ts1=seconds: 1
-nanos: 11000000
-}
+bindings: {val=15} +> {ts1=1970-01-01T00:00:01.011Z}
result: true
\ No newline at end of file
diff --git a/runtime/src/test/resources/typeComparisons.baseline b/runtime/src/test/resources/typeComparisons.baseline
index ae3e8aa01..e8fc3473f 100644
--- a/runtime/src/test/resources/typeComparisons.baseline
+++ b/runtime/src/test/resources/typeComparisons.baseline
@@ -42,3 +42,14 @@ Source: type(null) == null_type
=====>
bindings: {}
result: true
+
+Source: type(duration) == google.protobuf.Duration && type(timestamp) == google.protobuf.Timestamp
+declare duration {
+ value dyn
+}
+declare timestamp {
+ value dyn
+}
+=====>
+bindings: {duration=PT0S, timestamp=1970-01-01T00:00:00Z}
+result: true
diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline
index 8c7183761..ad97004f3 100644
--- a/runtime/src/test/resources/unknownResultSet.baseline
+++ b/runtime/src/test/resources/unknownResultSet.baseline
@@ -60,7 +60,7 @@ declare x {
}
=====>
bindings: {}
-error: evaluation error at test_location:31: Failed to parse timestamp: invalid timestamp "bad timestamp string"
+error: evaluation error at test_location:31: Text 'bad timestamp string' could not be parsed at index 0
error_code: BAD_FORMAT
Source: x.single_int32 == 1 || x.single_string == "test"
@@ -125,7 +125,7 @@ declare x {
}
=====>
bindings: {}
-error: evaluation error at test_location:31: Failed to parse timestamp: invalid timestamp "bad timestamp string"
+error: evaluation error at test_location:31: Text 'bad timestamp string' could not be parsed at index 0
error_code: BAD_FORMAT
Source: x.single_int32.f(1)
diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java
index cd0da5b80..147c5baf9 100644
--- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java
+++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java
@@ -37,7 +37,6 @@
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.DoubleValue;
-import com.google.protobuf.Duration;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
@@ -83,6 +82,8 @@
import dev.cel.runtime.CelVariableResolver;
import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum;
import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -344,9 +345,9 @@ public void arithmTimestamp() {
declareVariable("ts1", SimpleType.TIMESTAMP);
declareVariable("ts2", SimpleType.TIMESTAMP);
declareVariable("d1", SimpleType.DURATION);
- Duration d1 = Duration.newBuilder().setSeconds(15).setNanos(25).build();
- Timestamp ts1 = Timestamp.newBuilder().setSeconds(25).setNanos(35).build();
- Timestamp ts2 = Timestamp.newBuilder().setSeconds(10).setNanos(10).build();
+ Duration d1 = Duration.ofSeconds(15, 25);
+ Instant ts1 = Instant.ofEpochSecond(25, 35);
+ Instant ts2 = Instant.ofEpochSecond(10, 10);
CelVariableResolver resolver =
extend(
extend(ImmutableMap.of("d1", d1), ImmutableMap.of("ts1", ts1)),
@@ -371,9 +372,9 @@ public void arithmDuration() {
declareVariable("d1", SimpleType.DURATION);
declareVariable("d2", SimpleType.DURATION);
declareVariable("d3", SimpleType.DURATION);
- Duration d1 = Duration.newBuilder().setSeconds(15).setNanos(25).build();
- Duration d2 = Duration.newBuilder().setSeconds(10).setNanos(20).build();
- Duration d3 = Duration.newBuilder().setSeconds(25).setNanos(45).build();
+ java.time.Duration d1 = java.time.Duration.ofSeconds(15, 25);
+ java.time.Duration d2 = java.time.Duration.ofSeconds(10, 20);
+ java.time.Duration d3 = java.time.Duration.ofSeconds(25, 45);
CelVariableResolver resolver =
extend(
@@ -606,9 +607,9 @@ public void has() throws Exception {
public void duration() throws Exception {
declareVariable("d1", SimpleType.DURATION);
declareVariable("d2", SimpleType.DURATION);
- Duration d1010 = Duration.newBuilder().setSeconds(10).setNanos(10).build();
- Duration d1009 = Duration.newBuilder().setSeconds(10).setNanos(9).build();
- Duration d0910 = Duration.newBuilder().setSeconds(9).setNanos(10).build();
+ java.time.Duration d1010 = java.time.Duration.ofSeconds(10, 10);
+ java.time.Duration d1009 = java.time.Duration.ofSeconds(10, 9);
+ java.time.Duration d0910 = java.time.Duration.ofSeconds(9, 10);
container = CelContainer.ofName(Type.getDescriptor().getFile().getPackage());
source = "d1 < d2";
@@ -644,9 +645,9 @@ public void duration() throws Exception {
public void timestamp() throws Exception {
declareVariable("t1", SimpleType.TIMESTAMP);
declareVariable("t2", SimpleType.TIMESTAMP);
- Timestamp ts1010 = Timestamp.newBuilder().setSeconds(10).setNanos(10).build();
- Timestamp ts1009 = Timestamp.newBuilder().setSeconds(10).setNanos(9).build();
- Timestamp ts0910 = Timestamp.newBuilder().setSeconds(9).setNanos(10).build();
+ Instant ts1010 = Instant.ofEpochSecond(10, 10);
+ Instant ts1009 = Instant.ofEpochSecond(10, 9);
+ Instant ts0910 = Instant.ofEpochSecond(9, 10);
container = CelContainer.ofName(Type.getDescriptor().getFile().getPackage());
source = "t1 < t2";
@@ -691,7 +692,7 @@ public void packUnpackAny() {
declareVariable(
"message", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()));
declareVariable("list", ListType.create(SimpleType.DYN));
- Duration duration = ProtoTimeUtils.fromSecondsToDuration(100);
+ com.google.protobuf.Duration duration = ProtoTimeUtils.fromSecondsToDuration(100);
Any any = Any.pack(duration);
TestAllTypes message = TestAllTypes.newBuilder().setSingleAny(any).build();
@@ -960,10 +961,11 @@ public void namespacedVariables() {
@Test
public void durationFunctions() {
declareVariable("d1", SimpleType.DURATION);
- Duration d1 =
- Duration.newBuilder().setSeconds(25 * 3600 + 59 * 60 + 1).setNanos(11000000).build();
- Duration d2 =
- Duration.newBuilder().setSeconds(-(25 * 3600 + 59 * 60 + 1)).setNanos(-11000000).build();
+ long totalSeconds = 25 * 3600 + 59 * 60 + 1;
+ long nanos = 11000000;
+ Duration d1 = Duration.ofSeconds(totalSeconds, nanos);
+ Duration d2 = Duration.ofSeconds(-totalSeconds, -nanos);
+
container = CelContainer.ofName(Type.getDescriptor().getFile().getPackage());
source = "d1.getHours()";
@@ -997,8 +999,8 @@ public void durationFunctions() {
public void timestampFunctions() {
declareVariable("ts1", SimpleType.TIMESTAMP);
container = CelContainer.ofName(Type.getDescriptor().getFile().getPackage());
- Timestamp ts1 = Timestamp.newBuilder().setSeconds(1).setNanos(11000000).build();
- Timestamp ts2 = ProtoTimeUtils.fromSecondsToTimestamp(-1);
+ Instant ts1 = Instant.ofEpochSecond(1, 11000000);
+ Instant ts2 = Instant.ofEpochSecond(-1, 0);
source = "ts1.getFullYear(\"America/Los_Angeles\")";
runTest(ImmutableMap.of("ts1", ts1));
@@ -1050,7 +1052,7 @@ public void timestampFunctions() {
source = "ts1.getDate(\"9:30\")";
runTest(ImmutableMap.of("ts1", ts1));
- Timestamp tsSunday = ProtoTimeUtils.fromSecondsToTimestamp(3 * 24 * 3600);
+ Instant tsSunday = Instant.ofEpochSecond(3 * 24 * 3600);
source = "ts1.getDayOfWeek(\"America/Los_Angeles\")";
runTest(ImmutableMap.of("ts1", tsSunday));
source = "ts1.getDayOfWeek()";
@@ -1372,7 +1374,7 @@ public void timeConversions() {
runTest();
source = "int(t1) == 100";
- runTest(ImmutableMap.of("t1", ProtoTimeUtils.fromSecondsToTimestamp(100)));
+ runTest(ImmutableMap.of("t1", Instant.ofEpochSecond(100)));
source = "duration(\"1h2m3.4s\")";
runTest();
@@ -1927,6 +1929,15 @@ public void typeComparisons() {
// Test whether null resolves to null_type.
source = "type(null) == null_type";
runTest();
+
+ // Test runtime resolution of types
+ source =
+ "type(duration) == google.protobuf.Duration && "
+ + "type(timestamp) == google.protobuf.Timestamp";
+ // Intentionally declare as dyns
+ declareVariable("duration", SimpleType.DYN);
+ declareVariable("timestamp", SimpleType.DYN);
+ runTest(ImmutableMap.of("duration", java.time.Duration.ZERO, "timestamp", Instant.EPOCH));
}
@Test
@@ -2075,7 +2086,8 @@ public void dynamicMessage_adapted() throws Exception {
.setSingleStringWrapper(StringValue.of("hello"))
.setSingleUint32Wrapper(UInt32Value.of(12))
.setSingleUint64Wrapper(UInt64Value.of(34))
- .setSingleDuration(Duration.newBuilder().setSeconds(10).setNanos(20))
+ .setSingleDuration(
+ com.google.protobuf.Duration.newBuilder().setSeconds(10).setNanos(20))
.setSingleTimestamp(Timestamp.newBuilder().setSeconds(100).setNanos(200))
.setSingleValue(Value.newBuilder().setStringValue("a"))
.setSingleStruct(
@@ -2127,10 +2139,10 @@ public void dynamicMessage_adapted() throws Exception {
.isInstanceOf(BASE_CEL_OPTIONS.enableUnsignedLongs() ? UnsignedLong.class : Long.class);
source = "msg.single_duration";
- assertThat(runTest(input)).isInstanceOf(Duration.class);
+ assertThat(runTest(input)).isInstanceOf(java.time.Duration.class);
source = "msg.single_timestamp";
- assertThat(runTest(input)).isInstanceOf(Timestamp.class);
+ assertThat(runTest(input)).isInstanceOf(Instant.class);
source = "msg.single_value";
assertThat(runTest(input)).isInstanceOf(String.class);
diff --git a/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel b/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel
index a7e4c628c..3e32bbd2a 100644
--- a/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel
+++ b/testing/src/main/java/dev/cel/testing/utils/BUILD.bazel
@@ -17,6 +17,7 @@ java_library(
deps = [
"//common:cel_descriptors",
"//common/internal:default_instance_message_factory",
+ "//common/internal:proto_time_utils",
"//common/types",
"//common/types:type_providers",
"//common/values",
diff --git a/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java b/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java
index 0b27fa452..041c0f52d 100644
--- a/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java
+++ b/testing/src/main/java/dev/cel/testing/utils/ExprValueUtils.java
@@ -31,6 +31,7 @@
import dev.cel.common.CelDescriptorUtil;
import dev.cel.common.CelDescriptors;
import dev.cel.common.internal.DefaultInstanceMessageFactory;
+import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.types.CelType;
import dev.cel.common.types.ListType;
import dev.cel.common.types.MapType;
@@ -41,6 +42,8 @@
import dev.cel.runtime.CelUnknownSet;
import dev.cel.testing.testrunner.RegistryUtils;
import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -252,6 +255,19 @@ public static Value toValue(Object object, CelType type) throws Exception {
}
return Value.newBuilder().setMapValue(builder.build()).build();
}
+
+ if (object instanceof Instant) {
+ return Value.newBuilder()
+ .setObjectValue(Any.pack(ProtoTimeUtils.toProtoTimestamp((Instant) object)))
+ .build();
+ }
+
+ if (object instanceof Duration) {
+ return Value.newBuilder()
+ .setObjectValue(Any.pack(ProtoTimeUtils.toProtoDuration((Duration) object)))
+ .build();
+ }
+
if (object instanceof Message) {
return Value.newBuilder().setObjectValue(Any.pack((Message) object)).build();
}