mirror of
https://github.com/google/nomulus
synced 2026-05-23 00:01:58 +00:00
Refactor foundational temporal types to java.time (#3036)
* Migrates core classes (Clock, Sleeper, TransactionManager) and extensive domain models from Joda-Time to java.time. * Restores original public API method names while substituting parameters/return values with `java.time.Instant`. * Updates JAXB XJC `bindings.xjb` to natively generate `java.time.Instant` and `java.time.LocalDate`, eliminating `toDateTime` wrapper methods. * Fixes XML serializers (`DateAdapter`) to robustly convert OffsetDateTime timezone strings to UTC. * Cleans up redundant imports and Checkstyle failures across the codebase. Remaining Joda-Time surface area to migrate in future tasks: * Command-line parameters (e.g. `DateTimeParameter`, `DateParameter`, `IntervalParameter`) in `google.registry.tools.params`. * EPP/RDAP flow testing infrastructure (`EppTestCase`, `RdapActionBaseTestCase`, `FlowTestCase`). * Beam pipelines and Load Testing modules (`Spec11PipelineTest`, `RdePipelineTest`, `RegistryJpaReadTest`, `EppClient`). * Utility bridges and converters (`DateTimeUtils.toDateTime/toInstant`, `DateTimeConverter`, `UtcDateTimeAdapter`). * Remaining UI Console tests and Actions.
This commit is contained in:
@@ -19,7 +19,6 @@ import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A clock that tells the current time in milliseconds or nanoseconds.
|
||||
@@ -32,10 +31,6 @@ import org.joda.time.DateTime;
|
||||
@ThreadSafe
|
||||
public interface Clock extends Serializable {
|
||||
|
||||
/** Returns current time in UTC timezone. */
|
||||
@Deprecated
|
||||
DateTime nowUtc();
|
||||
|
||||
/** Returns current Instant (which is always in UTC). */
|
||||
Instant now();
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import static org.joda.time.DateTimeZone.UTC;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.sql.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
@@ -31,27 +31,13 @@ import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
/** Utilities methods and constants related to Joda {@link DateTime} objects. */
|
||||
public abstract class DateTimeUtils {
|
||||
|
||||
/** The start of the epoch, in a convenient constant. */
|
||||
@Deprecated public static final DateTime START_OF_TIME = new DateTime(0, UTC);
|
||||
|
||||
/** The start of the UNIX epoch (which is defined in UTC), in a convenient constant. */
|
||||
public static final Instant START_INSTANT = Instant.ofEpochMilli(0);
|
||||
|
||||
/**
|
||||
* A date in the far future that we can treat as infinity.
|
||||
*
|
||||
* <p>This value is (2^63-1)/1000 rounded down. Postgres can store dates as 64 bit microseconds,
|
||||
* but Java uses milliseconds, so this is the largest representable date that will survive a
|
||||
* round-trip through the database.
|
||||
*/
|
||||
@Deprecated public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, UTC);
|
||||
|
||||
/**
|
||||
* An instant in the far future that we can treat as infinity.
|
||||
*
|
||||
@@ -71,7 +57,7 @@ public abstract class DateTimeUtils {
|
||||
*/
|
||||
private static final DateTimeFormatter ISO_8601_FORMATTER =
|
||||
new DateTimeFormatterBuilder()
|
||||
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NORMAL)
|
||||
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NOT_NEGATIVE)
|
||||
.appendPattern("-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
.toFormatter()
|
||||
.withZone(ZoneOffset.UTC);
|
||||
@@ -102,55 +88,28 @@ public abstract class DateTimeUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the earliest of a number of given {@link DateTime} instances. */
|
||||
public static DateTime earliestOf(DateTime first, DateTime... rest) {
|
||||
return earliestDateTimeOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the earliest of a number of given {@link Instant} instances. */
|
||||
public static Instant earliestOf(Instant first, Instant... rest) {
|
||||
return earliestOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the earliest element in a {@link DateTime} iterable. */
|
||||
public static DateTime earliestDateTimeOf(Iterable<DateTime> dates) {
|
||||
checkArgument(!Iterables.isEmpty(dates));
|
||||
return Ordering.<DateTime>natural().min(dates);
|
||||
}
|
||||
|
||||
/** Returns the earliest element in a {@link Instant} iterable. */
|
||||
public static Instant earliestOf(Iterable<Instant> instants) {
|
||||
checkArgument(!Iterables.isEmpty(instants));
|
||||
return Ordering.<Instant>natural().min(instants);
|
||||
}
|
||||
|
||||
/** Returns the latest of a number of given {@link DateTime} instances. */
|
||||
public static DateTime latestOf(DateTime first, DateTime... rest) {
|
||||
return latestDateTimeOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the latest of a number of given {@link Instant} instances. */
|
||||
public static Instant latestOf(Instant first, Instant... rest) {
|
||||
return latestOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the latest element in a {@link DateTime} iterable. */
|
||||
public static DateTime latestDateTimeOf(Iterable<DateTime> dates) {
|
||||
checkArgument(!Iterables.isEmpty(dates));
|
||||
return Ordering.<DateTime>natural().max(dates);
|
||||
}
|
||||
|
||||
/** Returns the latest element in a {@link Instant} iterable. */
|
||||
public static Instant latestOf(Iterable<Instant> instants) {
|
||||
checkArgument(!Iterables.isEmpty(instants));
|
||||
return Ordering.<Instant>natural().max(instants);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link DateTime} is equal to or earlier than the second. */
|
||||
public static boolean isBeforeOrAt(DateTime timeToCheck, DateTime timeToCompareTo) {
|
||||
return !timeToCheck.isAfter(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Converts a Joda-Time Duration to a java.time.Duration. */
|
||||
@Nullable
|
||||
public static java.time.Duration toJavaDuration(@Nullable ReadableDuration duration) {
|
||||
@@ -168,25 +127,11 @@ public abstract class DateTimeUtils {
|
||||
return !timeToCheck.isAfter(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link DateTime} is equal to or later than the second. */
|
||||
public static boolean isAtOrAfter(DateTime timeToCheck, DateTime timeToCompareTo) {
|
||||
return !timeToCheck.isBefore(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link Instant} is equal to or later than the second. */
|
||||
public static boolean isAtOrAfter(Instant timeToCheck, Instant timeToCompareTo) {
|
||||
return !timeToCheck.isBefore(timeToCompareTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of
|
||||
* {@link DateTime#plusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
public static DateTime plusYears(DateTime now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return years == 0 ? now : now.plusYears(1).plusYears(years - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of
|
||||
* {@link java.time.ZonedDateTime#plusYears} to ensure that we never end up on February 29.
|
||||
@@ -210,15 +155,6 @@ public abstract class DateTimeUtils {
|
||||
return now.atZone(ZoneOffset.UTC).minusMonths(months).toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead
|
||||
* of {@link DateTime#minusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
public static DateTime minusYears(DateTime now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return years == 0 ? now : now.minusYears(1).minusYears(years - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead
|
||||
* of {@link java.time.ZonedDateTime#minusYears} to ensure that we never end up on February 29.
|
||||
@@ -230,40 +166,9 @@ public abstract class DateTimeUtils {
|
||||
: now.atZone(ZoneOffset.UTC).minusYears(1).minusYears(years - 1).toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #plusYears(DateTime, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static DateTime leapSafeAddYears(DateTime now, int years) {
|
||||
return plusYears(now, years);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #minusYears(DateTime, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static DateTime leapSafeSubtractYears(DateTime now, int years) {
|
||||
return minusYears(now, years);
|
||||
}
|
||||
|
||||
public static Date toSqlDate(LocalDate localDate) {
|
||||
return new Date(localDate.toDateTimeAtStartOfDay().getMillis());
|
||||
}
|
||||
|
||||
public static LocalDate toLocalDate(Date date) {
|
||||
return new LocalDate(date.getTime(), UTC);
|
||||
}
|
||||
|
||||
/** Converts a java.time.LocalDate to a Joda-Time LocalDate. */
|
||||
public static LocalDate toJodaLocalDate(java.time.LocalDate localDate) {
|
||||
return new LocalDate(localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth());
|
||||
}
|
||||
|
||||
/** Converts an Instant to a Joda-Time LocalDate in UTC. */
|
||||
public static LocalDate toJodaLocalDate(Instant instant) {
|
||||
return new LocalDate(instant.toEpochMilli(), UTC);
|
||||
/** Converts an Instant to a java.time.LocalDate in UTC. */
|
||||
public static LocalDate toLocalDate(Instant instant) {
|
||||
return instant.atZone(ZoneOffset.UTC).toLocalDate();
|
||||
}
|
||||
|
||||
/** Convert a joda {@link DateTime} to a java.time {@link Instant}, null-safe. */
|
||||
@@ -300,11 +205,19 @@ public abstract class DateTimeUtils {
|
||||
return instant.minus(minutes, ChronoUnit.MINUTES);
|
||||
}
|
||||
|
||||
public static Instant plusDays(Instant instant, int days) {
|
||||
public static Instant plusWeeks(Instant instant, int weeks) {
|
||||
return instant.atZone(ZoneOffset.UTC).plusWeeks(weeks).toInstant();
|
||||
}
|
||||
|
||||
public static Instant minusWeeks(Instant instant, int weeks) {
|
||||
return instant.atZone(ZoneOffset.UTC).minusWeeks(weeks).toInstant();
|
||||
}
|
||||
|
||||
public static Instant plusDays(Instant instant, long days) {
|
||||
return instant.atZone(ZoneOffset.UTC).plusDays(days).toInstant();
|
||||
}
|
||||
|
||||
public static Instant minusDays(Instant instant, int days) {
|
||||
public static Instant minusDays(Instant instant, long days) {
|
||||
return instant.atZone(ZoneOffset.UTC).minusDays(days).toInstant();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
/**
|
||||
* An object which accepts requests to put the current thread to sleep.
|
||||
@@ -31,16 +30,7 @@ public interface Sleeper {
|
||||
*
|
||||
* @throws InterruptedException if this thread was interrupted
|
||||
*/
|
||||
void sleep(ReadableDuration duration) throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep.
|
||||
*
|
||||
* @throws InterruptedException if this thread was interrupted
|
||||
*/
|
||||
default void sleep(Duration duration) throws InterruptedException {
|
||||
sleep(DateTimeUtils.toJodaDuration(duration));
|
||||
}
|
||||
void sleep(Duration duration) throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep, ignoring interrupts.
|
||||
@@ -50,35 +40,7 @@ public interface Sleeper {
|
||||
*
|
||||
* @see com.google.common.util.concurrent.Uninterruptibles#sleepUninterruptibly
|
||||
*/
|
||||
void sleepUninterruptibly(ReadableDuration duration);
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep, ignoring interrupts.
|
||||
*
|
||||
* <p>If {@link InterruptedException} was caught, then {@code Thread.currentThread().interrupt()}
|
||||
* will be called at the end of the {@code duration}.
|
||||
*
|
||||
* @see com.google.common.util.concurrent.Uninterruptibles#sleepUninterruptibly
|
||||
*/
|
||||
default void sleepUninterruptibly(Duration duration) {
|
||||
sleepUninterruptibly(DateTimeUtils.toJodaDuration(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current thread to interruptible sleep.
|
||||
*
|
||||
* <p>This is a convenience method for {@link #sleep} that properly converts an {@link
|
||||
* InterruptedException} to a {@link RuntimeException}.
|
||||
*/
|
||||
default void sleepInterruptibly(ReadableDuration duration) {
|
||||
try {
|
||||
sleep(duration);
|
||||
} catch (InterruptedException e) {
|
||||
// Restore current thread's interrupted state.
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Interrupted.", e);
|
||||
}
|
||||
}
|
||||
void sleepUninterruptibly(Duration duration);
|
||||
|
||||
/**
|
||||
* Puts the current thread to interruptible sleep.
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
package google.registry.util;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.MILLIS;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Clock implementation that proxies to the real system clock. */
|
||||
@ThreadSafe
|
||||
@@ -31,12 +29,6 @@ public class SystemClock implements Clock {
|
||||
@Inject
|
||||
public SystemClock() {}
|
||||
|
||||
/** Returns the current time. */
|
||||
@Override
|
||||
public DateTime nowUtc() {
|
||||
return DateTime.now(UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant now() {
|
||||
// Truncate to milliseconds to match the precision of Joda DateTime and our database schema
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.toJavaDuration;
|
||||
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
/** Implementation of {@link Sleeper} for production use. */
|
||||
@ThreadSafe
|
||||
@@ -33,14 +32,14 @@ public final class SystemSleeper implements Sleeper, Serializable {
|
||||
public SystemSleeper() {}
|
||||
|
||||
@Override
|
||||
public void sleep(ReadableDuration duration) throws InterruptedException {
|
||||
checkArgument(duration.getMillis() >= 0);
|
||||
Thread.sleep(duration.getMillis());
|
||||
public void sleep(Duration duration) throws InterruptedException {
|
||||
checkArgument(!duration.isNegative(), "Duration must be non-negative");
|
||||
Thread.sleep(duration.toMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sleepUninterruptibly(ReadableDuration duration) {
|
||||
checkArgument(duration.getMillis() >= 0);
|
||||
Uninterruptibles.sleepUninterruptibly(toJavaDuration(duration));
|
||||
public void sleepUninterruptibly(Duration duration) {
|
||||
checkArgument(!duration.isNegative(), "Duration must be non-negative");
|
||||
Uninterruptibles.sleepUninterruptibly(duration);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user