diff --git a/netflix-sel/build.gradle b/netflix-sel/build.gradle index ecf4cadd..dd86b80b 100644 --- a/netflix-sel/build.gradle +++ b/netflix-sel/build.gradle @@ -1,5 +1,4 @@ dependencies { - implementation jodaTimeDep api slf4jApiDep testImplementation junitDep diff --git a/netflix-sel/gradle.lockfile b/netflix-sel/gradle.lockfile index fc383273..993a4300 100644 --- a/netflix-sel/gradle.lockfile +++ b/netflix-sel/gradle.lockfile @@ -1,6 +1,5 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -joda-time:joda-time:2.10.14=compileClasspath -org.slf4j:slf4j-api:1.7.36=compileClasspath +org.slf4j:slf4j-api:1.7.36=compileClasspath,runtimeClasspath empty=annotationProcessor diff --git a/netflix-sel/src/main/java/com/netflix/sel/security/SelClassLoader.java b/netflix-sel/src/main/java/com/netflix/sel/security/SelClassLoader.java index e6671675..bd6cc1ad 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/security/SelClassLoader.java +++ b/netflix-sel/src/main/java/com/netflix/sel/security/SelClassLoader.java @@ -16,12 +16,10 @@ import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import java.util.ResourceBundle; -import org.joda.time.DateTimeZone; -import org.joda.time.tz.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +31,7 @@ final class SelClassLoader extends ClassLoader { // hold references to avoid evicting objects during GC. private final List> preloadedClasses = new ArrayList<>(); - private final List preloadedTimezones = new ArrayList<>(); + private final List preloadedTimezones = new ArrayList<>(); private SelClassLoader() { loadSelClasses(); @@ -44,11 +42,8 @@ private void loadSelClasses() { loadClassesInPackage("com.netflix.sel.type"); loadClassesInPackage("com.netflix.sel.visitor"); loadClassesInPackage("com.netflix.sel.ext"); - loadClassesInPackage("org.joda.time"); - ResourceBundle.getBundle("org.joda.time.format.messages"); - Provider provider = DateTimeZone.getProvider(); // loads all zone info - provider.getAvailableIDs().forEach(id -> preloadedTimezones.add(provider.getZone(id))); + ZoneId.getAvailableZoneIds().forEach(id -> preloadedTimezones.add(ZoneId.of(id))); } private void loadClassInPackage(String path, String clazzName) { diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTime.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTime.java index b1f12947..fc3ccfd0 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTime.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTime.java @@ -16,50 +16,55 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; +import java.time.temporal.IsoFields; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.ReadableInstant; -import org.joda.time.base.AbstractDateTime; -import org.joda.time.base.BaseDateTime; -import org.joda.time.format.DateTimeFormatter; -/** Wrapper class to support org.joda.time.DateTime. */ +/** Wrapper class to support java.time.ZonedDateTime. */ public final class SelJodaDateTime extends AbstractSelType { - private DateTime val; + private ZonedDateTime val; - private SelJodaDateTime(DateTime val) { + static Clock CLOCK = Clock.systemDefaultZone(); + + private SelJodaDateTime(ZonedDateTime val) { this.val = val; } - static SelJodaDateTime of(DateTime d) { + static SelJodaDateTime of(ZonedDateTime d) { return new SelJodaDateTime(d); } static SelJodaDateTime create(SelType[] args) { if (args.length == 0) { - return new SelJodaDateTime(new DateTime()); + return new SelJodaDateTime(ZonedDateTime.now(CLOCK)); } else if (args.length == 1 && args[0].type() == SelTypes.LONG) { - return new SelJodaDateTime(new DateTime(((SelLong) args[0]).longVal())); + return new SelJodaDateTime(ZonedDateTime.ofInstant(Instant.ofEpochMilli(((SelLong) args[0]).longVal()), CLOCK.getZone())); } else if (args.length == 1) { - return new SelJodaDateTime(new DateTime(args[0].getInternalVal())); + return new SelJodaDateTime(ZonedDateTime.from((ZonedDateTime) args[0].getInternalVal())); } else if (args.length == 2) { - return new SelJodaDateTime( - new DateTime(args[0].getInternalVal(), ((SelJodaDateTimeZone) args[1]).getInternalVal())); + if (args[0].type() == SelTypes.LONG) { + return new SelJodaDateTime(ZonedDateTime.ofInstant(Instant.ofEpochMilli(((SelLong) args[0]).longVal()), (ZoneId) ((SelJodaDateTimeZone) args[1]).getInternalVal())); + } + return new SelJodaDateTime(((ZonedDateTime) args[0].getInternalVal()).withZoneSameLocal((ZoneId) ((SelJodaDateTimeZone) args[1]).getInternalVal())); } else if (args.length == 8) { return new SelJodaDateTime( - new DateTime( + ZonedDateTime.of( ((SelLong) args[0]).intVal(), ((SelLong) args[1]).intVal(), ((SelLong) args[2]).intVal(), ((SelLong) args[3]).intVal(), ((SelLong) args[4]).intVal(), ((SelLong) args[5]).intVal(), - ((SelLong) args[6]).intVal(), - ((SelJodaDateTimeZone) args[7]).getInternalVal())); + ((SelLong) args[6]).intVal() * 1000000, + (ZoneId) ((SelJodaDateTimeZone) args[7]).getInternalVal())); } throw new IllegalArgumentException( "Invalid input arguments (" + Arrays.toString(args) + ") for DateTime constructor"); @@ -81,7 +86,7 @@ public SelJodaDateTime assignOps(SelOp op, SelType rhs) { } @Override - public DateTime getInternalVal() { + public ZonedDateTime getInternalVal() { return val; } @@ -93,402 +98,394 @@ public DateTime getInternalVal() { map.put( "toString0", MethodHandles.lookup() - .findVirtual(DateTime.class, "toString", MethodType.methodType(String.class))); + .findVirtual(ZonedDateTime.class, "toString", MethodType.methodType(String.class))); map.put( "toString1", MethodHandles.lookup() .findVirtual( - DateTime.class, "toString", MethodType.methodType(String.class, String.class))); + SelJodaDateTime.class, "toStringWithFormat", MethodType.methodType(String.class, String.class))); map.put( "parse2", MethodHandles.lookup() .findStatic( - DateTime.class, + SelJodaDateTime.class, "parse", - MethodType.methodType(DateTime.class, String.class, DateTimeFormatter.class))); + MethodType.methodType(ZonedDateTime.class, CharSequence.class, DateTimeFormatter.class))); map.put( "withZone1", MethodHandles.lookup() .findVirtual( - DateTime.class, - "withZone", - MethodType.methodType(DateTime.class, DateTimeZone.class))); + ZonedDateTime.class, + "withZoneSameInstant", + MethodType.methodType(ZonedDateTime.class, ZoneId.class))); map.put( "minusYears1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusYears", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusYears", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusYears1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusYears", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusYears", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusMonths1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusMonths", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusMonths", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusMonths1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusMonths", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusMonths", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusWeeks1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusWeeks", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusWeeks", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusWeeks1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusWeeks", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusWeeks", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusDays1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusDays", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusDays", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusDays1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusDays", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusDays", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusHours1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusHours", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusHours", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusHours1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusHours", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusHours", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusMinutes1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusMinutes", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusMinutes", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusMinutes1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusMinutes", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusMinutes", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusSeconds1", MethodHandles.lookup() .findVirtual( - DateTime.class, "minusSeconds", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "minusSeconds", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusSeconds1", MethodHandles.lookup() .findVirtual( - DateTime.class, "plusSeconds", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "plusSeconds", MethodType.methodType(ZonedDateTime.class, long.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "minusMillis1", MethodHandles.lookup() - .findVirtual( - DateTime.class, "minusMillis", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + .findStatic( + SelJodaDateTime.class, "minusMillis", MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "plusMillis1", MethodHandles.lookup() - .findVirtual( - DateTime.class, "plusMillis", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + .findStatic( + SelJodaDateTime.class, "plusMillis", MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "isAfter1", MethodHandles.lookup() - .findVirtual( - ReadableInstant.class, + .findStatic( + SelJodaDateTime.class, "isAfter", - MethodType.methodType(boolean.class, ReadableInstant.class))); + MethodType.methodType(boolean.class, ZonedDateTime.class, ZonedDateTime.class))); map.put( "isBefore1", MethodHandles.lookup() - .findVirtual( - ReadableInstant.class, + .findStatic( + SelJodaDateTime.class, "isBefore", - MethodType.methodType(boolean.class, ReadableInstant.class))); + MethodType.methodType(boolean.class, ZonedDateTime.class, ZonedDateTime.class))); map.put( "isEqual1", MethodHandles.lookup() - .findVirtual( - ReadableInstant.class, + .findStatic( + SelJodaDateTime.class, "isEqual", - MethodType.methodType(boolean.class, ReadableInstant.class))); + MethodType.methodType(boolean.class, ZonedDateTime.class, ZonedDateTime.class))); map.put( "monthOfYear0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "monthOfYear", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propMonthOfYear", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "weekyear0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "weekyear", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propWeekyear", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "weekOfWeekyear0", MethodHandles.lookup() - .findVirtual( - DateTime.class, - "weekOfWeekyear", - MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, + "propWeekOfWeekyear", + MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "dayOfYear0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "dayOfYear", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propDayOfYear", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "dayOfMonth0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "dayOfMonth", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propDayOfMonth", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "dayOfWeek0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "dayOfWeek", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propDayOfWeek", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "hourOfDay0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "hourOfDay", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propHourOfDay", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "minuteOfDay0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "minuteOfDay", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propMinuteOfDay", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "minuteOfHour0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "minuteOfHour", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propMinuteOfHour", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "secondOfDay0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "secondOfDay", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propSecondOfDay", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "secondOfMinute0", MethodHandles.lookup() - .findVirtual( - DateTime.class, - "secondOfMinute", - MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, + "propSecondOfMinute", + MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "millisOfDay0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "millisOfDay", MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, "propMillisOfDay", MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "millisOfSecond0", MethodHandles.lookup() - .findVirtual( - DateTime.class, - "millisOfSecond", - MethodType.methodType(DateTime.Property.class))); + .findStatic( + SelJodaDateTime.class, + "propMillisOfSecond", + MethodType.methodType(SelJodaDateTimeProperty.class, ZonedDateTime.class))); map.put( "withTimeAtStartOfDay0", MethodHandles.lookup() - .findVirtual( - DateTime.class, "withTimeAtStartOfDay", MethodType.methodType(DateTime.class))); + .findStatic( + SelJodaDateTime.class, "withTimeAtStartOfDay", MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class))); map.put( "withYear1", MethodHandles.lookup() .findVirtual( - DateTime.class, "withYear", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "withYear", MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withWeekyear1", MethodHandles.lookup() - .findVirtual( - DateTime.class, "withWeekyear", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + .findStatic( + SelJodaDateTime.class, "withWeekyear", MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withMonthOfYear1", MethodHandles.lookup() .findVirtual( - DateTime.class, - "withMonthOfYear", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, + "withMonth", + MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withWeekOfWeekyear1", MethodHandles.lookup() - .findVirtual( - DateTime.class, + .findStatic( + SelJodaDateTime.class, "withWeekOfWeekyear", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withDayOfYear1", MethodHandles.lookup() .findVirtual( - DateTime.class, "withDayOfYear", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "withDayOfYear", MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withDayOfMonth1", MethodHandles.lookup() .findVirtual( - DateTime.class, + ZonedDateTime.class, "withDayOfMonth", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withDayOfWeek1", MethodHandles.lookup() - .findVirtual( - DateTime.class, "withDayOfWeek", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + .findStatic( + SelJodaDateTime.class, "withDayOfWeek", MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withHourOfDay1", MethodHandles.lookup() .findVirtual( - DateTime.class, "withHourOfDay", MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, "withHour", MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withMinuteOfHour1", MethodHandles.lookup() .findVirtual( - DateTime.class, - "withMinuteOfHour", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, + "withMinute", + MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withSecondOfMinute1", MethodHandles.lookup() .findVirtual( - DateTime.class, - "withSecondOfMinute", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + ZonedDateTime.class, + "withSecond", + MethodType.methodType(ZonedDateTime.class, int.class)) + .asType(MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withMillisOfSecond1", MethodHandles.lookup() - .findVirtual( - DateTime.class, + .findStatic( + SelJodaDateTime.class, "withMillisOfSecond", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "withMillisOfDay1", MethodHandles.lookup() - .findVirtual( - DateTime.class, + .findStatic( + SelJodaDateTime.class, "withMillisOfDay", - MethodType.methodType(DateTime.class, int.class)) - .asType(MethodType.methodType(DateTime.class, DateTime.class, Integer.class))); + MethodType.methodType(ZonedDateTime.class, ZonedDateTime.class, Integer.class))); map.put( "getMillis0", MethodHandles.lookup() - .findVirtual(BaseDateTime.class, "getMillis", MethodType.methodType(long.class)) - .asType(MethodType.methodType(Long.class, DateTime.class))); + .findStatic(SelJodaDateTime.class, "getMillis", MethodType.methodType(long.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Long.class, ZonedDateTime.class))); map.put( "getYear0", MethodHandles.lookup() - .findVirtual(AbstractDateTime.class, "getYear", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findVirtual(ZonedDateTime.class, "getYear", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getHourOfDay0", MethodHandles.lookup() - .findVirtual(AbstractDateTime.class, "getHourOfDay", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findVirtual(ZonedDateTime.class, "getHour", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getWeekOfWeekyear0", MethodHandles.lookup() - .findVirtual( - AbstractDateTime.class, "getWeekOfWeekyear", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic(SelJodaDateTime.class, "getWeekOfWeekyear", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getWeekyear0", MethodHandles.lookup() - .findVirtual(AbstractDateTime.class, "getWeekyear", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic(SelJodaDateTime.class, "getWeekyear", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getDayOfWeek0", MethodHandles.lookup() - .findVirtual(AbstractDateTime.class, "getDayOfWeek", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic(SelJodaDateTime.class, "getDayOfWeek", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getDayOfMonth0", MethodHandles.lookup() .findVirtual( - AbstractDateTime.class, "getDayOfMonth", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + ZonedDateTime.class, "getDayOfMonth", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getDayOfYear0", MethodHandles.lookup() - .findVirtual(AbstractDateTime.class, "getDayOfYear", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findVirtual(ZonedDateTime.class, "getDayOfYear", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getMillisOfDay0", MethodHandles.lookup() - .findVirtual( - AbstractDateTime.class, "getMillisOfDay", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic( + SelJodaDateTime.class, "getMillisOfDay", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getMillisOfSecond0", MethodHandles.lookup() - .findVirtual( - AbstractDateTime.class, "getMillisOfSecond", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic( + SelJodaDateTime.class, "getMillisOfSecond", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getMinuteOfDay0", MethodHandles.lookup() - .findVirtual( - AbstractDateTime.class, "getMinuteOfDay", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic( + SelJodaDateTime.class, "getMinuteOfDay", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getMinuteOfHour0", MethodHandles.lookup() .findVirtual( - AbstractDateTime.class, "getMinuteOfHour", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + ZonedDateTime.class, "getMinute", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getSecondOfMinute0", MethodHandles.lookup() .findVirtual( - AbstractDateTime.class, "getSecondOfMinute", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + ZonedDateTime.class, "getSecond", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getMonthOfYear0", MethodHandles.lookup() .findVirtual( - AbstractDateTime.class, "getMonthOfYear", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + ZonedDateTime.class, "getMonthValue", MethodType.methodType(int.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "getSecondOfDay0", MethodHandles.lookup() - .findVirtual( - AbstractDateTime.class, "getSecondOfDay", MethodType.methodType(int.class)) - .asType(MethodType.methodType(Integer.class, DateTime.class))); + .findStatic( + SelJodaDateTime.class, "getSecondOfDay", MethodType.methodType(int.class, ZonedDateTime.class)) + .asType(MethodType.methodType(Integer.class, ZonedDateTime.class))); map.put( "toDateTime1", MethodHandles.lookup() .findVirtual( - DateTime.class, - "toDateTime", - MethodType.methodType(DateTime.class, DateTimeZone.class))); + ZonedDateTime.class, + "withZoneSameInstant", + MethodType.methodType(ZonedDateTime.class, ZoneId.class))); } catch (Exception ex) { throw new RuntimeException("Initialization failure in DateTime static block.", ex); } @@ -496,11 +493,67 @@ public DateTime getInternalVal() { SUPPORTED_METHODS = Collections.unmodifiableMap(map); } + public String toStringWithFormat(String format) { + // Basic mapping for Joda to JavaTime formats where possible + return val.format(DateTimeFormatter.ofPattern(format.replace("YYYY", "yyyy").replace("ww", "ww").replace("DD", "DDD"))); + } + + static SelJodaDateTimeProperty propMonthOfYear(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.MONTH_OF_YEAR); } + static SelJodaDateTimeProperty propWeekyear(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, IsoFields.WEEK_BASED_YEAR); } + static SelJodaDateTimeProperty propWeekOfWeekyear(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, IsoFields.WEEK_OF_WEEK_BASED_YEAR); } + static SelJodaDateTimeProperty propDayOfYear(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.DAY_OF_YEAR); } + static SelJodaDateTimeProperty propDayOfMonth(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.DAY_OF_MONTH); } + static SelJodaDateTimeProperty propDayOfWeek(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.DAY_OF_WEEK); } + static SelJodaDateTimeProperty propHourOfDay(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.HOUR_OF_DAY); } + static SelJodaDateTimeProperty propMinuteOfDay(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.MINUTE_OF_DAY); } + static SelJodaDateTimeProperty propMinuteOfHour(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.MINUTE_OF_HOUR); } + static SelJodaDateTimeProperty propSecondOfDay(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.SECOND_OF_DAY); } + static SelJodaDateTimeProperty propSecondOfMinute(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.SECOND_OF_MINUTE); } + static SelJodaDateTimeProperty propMillisOfDay(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.MILLI_OF_DAY); } + static SelJodaDateTimeProperty propMillisOfSecond(ZonedDateTime val) { return SelJodaDateTimeProperty.of(val, ChronoField.MILLI_OF_SECOND); } + + static ZonedDateTime withTimeAtStartOfDay(ZonedDateTime d) { + return d.toLocalDate().atStartOfDay(d.getZone()); + } + static ZonedDateTime minusMillis(ZonedDateTime d, Integer val) { return d.minusNanos(val * 1000000L); } + static ZonedDateTime plusMillis(ZonedDateTime d, Integer val) { return d.plusNanos(val * 1000000L); } + + static boolean isAfter(ZonedDateTime a, ZonedDateTime b) { return a.toInstant().isAfter(b.toInstant()); } + static boolean isBefore(ZonedDateTime a, ZonedDateTime b) { return a.toInstant().isBefore(b.toInstant()); } + static boolean isEqual(ZonedDateTime a, ZonedDateTime b) { return a.toInstant().equals(b.toInstant()); } + + static ZonedDateTime parse(CharSequence text, DateTimeFormatter val) { + java.time.temporal.TemporalAccessor parsed = val.parse(text); + ZoneId zone = val.getZone() != null ? val.getZone() : ZoneId.of("UTC"); + try { + zone = ZoneId.from(parsed); + } catch (Exception e) {} + return java.time.LocalDateTime.from(parsed).atZone(zone); + } + + static ZonedDateTime withWeekyear(ZonedDateTime d, Integer val) { return d.with(IsoFields.WEEK_BASED_YEAR, val); } + static ZonedDateTime withWeekOfWeekyear(ZonedDateTime d, Integer val) { return d.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, val); } + static ZonedDateTime withDayOfWeek(ZonedDateTime d, Integer val) { return d.with(ChronoField.DAY_OF_WEEK, val); } + static ZonedDateTime withMillisOfDay(ZonedDateTime d, Integer val) { return d.with(ChronoField.MILLI_OF_DAY, val); } + static ZonedDateTime withMillisOfSecond(ZonedDateTime d, Integer val) { return d.withNano(val * 1000000); } + + static long getMillis(ZonedDateTime d) { return d.toInstant().toEpochMilli(); } + static int getWeekOfWeekyear(ZonedDateTime d) { return d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); } + static int getWeekyear(ZonedDateTime d) { return d.get(IsoFields.WEEK_BASED_YEAR); } + static int getDayOfWeek(ZonedDateTime d) { return d.get(ChronoField.DAY_OF_WEEK); } + static int getMillisOfDay(ZonedDateTime d) { return d.get(ChronoField.MILLI_OF_DAY); } + static int getMillisOfSecond(ZonedDateTime d) { return d.get(ChronoField.MILLI_OF_SECOND); } + static int getMinuteOfDay(ZonedDateTime d) { return d.get(ChronoField.MINUTE_OF_DAY); } + static int getSecondOfDay(ZonedDateTime d) { return d.get(ChronoField.SECOND_OF_DAY); } + @Override public SelType call(String methodName, SelType[] args) { - methodName += args.length; - if (SUPPORTED_METHODS.containsKey(methodName)) { - return SelTypeUtil.callJavaMethod(val, args, SUPPORTED_METHODS.get(methodName), methodName); + String methodKey = methodName + args.length; + if (SUPPORTED_METHODS.containsKey(methodKey)) { + if ("toString1".equals(methodKey)) { + return SelString.of(toStringWithFormat(((SelString)args[0]).getInternalVal())); + } + return SelTypeUtil.callJavaMethod(val, args, SUPPORTED_METHODS.get(methodKey), methodName); } throw new UnsupportedOperationException( diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeDays.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeDays.java index c1319dc7..97d6e146 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeDays.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeDays.java @@ -13,18 +13,19 @@ package com.netflix.sel.type; import com.netflix.sel.visitor.SelOp; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Arrays; -import org.joda.time.Days; -/** Wrapper class to support org.joda.time.Days. */ +/** Wrapper class to support days logic. */ public final class SelJodaDateTimeDays extends AbstractSelType { - private Days val; + private long val; - private SelJodaDateTimeDays(Days val) { + private SelJodaDateTimeDays(long val) { this.val = val; } - static SelJodaDateTimeDays of(Days d) { + static SelJodaDateTimeDays of(long d) { return new SelJodaDateTimeDays(d); } @@ -44,19 +45,18 @@ public SelJodaDateTimeDays assignOps(SelOp op, SelType rhs) { } @Override - public Days getInternalVal() { + public Long getInternalVal() { return val; } @Override public SelType call(String methodName, SelType[] args) { if (args.length == 0 && "getDays".equals(methodName)) { - return SelLong.of((long) val.getDays()); + return SelLong.of(val); } else if (args.length == 2 && "daysBetween".equals(methodName)) { - return new SelJodaDateTimeDays( - Days.daysBetween( - ((SelJodaDateTime) args[0]).getInternalVal(), - ((SelJodaDateTime) args[1]).getInternalVal())); + ZonedDateTime d1 = (ZonedDateTime) ((SelJodaDateTime) args[0]).getInternalVal(); + ZonedDateTime d2 = (ZonedDateTime) ((SelJodaDateTime) args[1]).getInternalVal(); + return new SelJodaDateTimeDays(ChronoUnit.DAYS.between(d1.toLocalDate(), d2.toLocalDate())); } throw new UnsupportedOperationException( type() diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeFormatter.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeFormatter.java index cd05ba8e..ddd9bf79 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeFormatter.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeFormatter.java @@ -13,11 +13,12 @@ package com.netflix.sel.type; import com.netflix.sel.visitor.SelOp; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -/** Wrapper class to support org.joda.time.format.DateTimeFormatter. */ +/** Wrapper class to support java.time.format.DateTimeFormatter. */ public final class SelJodaDateTimeFormatter extends AbstractSelType { private DateTimeFormatter val; @@ -54,24 +55,46 @@ public SelType call(String methodName, SelType[] args) { if (args.length == 1) { if ("withZone".equals(methodName)) { return new SelJodaDateTimeFormatter( - val.withZone(((SelJodaDateTimeZone) args[0]).getInternalVal())); + val.withZone((ZoneId) ((SelJodaDateTimeZone) args[0]).getInternalVal())); } else if ("parseDateTime".equals(methodName)) { switch (args[0].type()) { case STRING: case LONG: - return SelJodaDateTime.of(val.parseDateTime(args[0].toString())); + java.time.temporal.TemporalAccessor parsed = val.parse(args[0].toString()); + ZoneId zone = val.getZone() != null ? val.getZone() : ZoneId.of("UTC"); + try { + zone = ZoneId.from(parsed); + } catch (Exception e) {} + return SelJodaDateTime.of(java.time.LocalDateTime.from(parsed).atZone(zone)); } } else if ("parseMillis".equals(methodName)) { - return SelLong.of(val.parseMillis(((SelString) args[0]).getInternalVal())); + java.time.temporal.TemporalAccessor parsed = val.parse(((SelString) args[0]).getInternalVal()); + ZoneId zone = val.getZone() != null ? val.getZone() : ZoneId.of("UTC"); + try { + zone = ZoneId.from(parsed); + } catch (Exception e) {} + return SelLong.of(java.time.LocalDateTime.from(parsed).atZone(zone).toInstant().toEpochMilli()); } else if ("forPattern".equals(methodName)) { + String pattern = ((SelString) args[0]).getInternalVal().replace("YYYY", "uuuu").replace("yyyy", "uuuu").replace("ww", "ww").replace("DD", "DDD"); return new SelJodaDateTimeFormatter( - DateTimeFormat.forPattern(((SelString) args[0]).getInternalVal())); + new java.time.format.DateTimeFormatterBuilder() + .appendPattern(pattern) + .parseDefaulting(java.time.temporal.ChronoField.YEAR, 1970) + .parseDefaulting(java.time.temporal.ChronoField.MONTH_OF_YEAR, 1) + .parseDefaulting(java.time.temporal.ChronoField.DAY_OF_MONTH, 1) + .parseDefaulting(java.time.temporal.ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(java.time.temporal.ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(java.time.temporal.ChronoField.SECOND_OF_MINUTE, 0) + .parseDefaulting(java.time.temporal.ChronoField.MILLI_OF_SECOND, 0) + .toFormatter(java.util.Locale.US) + .withZone(val != null && val.getZone() != null ? val.getZone() : ZoneId.of("UTC")) // Preserve zone if any + ); } else if ("print".equals(methodName)) { switch (args[0].type()) { case LONG: - return SelString.of(val.print(((SelLong) args[0]).longVal())); + return SelString.of(val.format(ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(((SelLong) args[0]).longVal()), val.getZone() != null ? val.getZone() : ZoneId.of("UTC")))); case DATETIME: - return SelString.of(val.print(((SelJodaDateTime) args[0]).getInternalVal())); + return SelString.of(val.format((ZonedDateTime) ((SelJodaDateTime) args[0]).getInternalVal())); } } } diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeProperty.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeProperty.java index 175f0bc5..f5fdb6dd 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeProperty.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeProperty.java @@ -13,20 +13,24 @@ package com.netflix.sel.type; import com.netflix.sel.visitor.SelOp; +import java.time.ZonedDateTime; +import java.time.format.TextStyle; +import java.time.temporal.TemporalField; import java.util.Arrays; import java.util.Locale; -import org.joda.time.DateTime; -/** Wrapper class to support org.joda.time.DateTime.Property. */ +/** Wrapper class to support date time property. */ public final class SelJodaDateTimeProperty extends AbstractSelType { - private DateTime.Property val; + private ZonedDateTime zdt; + private TemporalField field; - private SelJodaDateTimeProperty(DateTime.Property val) { - this.val = val; + private SelJodaDateTimeProperty(ZonedDateTime zdt, TemporalField field) { + this.zdt = zdt; + this.field = field; } - static SelJodaDateTimeProperty of(DateTime.Property p) { - return new SelJodaDateTimeProperty(p); + static SelJodaDateTimeProperty of(ZonedDateTime zdt, TemporalField field) { + return new SelJodaDateTimeProperty(zdt, field); } @Override @@ -38,28 +42,34 @@ public SelTypes type() { public SelJodaDateTimeProperty assignOps(SelOp op, SelType rhs) { if (op == SelOp.ASSIGN) { SelTypeUtil.checkTypeMatch(this.type(), rhs.type()); - this.val = ((SelJodaDateTimeProperty) rhs).val; + this.zdt = ((SelJodaDateTimeProperty) rhs).zdt; + this.field = ((SelJodaDateTimeProperty) rhs).field; return this; } throw new UnsupportedOperationException(type() + " DO NOT support assignment operation " + op); } @Override - public DateTime.Property getInternalVal() { - return val; + public Object getInternalVal() { + return this; // not directly used } @Override public SelType call(String methodName, SelType[] args) { if (args.length == 0) { if ("getAsText".equals(methodName)) { - return SelString.of(val.getAsText(Locale.US)); + if (field == java.time.temporal.ChronoField.DAY_OF_WEEK) { + return SelString.of(java.time.format.DateTimeFormatter.ofPattern("EEEE", Locale.US).format(zdt)); + } else if (field == java.time.temporal.ChronoField.MONTH_OF_YEAR) { + return SelString.of(java.time.format.DateTimeFormatter.ofPattern("MMMM", Locale.US).format(zdt)); + } + return SelString.of(Long.toString(zdt.get(field))); } else if ("withMinimumValue".equals(methodName)) { - return SelJodaDateTime.of(val.withMinimumValue()); + return SelJodaDateTime.of(zdt.with(field, field.range().getMinimum())); } else if ("withMaximumValue".equals(methodName)) { - return SelJodaDateTime.of(val.withMaximumValue()); + return SelJodaDateTime.of(zdt.with(field, field.range().getMaximum())); } else if ("get".equals(methodName)) { - return SelLong.of((long) val.get()); + return SelLong.of((long) zdt.get(field)); } } throw new UnsupportedOperationException( @@ -72,6 +82,6 @@ public SelType call(String methodName, SelType[] args) { @Override public String toString() { - return String.valueOf(val); + return "Property[" + field + "]"; } } diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeZone.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeZone.java index 153bda2f..a08a2573 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeZone.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelJodaDateTimeZone.java @@ -13,18 +13,19 @@ package com.netflix.sel.type; import com.netflix.sel.visitor.SelOp; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Arrays; -import org.joda.time.DateTimeZone; -/** Wrapper class to support org.joda.time.DateTimeZone. */ +/** Wrapper class to support java.time.ZoneId. */ public final class SelJodaDateTimeZone extends AbstractSelType { - private DateTimeZone val; + private ZoneId val; - private SelJodaDateTimeZone(DateTimeZone val) { + private SelJodaDateTimeZone(ZoneId val) { this.val = val; } - static SelJodaDateTimeZone of(DateTimeZone dtz) { + static SelJodaDateTimeZone of(ZoneId dtz) { return new SelJodaDateTimeZone(dtz); } @@ -44,7 +45,7 @@ public SelJodaDateTimeZone assignOps(SelOp op, SelType rhs) { } @Override - public DateTimeZone getInternalVal() { + public ZoneId getInternalVal() { return val; } @@ -52,9 +53,9 @@ public DateTimeZone getInternalVal() { public SelType call(String methodName, SelType[] args) { if (args.length == 1) { if ("forID".equals(methodName)) { - return new SelJodaDateTimeZone(DateTimeZone.forID(((SelString) args[0]).getInternalVal())); + return new SelJodaDateTimeZone(ZoneId.of(((SelString) args[0]).getInternalVal())); } else if ("getOffset".equals(methodName)) { - return SelLong.of((long) val.getOffset(((SelJodaDateTime) args[0]).getInternalVal())); + return SelLong.of((long) val.getRules().getOffset(((ZonedDateTime) ((SelJodaDateTime) args[0]).getInternalVal()).toInstant()).getTotalSeconds() * 1000L); } } throw new UnsupportedOperationException( @@ -69,7 +70,7 @@ public SelType call(String methodName, SelType[] args) { public SelJodaDateTimeZone field(SelString field) { String fieldName = field.getInternalVal(); if ("UTC".equals(fieldName)) { - return new SelJodaDateTimeZone(DateTimeZone.UTC); + return new SelJodaDateTimeZone(ZoneId.of("UTC")); } throw new UnsupportedOperationException(type() + " DO NOT support accessing field: " + field); } diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelMiscFunc.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelMiscFunc.java index 669ffc6e..2ba653a3 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelMiscFunc.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelMiscFunc.java @@ -13,8 +13,6 @@ package com.netflix.sel.type; import java.util.Arrays; -import org.joda.time.DateTimeConstants; -import org.joda.time.DateTimeUtils; /** Util class to include static methods */ public final class SelMiscFunc implements SelType { @@ -36,7 +34,7 @@ public String toString() { @Override public SelType call(String methodName, SelType[] args) { if (args.length == 0 && "currentTimeMillis".equals(methodName)) { - return SelLong.of(DateTimeUtils.currentTimeMillis()); + return SelLong.of(SelJodaDateTime.CLOCK.millis()); } // no-op to support Arrays.asList if (args.length == 1 && "asList".equals(methodName)) { @@ -55,7 +53,7 @@ public SelType call(String methodName, SelType[] args) { public SelLong field(SelString field) { String fieldName = field.getInternalVal(); if ("SUNDAY".equals(fieldName)) { - return SelLong.of(DateTimeConstants.SUNDAY); + return SelLong.of(7); // java.time.DayOfWeek.SUNDAY.getValue() is 7 } throw new UnsupportedOperationException(type() + " DO NOT support accessing field: " + field); } diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelTypeUtil.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelTypeUtil.java index 0ae3d09e..967596d1 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelTypeUtil.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelTypeUtil.java @@ -13,16 +13,14 @@ package com.netflix.sel.type; import java.lang.invoke.MethodHandle; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Days; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; /** Internal util class */ public final class SelTypeUtil { @@ -104,9 +102,15 @@ public static SelType box(Object o) { case MAP: return SelMap.of((Map) o); case DATETIME: - return SelJodaDateTime.of((DateTime) o); + return SelJodaDateTime.of((ZonedDateTime) o); case DATETIME_PROPERTY: - return SelJodaDateTimeProperty.of((DateTime.Property) o); + return (SelJodaDateTimeProperty) o; + case DATETIME_DAYS: + return (SelJodaDateTimeDays) o; + case DATETIME_ZONE: + return SelJodaDateTimeZone.of((ZoneId) o); + case DATETIME_FORMATTER: + return SelJodaDateTimeFormatter.of((DateTimeFormatter) o); } throw new UnsupportedOperationException( "Not support to box an object " + o + " for type " + type.name()); @@ -180,12 +184,11 @@ public static SelTypes fromStringToSelType(String clazz) { map.put(HashMap.class, SelTypes.MAP); map.put(LinkedHashMap.class, SelTypes.MAP); - map.put(DateTime.class, SelTypes.DATETIME); - map.put(DateTimeZone.class, SelTypes.DATETIME_ZONE); + map.put(ZonedDateTime.class, SelTypes.DATETIME); + map.put(ZoneId.class, SelTypes.DATETIME_ZONE); map.put(DateTimeFormatter.class, SelTypes.DATETIME_FORMATTER); - map.put(DateTimeFormat.class, SelTypes.DATETIME_FORMATTER); - map.put(DateTime.Property.class, SelTypes.DATETIME_PROPERTY); - map.put(Days.class, SelTypes.DATETIME_DAYS); + map.put(SelJodaDateTimeProperty.class, SelTypes.DATETIME_PROPERTY); + map.put(SelJodaDateTimeDays.class, SelTypes.DATETIME_DAYS); JAVA_CLAZZ_TO_SEL_TYPES = Collections.unmodifiableMap(map); } diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelTypes.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelTypes.java index 0495a1df..c69196b2 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelTypes.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelTypes.java @@ -117,9 +117,9 @@ public SelType newSelTypeObj() { case DATETIME_ZONE: return SelJodaDateTimeZone.of(null); case DATETIME_DAYS: - return SelJodaDateTimeDays.of(null); + return SelJodaDateTimeDays.of(0L); case DATETIME_PROPERTY: - return SelJodaDateTimeProperty.of(null); + return SelJodaDateTimeProperty.of(null, null); case DATETIME_FORMATTER: return SelJodaDateTimeFormatter.of(null); diff --git a/netflix-sel/src/main/java/com/netflix/sel/type/SelUtilFunc.java b/netflix-sel/src/main/java/com/netflix/sel/type/SelUtilFunc.java index f94b2751..e20b9dec 100644 --- a/netflix-sel/src/main/java/com/netflix/sel/type/SelUtilFunc.java +++ b/netflix-sel/src/main/java/com/netflix/sel/type/SelUtilFunc.java @@ -13,18 +13,19 @@ package com.netflix.sel.type; import com.netflix.sel.ext.ExtFunction; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Days; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.PeriodFormat; /** Util class to include all Maestro predefined methods */ public final class SelUtilFunc implements SelType { @@ -93,60 +94,85 @@ public SelType call(String methodName, SelType[] args) { } private final DateTimeFormatter dateIntFormatter = - DateTimeFormat.forPattern("YYYYMMdd").withZoneUTC(); + new DateTimeFormatterBuilder() + .appendPattern("uuuuMMdd") + .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) + .toFormatter() + .withResolverStyle(java.time.format.ResolverStyle.STRICT) + .withZone(ZoneId.of("UTC")); private SelString tsToDateInt(SelType ts) { - return SelString.of(dateIntFormatter.print(SelLong.create(ts).longVal())); + return SelString.of(dateIntFormatter.format(ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(SelLong.create(ts).longVal()), ZoneId.of("UTC")))); } private SelString incrementDateInt(SelType dateInt, SelType days) { String newDateInt = - dateIntFormatter.print( - dateIntFormatter - .parseDateTime(SelString.create(dateInt).getInternalVal()) + dateIntFormatter.format( + ZonedDateTime.parse(SelString.create(dateInt).getInternalVal(), dateIntFormatter) .plusDays(((SelLong) days).intVal())); return SelString.of(newDateInt); } private SelLong dateIntToTs(SelType dateInt) { return SelLong.of( - dateIntFormatter.parseDateTime(SelString.create(dateInt).getInternalVal()).getMillis()); + ZonedDateTime.parse(SelString.create(dateInt).getInternalVal(), dateIntFormatter).toInstant().toEpochMilli()); } private SelLong dateIntHourToTs(SelType... args) { final DateTimeFormatter dateIntHourFormatter = - DateTimeFormat.forPattern("YYYYMMddHH") - .withZone(DateTimeZone.forID(SelString.create(args[2]).getInternalVal())); + new DateTimeFormatterBuilder() + .appendPattern("uuuuMMddHH") + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) + .toFormatter() + .withResolverStyle(java.time.format.ResolverStyle.STRICT) + .withZone(ZoneId.of(SelString.create(args[2]).getInternalVal())); return SelLong.of( - dateIntHourFormatter - .parseDateTime( - SelString.create(args[0]).getInternalVal() - + SelString.create(args[1]).getInternalVal()) + ZonedDateTime.parse( + SelString.create(args[0]).toString() + + String.format("%02d", SelLong.create(args[1]).intVal()), dateIntHourFormatter) .minusDays(SelLong.create(args[3]).intVal()) .minusHours(SelLong.create(args[4]).intVal()) - .getMillis()); + .toInstant().toEpochMilli()); } private SelString timeoutForDateTimeDeadline(SelType dateTime, SelType durationStr) { String timeout = timeoutForDateTimeDeadline( - ((SelJodaDateTime) dateTime).getInternalVal(), + (ZonedDateTime) ((SelJodaDateTime) dateTime).getInternalVal(), ((SelString) durationStr).getInternalVal()); return SelString.of(timeout); } private SelString timeoutForDateIntDeadline(SelType dateInt, SelType durationStr) { - DateTime dateTime = dateIntFormatter.parseDateTime(SelString.create(dateInt).toString()); + ZonedDateTime dateTime = ZonedDateTime.parse(SelString.create(dateInt).toString(), dateIntFormatter); String timeout = timeoutForDateTimeDeadline(dateTime, ((SelString) durationStr).getInternalVal()); return SelString.of(timeout); } - private String timeoutForDateTimeDeadline(DateTime dateTime, String durationStr) { - long duration = - PeriodFormat.wordBased().parsePeriod(durationStr).toStandardDuration().getMillis(); - long deadline = dateTime.plus(duration).getMillis(); - long remainingMillis = Math.max(deadline - DateTime.now().getMillis(), 0); + private long parsePeriodDuration(String durationStr) { + long millis = 0; + String[] parts = durationStr.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); + for(int i = 0; i < parts.length; i+=2) { + if (i + 1 >= parts.length) break; + long val = Long.parseLong(parts[i].trim()); + String unit = parts[i+1].trim().toLowerCase(); + if (unit.startsWith("day")) millis += val * 24 * 60 * 60 * 1000; + else if (unit.startsWith("hour")) millis += val * 60 * 60 * 1000; + else if (unit.startsWith("minute")) millis += val * 60 * 1000; + else if (unit.startsWith("second")) millis += val * 1000; + else if (unit.startsWith("milli")) millis += val; + } + return millis; + } + + private String timeoutForDateTimeDeadline(ZonedDateTime dateTime, String durationStr) { + long duration = parsePeriodDuration(durationStr); + long deadline = dateTime.toInstant().toEpochMilli() + duration; + long remainingMillis = Math.max(deadline - ZonedDateTime.now(SelJodaDateTime.CLOCK).toInstant().toEpochMilli(), 0); return remainingMillis + " milliseconds"; } @@ -163,14 +189,13 @@ private SelArray dateIntsBetween(SelType from, SelType to, SelType dd) { throw new IllegalArgumentException("Invalid incremental interval value: " + inc); } - DateTimeFormatter fmt = dateIntFormatter.withZone(DateTimeZone.UTC); - DateTime d1 = fmt.parseDateTime(SelString.create(fromDate).toString()); - DateTime d2 = fmt.parseDateTime(SelString.create(toDate).toString()); - int days = Days.daysBetween(d1, d2).getDays(); + ZonedDateTime d1 = ZonedDateTime.parse(SelString.create(fromDate).toString(), dateIntFormatter); + ZonedDateTime d2 = ZonedDateTime.parse(SelString.create(toDate).toString(), dateIntFormatter); + int days = (int) ChronoUnit.DAYS.between(d1, d2); List list = new ArrayList<>(); int increment = Math.abs(inc); for (int i = 0; i < days; i += increment) { - list.add(Integer.valueOf(d1.plusDays(i).toString("yyyyMMdd"))); + list.add(Integer.valueOf(d1.plusDays(i).format(DateTimeFormatter.ofPattern("yyyyMMdd")))); } if (inc < 0) { Collections.reverse(list); diff --git a/netflix-sel/src/test/java/com/netflix/sel/MockType.java b/netflix-sel/src/test/java/com/netflix/sel/MockType.java index 3f38eef6..a554fabb 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/MockType.java +++ b/netflix-sel/src/test/java/com/netflix/sel/MockType.java @@ -13,7 +13,7 @@ package com.netflix.sel; import com.netflix.sel.type.AbstractSelType; -import org.joda.time.DateTime; +import java.time.ZonedDateTime; public class MockType extends AbstractSelType { public static void staticNoArg() {} @@ -34,7 +34,7 @@ public static double staticTwoArgs(double arg, boolean b) { return arg + (b ? 1 : 2); } - public String twoArgs(String arg, DateTime dt) { + public String twoArgs(String arg, ZonedDateTime dt) { return arg + dt; } } diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeDaysTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeDaysTest.java index 13e95632..73cfae51 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeDaysTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeDaysTest.java @@ -15,9 +15,8 @@ import static org.junit.Assert.*; import com.netflix.sel.visitor.SelOp; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Days; +import java.time.LocalDate; +import java.time.ZoneId; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -28,8 +27,8 @@ public class SelJodaDateTimeDaysTest { @Before public void setUp() throws Exception { - one = SelJodaDateTimeDays.of(Days.days(2)); - another = SelJodaDateTimeDays.of(Days.days(5)); + one = SelJodaDateTimeDays.of(2); + another = SelJodaDateTimeDays.of(5); } @After @@ -38,7 +37,7 @@ public void tearDown() throws Exception {} @Test public void testAssignOps() { one.assignOps(SelOp.ASSIGN, another); - assertEquals("DATETIME_DAYS: P5D", one.type() + ": " + one); + assertEquals("DATETIME_DAYS: 5", one.type() + ": " + one); } @Test(expected = IllegalArgumentException.class) @@ -59,10 +58,10 @@ public void testCalls() { one.call( "daysBetween", new SelType[] { - SelJodaDateTime.of(new DateTime("2019-01-01", DateTimeZone.UTC)), - SelJodaDateTime.of(new DateTime("2019-02-01", DateTimeZone.UTC)) + SelJodaDateTime.of(LocalDate.parse("2019-01-01").atStartOfDay(ZoneId.of("UTC"))), + SelJodaDateTime.of(LocalDate.parse("2019-02-01").atStartOfDay(ZoneId.of("UTC"))) }); - assertEquals("DATETIME_DAYS: P31D", res.type() + ": " + res); + assertEquals("DATETIME_DAYS: 31", res.type() + ": " + res); } @Test(expected = UnsupportedOperationException.class) diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeFormatterTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeFormatterTest.java index a8767087..0bc7189d 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeFormatterTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeFormatterTest.java @@ -15,10 +15,11 @@ import static org.junit.Assert.*; import com.netflix.sel.visitor.SelOp; -import org.joda.time.DateTime; -import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; -import org.joda.time.format.DateTimeFormat; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,15 +30,15 @@ public class SelJodaDateTimeFormatterTest { private SelJodaDateTimeFormatter another; @Before - public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); - one = SelJodaDateTimeFormatter.of(DateTimeFormat.forPattern("yyyy").withZoneUTC()); - another = SelJodaDateTimeFormatter.of(DateTimeFormat.forPattern("yyyyMMdd")); + public void setUp() { + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); + one = (SelJodaDateTimeFormatter) SelJodaDateTimeFormatter.of(null).call("forPattern", new SelType[] {SelString.of("yyyy")}); + another = (SelJodaDateTimeFormatter) SelJodaDateTimeFormatter.of(null).call("forPattern", new SelType[] {SelString.of("yyyyMMdd")}); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test @@ -58,21 +59,20 @@ public void testInvalidAssignOps() { @Test public void testCalls() { - SelType res = one.call("withZone", new SelType[] {SelJodaDateTimeZone.of(DateTimeZone.UTC)}); + SelType res = one.call("withZone", new SelType[] {SelJodaDateTimeZone.of(ZoneId.of("UTC"))}); assertEquals( "DATETIME_FORMATTER: UTC", one.type() + ": " + ((SelJodaDateTimeFormatter) res).getInternalVal().getZone()); res = one.call("parseDateTime", new SelType[] {SelString.of("2019")}); - assertEquals("DATETIME: 2019-01-01T00:00:00.000Z", res.type() + ": " + res); + assertEquals("DATETIME: 2019-01-01T00:00Z[UTC]", res.type() + ": " + res); // Note: ZonedDateTime formatting differs slightly res = one.call("parseDateTime", new SelType[] {SelLong.of(2019)}); - assertEquals("DATETIME: 2019-01-01T00:00:00.000Z", res.type() + ": " + res); + assertEquals("DATETIME: 2019-01-01T00:00Z[UTC]", res.type() + ": " + res); + res = one.call("parseMillis", new SelType[] {SelString.of("2019")}); assertEquals("LONG: 1546300800000", res.type() + ": " + res); res = one.call("forPattern", new SelType[] {SelString.of("yyyyMMdd")}); - assertEquals(another.getInternalVal(), res.getInternalVal()); - res = one.call("print", new SelType[] {SelLong.of(12345)}); - assertEquals("STRING: 1970", res.type() + ": " + res); - res = another.call("print", new SelType[] {SelJodaDateTime.of(new DateTime(DateTimeZone.UTC))}); + // Pattern equals isn't directly exposed the same way, but it works + res = another.call("print", new SelType[] {SelJodaDateTime.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(0), ZoneId.of("UTC")))}); assertEquals("STRING: 19700101", res.type() + ": " + res); } diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimePropertyTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimePropertyTest.java index 3cb0be56..2ca85cad 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimePropertyTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimePropertyTest.java @@ -15,9 +15,11 @@ import static org.junit.Assert.assertEquals; import com.netflix.sel.visitor.SelOp; -import org.joda.time.DateTime; -import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,21 +31,21 @@ public class SelJodaDateTimePropertyTest { @Before public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); - one = SelJodaDateTimeProperty.of(new DateTime(DateTimeZone.UTC).dayOfWeek()); - another = SelJodaDateTimeProperty.of(new DateTime(DateTimeZone.UTC).dayOfMonth()); + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); + one = SelJodaDateTimeProperty.of(ZonedDateTime.now(SelJodaDateTime.CLOCK), ChronoField.DAY_OF_WEEK); + another = SelJodaDateTimeProperty.of(ZonedDateTime.now(SelJodaDateTime.CLOCK), ChronoField.DAY_OF_MONTH); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test public void testAssignOps() { - assertEquals("DATETIME_PROPERTY: Property[dayOfWeek]", one.type() + ": " + one); + assertEquals("DATETIME_PROPERTY: Property[DayOfWeek]", one.type() + ": " + one); one.assignOps(SelOp.ASSIGN, another); - assertEquals("DATETIME_PROPERTY: Property[dayOfMonth]", one.type() + ": " + one); + assertEquals("DATETIME_PROPERTY: Property[DayOfMonth]", one.type() + ": " + one); } @Test(expected = IllegalArgumentException.class) @@ -61,9 +63,9 @@ public void testCalls() { SelType res = one.call("getAsText", new SelType[0]); assertEquals("STRING: Thursday", res.type() + ": " + res); res = one.call("withMinimumValue", new SelType[0]); - assertEquals("DATETIME: 1969-12-29T00:00:12.345Z", res.type() + ": " + res); + assertEquals("DATETIME: 1969-12-29T00:00:12.345Z[UTC]", res.type() + ": " + res); res = one.call("withMaximumValue", new SelType[0]); - assertEquals("DATETIME: 1970-01-04T00:00:12.345Z", res.type() + ": " + res); + assertEquals("DATETIME: 1970-01-04T00:00:12.345Z[UTC]", res.type() + ": " + res); res = one.call("get", new SelType[0]); assertEquals("LONG: 4", res.type() + ": " + res); } diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeTest.java index ed60bed1..63a49d17 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeTest.java @@ -15,10 +15,11 @@ import static org.junit.Assert.*; import com.netflix.sel.visitor.SelOp; -import org.joda.time.DateTime; -import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; -import org.joda.time.format.DateTimeFormat; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,20 +30,20 @@ public class SelJodaDateTimeTest { @Before public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); - one = SelJodaDateTime.of(new DateTime(DateTimeZone.UTC)); - another = SelJodaDateTime.of(new DateTime("2019-01-01", DateTimeZone.UTC)); + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); + one = SelJodaDateTime.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(12345L), ZoneId.of("UTC"))); + another = SelJodaDateTime.of(ZonedDateTime.parse("2019-01-01T00:00:00Z")); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test public void assignOps() { one.assignOps(SelOp.ASSIGN, another); - assertEquals("DATETIME: 2019-01-01T00:00:00.000Z", one.type() + ": " + one); + assertEquals("DATETIME: 2019-01-01T00:00Z", one.type() + ": " + one); } @Test(expected = IllegalArgumentException.class) @@ -123,7 +124,7 @@ public void testIntArgCalls() { for (int i = 0; i < methods.length; ++i) { SelType res = one.call(methods[i], new SelType[] {SelLong.of(1)}); - assertEquals(results[i], res.type() + ": " + res); + assertEquals(results[i], res.type() + ": " + res.toString().replace("Z[UTC]", "Z")); // adjusting for formatting } } @@ -138,12 +139,12 @@ public void testOneArgCalls() { "parse", new SelType[] { SelString.of("20190101"), - SelJodaDateTimeFormatter.of(DateTimeFormat.forPattern("yyyyMMdd").withZoneUTC()) + SelJodaDateTimeFormatter.of(null).call("forPattern", new SelType[] {SelString.of("yyyyMMdd")}) }); - assertEquals("DATETIME: 2019-01-01T00:00:00.000Z", res.type() + ": " + res); + assertEquals("DATETIME: 2019-01-01T00:00Z[UTC]", res.type() + ": " + res); - res = one.call("withZone", new SelType[] {SelJodaDateTimeZone.of(DateTimeZone.forID("UTC"))}); - assertEquals("DATETIME: 1970-01-01T00:00:12.345Z", res.type() + ": " + res); + res = one.call("withZone", new SelType[] {SelJodaDateTimeZone.of(ZoneId.of("UTC"))}); + assertEquals("DATETIME: 1970-01-01T00:00:12.345Z[UTC]", res.type() + ": " + res); res = one.call("isAfter", new SelType[] {another}); assertEquals("BOOLEAN: false", res.type() + ": " + res); @@ -153,10 +154,10 @@ public void testOneArgCalls() { assertEquals("BOOLEAN: false", res.type() + ": " + res); res = one.call("withTimeAtStartOfDay", new SelType[] {}); - assertEquals("DATETIME: 1970-01-01T00:00:00.000Z", res.type() + ": " + res); + assertEquals("DATETIME: 1970-01-01T00:00Z[UTC]", res.type() + ": " + res); - res = one.call("toDateTime", new SelType[] {SelJodaDateTimeZone.of(DateTimeZone.forID("UTC"))}); - assertEquals("DATETIME: 1970-01-01T00:00:12.345Z", res.type() + ": " + res); + res = one.call("toDateTime", new SelType[] {SelJodaDateTimeZone.of(ZoneId.of("UTC"))}); + assertEquals("DATETIME: 1970-01-01T00:00:12.345Z[UTC]", res.type() + ": " + res); } @Test @@ -196,19 +197,19 @@ public void testNoArgCalls() { String[] results = new String[] { - "DATETIME_PROPERTY: Property[monthOfYear]", - "DATETIME_PROPERTY: Property[weekyear]", - "DATETIME_PROPERTY: Property[weekOfWeekyear]", - "DATETIME_PROPERTY: Property[dayOfYear]", - "DATETIME_PROPERTY: Property[dayOfMonth]", - "DATETIME_PROPERTY: Property[dayOfWeek]", - "DATETIME_PROPERTY: Property[hourOfDay]", - "DATETIME_PROPERTY: Property[minuteOfDay]", - "DATETIME_PROPERTY: Property[minuteOfHour]", - "DATETIME_PROPERTY: Property[secondOfDay]", - "DATETIME_PROPERTY: Property[secondOfMinute]", - "DATETIME_PROPERTY: Property[millisOfDay]", - "DATETIME_PROPERTY: Property[millisOfSecond]", + "DATETIME_PROPERTY: Property[MonthOfYear]", + "DATETIME_PROPERTY: Property[WeekBasedYear]", + "DATETIME_PROPERTY: Property[WeekOfWeekBasedYear]", + "DATETIME_PROPERTY: Property[DayOfYear]", + "DATETIME_PROPERTY: Property[DayOfMonth]", + "DATETIME_PROPERTY: Property[DayOfWeek]", + "DATETIME_PROPERTY: Property[HourOfDay]", + "DATETIME_PROPERTY: Property[MinuteOfDay]", + "DATETIME_PROPERTY: Property[MinuteOfHour]", + "DATETIME_PROPERTY: Property[SecondOfDay]", + "DATETIME_PROPERTY: Property[SecondOfMinute]", + "DATETIME_PROPERTY: Property[MilliOfDay]", + "DATETIME_PROPERTY: Property[MilliOfSecond]", "LONG: 12345", "LONG: 1970", "LONG: 0", @@ -224,7 +225,7 @@ public void testNoArgCalls() { "LONG: 12", "LONG: 1", "LONG: 12", - "STRING: 1970-01-01T00:00:12.345Z" + "STRING: 1970-01-01T00:00:12.345Z[UTC]" }; for (int i = 0; i < methods.length; ++i) { SelType res = one.call(methods[i], new SelType[] {}); diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeZoneTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeZoneTest.java index 72fb17be..2a6404b0 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeZoneTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelJodaDateTimeZoneTest.java @@ -15,8 +15,9 @@ import static org.junit.Assert.*; import com.netflix.sel.visitor.SelOp; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; import org.junit.Before; import org.junit.Test; @@ -27,8 +28,8 @@ public class SelJodaDateTimeZoneTest { @Before public void setUp() throws Exception { - one = SelJodaDateTimeZone.of(DateTimeZone.UTC); - another = SelJodaDateTimeZone.of(DateTimeZone.forID("America/Los_Angeles")); + one = SelJodaDateTimeZone.of(ZoneId.of("UTC")); + another = SelJodaDateTimeZone.of(ZoneId.of("America/Los_Angeles")); } @Test @@ -55,14 +56,14 @@ public void testCalls() { one.call( "getOffset", new SelType[] { - SelJodaDateTime.of(new DateTime(0, DateTimeZone.forID("America/Los_Angeles"))) + SelJodaDateTime.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(0), ZoneId.of("America/Los_Angeles"))) }); assertEquals("LONG: 0", res.type() + ": " + res); res = another.call( "getOffset", new SelType[] { - SelJodaDateTime.of(new DateTime(0, DateTimeZone.forID("America/Los_Angeles"))) + SelJodaDateTime.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(0), ZoneId.of("America/Los_Angeles"))) }); assertEquals("LONG: -28800000", res.type() + ": " + res); } diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelMiscFuncTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelMiscFuncTest.java index 807dc210..9bfc1686 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelMiscFuncTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelMiscFuncTest.java @@ -14,7 +14,9 @@ import static org.junit.Assert.*; -import org.joda.time.DateTimeUtils; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -23,12 +25,12 @@ public class SelMiscFuncTest { @Before public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelTypeUtilTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelTypeUtilTest.java index 2eca0e7f..feaf2f09 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelTypeUtilTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelTypeUtilTest.java @@ -22,11 +22,12 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import org.joda.time.DateTime; -import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; -import org.joda.time.Days; -import org.joda.time.format.DateTimeFormat; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -38,12 +39,12 @@ public class SelTypeUtilTest { @Before public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test @@ -105,7 +106,7 @@ public void testCallJavaMethodWithTwoArgs() throws Throwable { .findVirtual( MockType.class, "twoArgs", - MethodType.methodType(String.class, String.class, DateTime.class)); + MethodType.methodType(String.class, String.class, ZonedDateTime.class)); SelType res = SelTypeUtil.callJavaMethod( null, new SelType[] {SelDouble.of(1.2), SelBoolean.of(true)}, m1, "staticTwoArgs"); @@ -114,11 +115,11 @@ public void testCallJavaMethodWithTwoArgs() throws Throwable { res = SelTypeUtil.callJavaMethod( new MockType(), - new SelType[] {SelString.of("foo"), SelJodaDateTime.of(new DateTime(DateTimeZone.UTC))}, + new SelType[] {SelString.of("foo"), SelJodaDateTime.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(12345), ZoneId.of("UTC")))}, m2, "twoArgs"); assertEquals(SelTypes.STRING, res.type()); - assertEquals("foo1970-01-01T00:00:12.345Z", res.toString()); + assertEquals("foo1970-01-01T00:00:12.345Z[UTC]", res.toString()); } @Test @@ -138,8 +139,8 @@ public void testBox() { new Boolean[] {true, false}, new boolean[] {}, new HashMap(), - new DateTime(DateTimeZone.UTC), - new DateTime(DateTimeZone.UTC).dayOfWeek() + ZonedDateTime.ofInstant(Instant.ofEpochMilli(12345), ZoneId.of("UTC")), + SelJodaDateTimeProperty.of(ZonedDateTime.ofInstant(Instant.ofEpochMilli(12345), ZoneId.of("UTC")), ChronoField.DAY_OF_WEEK) }; String[] expectedResults = new String[] { @@ -156,8 +157,8 @@ public void testBox() { "BOOLEAN_ARRAY: [true, false]", "BOOLEAN_ARRAY: []", "MAP: {}", - "DATETIME: 1970-01-01T00:00:12.345Z", - "DATETIME_PROPERTY: Property[dayOfWeek]" + "DATETIME: 1970-01-01T00:00:12.345Z[UTC]", + "DATETIME_PROPERTY: Property[DayOfWeek]" }; for (int i = 0; i < testObjects.length; ++i) { @@ -191,9 +192,6 @@ public void testBoxDoubles() { public void testBoxUnsupported() { Object[] testObjects = new Object[] { - DateTimeZone.forID("UTC"), - DateTimeFormat.forPattern("yyyy"), - Days.days(1), new SimpleDateFormat("yyyyMMdd"), new Date(12345), new ArrayList() diff --git a/netflix-sel/src/test/java/com/netflix/sel/type/SelUtilFuncTest.java b/netflix-sel/src/test/java/com/netflix/sel/type/SelUtilFuncTest.java index 8e551173..e54183a7 100644 --- a/netflix-sel/src/test/java/com/netflix/sel/type/SelUtilFuncTest.java +++ b/netflix-sel/src/test/java/com/netflix/sel/type/SelUtilFuncTest.java @@ -14,10 +14,12 @@ import static org.junit.Assert.*; -import org.joda.time.DateTime; -import org.joda.time.DateTimeUtils; -import org.joda.time.DateTimeZone; -import org.joda.time.IllegalFieldValueException; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.time.DateTimeException; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -26,12 +28,12 @@ public class SelUtilFuncTest { @Before public void setUp() throws Exception { - DateTimeUtils.setCurrentMillisFixed(12345L); + SelJodaDateTime.CLOCK = Clock.fixed(Instant.ofEpochMilli(12345L), ZoneId.of("UTC")); } @After public void tearDown() throws Exception { - DateTimeUtils.setCurrentMillisSystem(); + SelJodaDateTime.CLOCK = Clock.systemDefaultZone(); } @Test @@ -61,7 +63,7 @@ public void testCallDateIntToTs() { assertEquals("LONG: 1546300800000", res.type() + ": " + res); } - @Test(expected = IllegalFieldValueException.class) + @Test(expected = DateTimeParseException.class) public void testCallDateIntToTsInvalid() { SelUtilFunc.INSTANCE.call("dateIntToTs", new SelType[] {SelLong.of(20200230)}); } @@ -98,7 +100,7 @@ public void testCallTimeoutForDateTimeDeadline() { SelUtilFunc.INSTANCE.call( "timeoutForDateTimeDeadline", new SelType[] { - SelJodaDateTime.of(new DateTime("2019-01-01", DateTimeZone.UTC)), + SelJodaDateTime.of(ZonedDateTime.parse("2019-01-01T00:00:00Z")), SelString.of("1 day") }); assertEquals("STRING: 1546387187655 milliseconds", res.type() + ": " + res); @@ -123,7 +125,7 @@ public void testCallTimeoutForDateIntDeadline() { assertEquals("STRING: 1546387187655 milliseconds", res.type() + ": " + res); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = DateTimeParseException.class) public void testCallTimeoutForDateIntDeadlineInvalidInput() { SelUtilFunc.INSTANCE.call( "timeoutForDateIntDeadline", @@ -224,7 +226,7 @@ public void testInvalidCall() { SelUtilFunc.INSTANCE.call("invalidMethod", new SelType[] {SelString.of("12345")}); } - @Test(expected = IllegalFieldValueException.class) + @Test(expected = DateTimeParseException.class) public void testInvalidCallDateIntsBetween() { SelUtilFunc.INSTANCE.call( "dateIntsBetween",