Skip to content

Complete Joda-Time to java.time migration#3039

Merged
CydeWeys merged 1 commit into
google:masterfrom
CydeWeys:javatime-refactor-10th
May 13, 2026
Merged

Complete Joda-Time to java.time migration#3039
CydeWeys merged 1 commit into
google:masterfrom
CydeWeys:javatime-refactor-10th

Conversation

@CydeWeys

@CydeWeys CydeWeys commented May 9, 2026

Copy link
Copy Markdown
Member

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() and todayUtc() to eliminate repetitive conversions throughout the codebase.
  • 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 change is Reviewable

Comment thread util/src/main/java/google/registry/util/PosixTarHeader.java Fixed
@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from a252f9d to 788946a Compare May 11, 2026 17:30
@Override
public Instant now() {
// Truncate to milliseconds to match the precision of Joda DateTime and our database schema
// Truncate to milliseconds to match the precision of Joda Instant and our database schema

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems strange, but do note that we do use the Joda Instant class in one place (unavoidably), as that's what the Beam API uses.

* {@link #registrationExpirationTime}, after which point the next invocation of a periodic
* cronjob will explicitly delete the domain. This field is a DateTime and not a boolean because
* of edge cases that occur during the autorenew grace period. We need to be able to tell the
* cronjob will explicitly delete the domain. This field is a Instant and not a boolean because of

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Should be "an Instant". Grep the codebase for all uses of Instant in documentation and make them grammatically correct.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not done yet

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I hadn't done it yet. It is done now.

Comment thread core/src/main/java/google/registry/rdap/AbstractJsonableObject.java
Comment thread core/src/main/java/google/registry/rdap/AbstractJsonableObject.java
private final FakeClock clock = new FakeClock(DateTime.parse("1999-12-31TZ"));
private final FakeClock clock = new FakeClock(Instant.parse("1999-12-31T00:00:00Z"));

// This is teh default as-of time the RDE/BRDA job.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix spelling of "teh"

<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
<rdeDomain:exDate>+294247-01-10T04:00:54Z</rdeDomain:exDate>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know ISO 8601 specifies there should be a plus sign if the number of digits in the year exceeds four, but we probably don't want to make externally visible changes to our RDE format here. What do the relevant RFCs say for what exact datetime format is expected here? Does it want the plus for long dates or not? Consider reverting this change (because we know the current format is accepted) unless you're sure the new format is compliant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking into this further, I think we just use the default ISO format and allow there to be a plus sign. It should be in spec. Let's add a test ensuring it passes the RDE XSD.

// It wasn't a DateTime.
return new AbstractMap.SimpleEntry<>(null, Instant.parse(string));
} catch (DateTimeParseException e) {
// It wasn't a Instant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: It wasn't an Instant.

@CydeWeys
CydeWeys requested review from gbrodman May 11, 2026 17:58
@CydeWeys
CydeWeys enabled auto-merge May 11, 2026 17:58
@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from 788946a to 6c5c0c0 Compare May 11, 2026 18:21

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman partially reviewed 42 files and made 7 comments.
Reviewable status: 42 of 137 files reviewed, 14 unresolved discussions (waiting on CydeWeys).


-- commits line 12 at r2:
i don't think this line is true


common/src/main/java/google/registry/util/Clock.java line 50 at r2 (raw file):

  /** Returns the current time in milliseconds since the epoch. */
  default long nowMillis() {
    return now().toEpochMilli();

have you gone through to check to see if all instances of clock.now().toEpochMilli() have been replaced with this?


config/presubmits.py line 89 at r2 (raw file):

PRESUBMITS = {

i think we should probably add a presubmit that forbids joda time except in the exception(s)


core/src/main/java/google/registry/batch/DeleteProberDataAction.java line 95 at r2 (raw file):

  //
  // Note: creationTime must be compared to a Java object (CreateAutoTimestamp) but deletionTime can
  // be compared directly to the SQL timestamp (it's a Instant)

"an"


core/src/main/java/google/registry/beam/spec11/SafeBrowsingTransforms.java line 129 at r2 (raw file):

    /** Evaluates any buffered {@link DomainNameInfo} objects upon completing the bundle. */
    @SuppressWarnings("UnnecessarilyFullyQualified")

why do we even need to fully qualify this?


core/src/main/java/google/registry/model/domain/package-info.java line 35 at r2 (raw file):

import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
import java.time.Instant;

why imports added?

* {@link #registrationExpirationTime}, after which point the next invocation of a periodic
* cronjob will explicitly delete the domain. This field is a DateTime and not a boolean because
* of edge cases that occur during the autorenew grace period. We need to be able to tell the
* cronjob will explicitly delete the domain. This field is a Instant and not a boolean because of

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not done yet

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 95 files and all commit messages, and made 7 comments.
Reviewable status: all files reviewed, 21 unresolved discussions (waiting on CydeWeys).


core/src/main/java/google/registry/tools/GetEppResourceCommand.java line 35 at r3 (raw file):

      names = "--read_timestamp",
      description = "Timestamp to use when reading. May not be in the past.",
      converter = DateTimeParameter.class)

DateTime?


core/src/main/java/google/registry/tools/params/DateParameter.java line 35 at r3 (raw file):

  /**
   * Parser for DateTimes that permits only a restricted subset of ISO 8601 datetime syntax. The

parser for instants


core/src/main/java/google/registry/tools/params/DateTimeParameter.java line 24 at r3 (raw file):

/** {@linkplain Instant} CLI parameter converter/validator. Can be ISO or millis from epoch. */
public final class DateTimeParameter extends ParameterConverterValidator<Instant> {

why is this still called this?


core/src/main/java/google/registry/tools/params/TransitionListParameter.java line 32 at r3 (raw file):

public abstract class TransitionListParameter<V> extends KeyValueMapParameter<Instant, V> {

  private static final DateTimeParameter DATE_TIME_CONVERTER = new DateTimeParameter();

prob shouldn't call it DATE_TIME_CONVERTER


core/src/main/java/google/registry/xml/UtcDateTimeAdapter.java line 35 at r3 (raw file):

 * @see <a href="http://tools.ietf.org/html/rfc3339">RFC3339</a>
 */
public class UtcDateTimeAdapter extends XmlAdapter<String, Instant> {

prob shouldn't call it "datetime" in the name


core/src/test/java/google/registry/tools/GenerateEscrowDepositCommandTest.java line 284 at r3 (raw file):

  }
}

unnecessary newline?


util/src/main/java/google/registry/util/PosixTarHeader.java line 503 at r3 (raw file):

}

extra newlines

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from 6c5c0c0 to e56ab45 Compare May 11, 2026 19:14

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 10 files and all commit messages, and resolved 2 discussions.
Reviewable status: all files reviewed, 18 unresolved discussions (waiting on CydeWeys).

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch 3 times, most recently from 4f4afe5 to 173e4b3 Compare May 12, 2026 14:44

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CydeWeys made 12 comments and resolved 2 discussions.
Reviewable status: 100 of 139 files reviewed, 16 unresolved discussions (waiting on gbrodman).


-- commits line 12 at r2:

Previously, gbrodman wrote…

i don't think this line is true

It is true now.


common/src/main/java/google/registry/util/Clock.java line 50 at r2 (raw file):

Previously, gbrodman wrote…

have you gone through to check to see if all instances of clock.now().toEpochMilli() have been replaced with this?

Yes, all taken care of.


config/presubmits.py line 89 at r2 (raw file):

Previously, gbrodman wrote…

i think we should probably add a presubmit that forbids joda time except in the exception(s)

Done.


core/src/main/java/google/registry/beam/spec11/SafeBrowsingTransforms.java line 129 at r2 (raw file):

Previously, gbrodman wrote…

why do we even need to fully qualify this?

Because this is the only wrong Instant in the entire codebase, and it makes sense to make it look different at the callsite rather than import the deprecated Instant and then have this line look innocuous. I moved the suppress warnings down to be more specific.


core/src/main/java/google/registry/tools/params/DateParameter.java line 35 at r3 (raw file):

Previously, gbrodman wrote…

parser for instants

Done.


core/src/main/java/google/registry/tools/params/DateTimeParameter.java line 24 at r3 (raw file):

Previously, gbrodman wrote…

why is this still called this?

Done.


core/src/main/java/google/registry/tools/params/TransitionListParameter.java line 32 at r3 (raw file):

Previously, gbrodman wrote…

prob shouldn't call it DATE_TIME_CONVERTER

Done.


core/src/main/java/google/registry/xml/UtcDateTimeAdapter.java line 35 at r3 (raw file):

Previously, gbrodman wrote…

prob shouldn't call it "datetime" in the name

Done.


core/src/test/java/google/registry/tools/GenerateEscrowDepositCommandTest.java line 284 at r3 (raw file):

Previously, gbrodman wrote…

unnecessary newline?

Done.


core/src/main/java/google/registry/model/domain/package-info.java line 35 at r2 (raw file):

Previously, gbrodman wrote…

why imports added?

Done.


core/src/main/java/google/registry/tools/GetEppResourceCommand.java line 35 at r3 (raw file):

Previously, gbrodman wrote…

DateTime?

Done.

* {@link #registrationExpirationTime}, after which point the next invocation of a periodic
* cronjob will explicitly delete the domain. This field is a DateTime and not a boolean because
* of edge cases that occur during the autorenew grace period. We need to be able to tell the
* cronjob will explicitly delete the domain. This field is a Instant and not a boolean because of

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I hadn't done it yet. It is done now.

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from 173e4b3 to f131a1b Compare May 12, 2026 14:47

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CydeWeys made 1 comment.
Reviewable status: 100 of 139 files reviewed, 16 unresolved discussions (waiting on gbrodman).


util/src/main/java/google/registry/util/PosixTarHeader.java line 503 at r3 (raw file):

Previously, gbrodman wrote…

extra newlines

Done.

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PTAL

@CydeWeys made 1 comment.
Reviewable status: 96 of 139 files reviewed, 16 unresolved discussions (waiting on gbrodman).

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman partially reviewed 43 files and all commit messages, made 1 comment, and resolved 16 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on CydeWeys).


-- commits line 12 at r2:

Previously, CydeWeys (Ben McIlwain) wrote…

It is true now.

you sound like AI -- the lockfiles and dependencies are unmodified.

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CydeWeys made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on CydeWeys).


-- commits line 12 at r2:

Previously, gbrodman wrote…

you sound like AI -- the lockfiles and dependencies are unmodified.

Well the AI is wrong (in its commit description). The problem is that joda time is still a transitive/runtime dependency of Apache Beam, so while we can remove it from the dependencies file(s), it will still be pulled into the lock files, only then we won't even have control over which revision ends up being used. Do we care?

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from f131a1b to dc93816 Compare May 12, 2026 19:13

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good news -- I fixed the blank line issues once and for all.

(Though at the cost of some additional one-time-only diffs in this PR.)

@CydeWeys made 1 comment.
Reviewable status: 127 of 227 files reviewed, all discussions resolved (waiting on gbrodman).

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 4 files and all commit messages, and made 1 comment.
Reviewable status: 131 of 227 files reviewed, 1 unresolved discussion (waiting on CydeWeys).


-- commits line 12 at r2:

Previously, CydeWeys (Ben McIlwain) wrote…

Well the AI is wrong (in its commit description). The problem is that joda time is still a transitive/runtime dependency of Apache Beam, so while we can remove it from the dependencies file(s), it will still be pulled into the lock files, only then we won't even have control over which revision ends up being used. Do we care?

But we should remove it from the build.gradle files (which this PR does at least in part) and the dependencies.gradle file (which this PR does not).

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman partially reviewed 96 files.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on CydeWeys).

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from dc93816 to ee36a42 Compare May 12, 2026 19:38

@CydeWeys CydeWeys left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CydeWeys made 1 comment.
Reviewable status: 217 of 227 files reviewed, 1 unresolved discussion (waiting on gbrodman).


-- commits line 12 at r2:

Previously, gbrodman wrote…

But we should remove it from the build.gradle files (which this PR does at least in part) and the dependencies.gradle file (which this PR does not).

Welp, more worringly, after running another whole update of the lockfiles, it's not even showing in there either, so now it's just a floating version. But it's basically totally excised from everything now.

@CydeWeys

Copy link
Copy Markdown
Member Author

PTAL

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 10 files and all commit messages, and resolved 1 discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on CydeWeys).

@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from ee36a42 to 8615d1c Compare May 12, 2026 21:21

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 14 files and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on CydeWeys).

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.
@CydeWeys
CydeWeys force-pushed the javatime-refactor-10th branch from 8615d1c to 681dc7d Compare May 13, 2026 15:05

@gbrodman gbrodman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbrodman reviewed 15 files and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on CydeWeys).

@CydeWeys
CydeWeys added this pull request to the merge queue May 13, 2026
Merged via the queue into google:master with commit 56fe588 May 13, 2026
10 checks passed
@CydeWeys
CydeWeys deleted the javatime-refactor-10th branch May 13, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants