Complete Joda-Time to java.time migration (#3039)

This completes the exhaustive refactoring of foundational temporal types from Joda-Time to the native java.time API across the entire codebase.

- Replaced org.joda.time.DateTime, Instant, LocalDate, and Duration with java.time equivalents.
- Audited and updated Clock implementations (FakeClock, SystemClock). Added nowMillis(), nowDate(), and nowDateTime() to eliminate repetitive conversions and maintain parallel naming.
- Replaced ZonedDateTime with OffsetDateTime globally per go/avoid-zdt. OffsetDateTime is a better fit as we use a hardcoded ZoneOffset.UTC throughout the system, making geographical time zone rules (like daylight saving time) irrelevant and preventing serialization ambiguities. Added a presubmit check.
- Completely removed all transitional bridge methods from DateTimeUtils and deleted obsolete converters (e.g., DateTimeConverter).
- Updated testing infrastructure, Apache Beam pipelines, custom JCommander parameters, and networking modules to solely rely on java.time primitives.
- Retained the lone necessary org.joda.time.Instant usage in SafeBrowsingTransforms required by the Apache Beam API.
- Cleared Gradle lockfiles and removed the joda-time dependency entirely from the build configuration.
This commit is contained in:
Ben McIlwain
2026-05-13 16:07:19 +00:00
committed by GitHub
parent b33c2f4874
commit 56fe588b56
218 changed files with 589 additions and 1390 deletions
@@ -16,15 +16,16 @@ package google.registry.util;
import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import javax.annotation.concurrent.ThreadSafe;
/**
* A clock that tells the current time in milliseconds or nanoseconds.
*
* <p>Clocks are technically serializable because they are either a stateless wrapper around the
* system clock, or for testing, are just a wrapper around a DateTime. This means that if you
* system clock, or for testing, are just a wrapper around an Instant. This means that if you
* serialize a clock and deserialize it elsewhere, you won't necessarily get the same time or time
* zone -- what you will get is a functioning clock.
*/
@@ -34,8 +35,18 @@ public interface Clock extends Serializable {
/** Returns current Instant (which is always in UTC). */
Instant now();
/** Returns the current time as a {@link ZonedDateTime} in UTC. */
default ZonedDateTime nowDate() {
return ZonedDateTime.ofInstant(now(), ZoneOffset.UTC);
/** Returns the current time as an {@link OffsetDateTime} in UTC. */
default OffsetDateTime nowDateTime() {
return OffsetDateTime.ofInstant(now(), ZoneOffset.UTC);
}
/** Returns the current time as a {@link LocalDate} in UTC. */
default LocalDate nowDate() {
return LocalDate.ofInstant(now(), ZoneOffset.UTC);
}
/** Returns the current time in milliseconds since the epoch. */
default long nowMillis() {
return now().toEpochMilli();
}
}