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
-1
View File
@@ -409,4 +409,3 @@ if __name__ == '__main__':
sys.exit(main(sys.argv))
except Abort as ex:
sys.exit(1)
+27 -71
View File
@@ -102,6 +102,22 @@ PRESUBMITS = {
{"node_modules/", ".idea"}, REQUIRED):
"Source files must end in a newline.",
# Files must not end with extraneous blank lines
PresubmitCheck(
r".*\n\n$",
("java", "js", "soy", "sql", "py", "sh", "gradle", "ts", "xml"),
{"node_modules/", ".idea", "nomulus.golden.sql"},
):
"Source files must not end with extraneous blank lines.",
# Duplicate empty lines
PresubmitCheck(
r".*\n\n\n.*",
("java", "js", "soy", "sh", "gradle", "ts", "xml"),
{"node_modules/", ".idea"},
):
"Source files must not contain duplicate empty lines.",
# System.(out|err).println should only appear in tools/ or load-testing/
PresubmitCheck(
r".*\bSystem\s*\.\s*(?:out|err)\s*\.\s*print.*", "java", {
@@ -160,7 +176,8 @@ PRESUBMITS = {
"SelfSignedCaCertificate.java",
"X509Utils.java",
"TmchCertificateAuthority.java",
"DelegatedCredentials.java"
"DelegatedCredentials.java",
"SslInitializerTestUtils.java"
},
):
"Do not use java.util.Date. Use classes in java.time package instead.",
@@ -202,85 +219,24 @@ PRESUBMITS = {
{},
):
"Do not use .isEqualTo(Optional.of(...)). Use Truth's .hasValue(...) instead.",
# TODO: Remove the java.time migration presubmit checks below once the entire codebase has been migrated to java.time.
PresubmitCheck(
r".*toDateTime\(\s*toInstant\(.*",
"java",
{"DateTimeUtilsTest.java"},
):
"Do not double-wrap toDateTime(toInstant(...)).",
PresubmitCheck(
r".*toInstant\(\s*toDateTime\(.*",
"java",
{"DateTimeUtilsTest.java"},
):
"Do not double-wrap toInstant(toDateTime(...)).",
PresubmitCheck(
r".*toInstant\([^;]*[cC]lock\.now\(\).*",
r".*java\.time\.ZonedDateTime.*",
"java",
{},
):
"Do not use toInstant(clock.now()). Use clock.now() instead.",
PresubmitCheck(
r".*toDateTime\([^;]*[cC]lock\.now\(\).*",
"java",
{},
):
"Do not use toDateTime(clock.now()). Use clock.now() and Instant overloads instead.",
PresubmitCheck(
r".*toInstant\([^;]*tm\(\)\.getTxTime\(\).*",
"java",
{},
):
"Do not use toInstant(tm().getTxTime()). Use tm().getTxTime() instead.",
PresubmitCheck(
r".*toDateTime\([^;]*tm\(\)\.getTxTime\(\).*",
"java",
{},
):
"Do not use toDateTime(tm().getTxTime()). Use tm().getTxTime() and Instant overloads instead.",
PresubmitCheck(
r".*\(\s*Instant\s*\)\s*(?:this\.)?(?:fakeClock|clock)\.now\(\s*\).*",
"java",
{},
):
"Do not unnecessarily cast clock.now() to Instant.",
PresubmitCheck(
r".*toDateTime\(\s*Instant\.now\(.*",
"java",
{},
):
"Do not wrap Instant.now() in toDateTime. Use DateTime.now(UTC) directly.",
PresubmitCheck(
r".*toInstant\(\s*DateTime\.now\(.*",
"java",
{},
):
"Do not wrap DateTime.now() in toInstant. Use Instant.now().truncatedTo(ChronoUnit.MILLIS) directly.",
PresubmitCheck(
r".*toDateTime\(\s*Instant\.parse\(.*",
"java",
{"DateTimeUtilsTest.java"},
):
"Do not wrap Instant.parse in toDateTime. Use DateTime.parse directly.",
PresubmitCheck(
r".*toInstant\(\s*DateTime\.parse\(.*",
"java",
{"DateTimeUtilsTest.java"},
):
"Do not wrap DateTime.parse in toInstant. Use Instant.parse directly.",
PresubmitCheck(
r".*cloneProjectedAtTime\(\s*toDateTime\(.*",
"java",
{},
):
"Do not use cloneProjectedAtTime(toDateTime(...)). Use cloneProjectedAtTime(...) instead.",
"Do not use java.time.ZonedDateTime. Use java.time.OffsetDateTime per go/avoid-zdt.",
PresubmitCheck(
r".*ZoneId\.of\(\s*\"UTC\"\s*\).*",
"java",
{},
):
"Do not use ZoneId.of(\"UTC\"). Use java.time.ZoneOffset.UTC."
"Do not use ZoneId.of(\"UTC\"). Use java.time.ZoneOffset.UTC.",
PresubmitCheck(
r".*org\.joda\.time.*",
"java",
{"SafeBrowsingTransforms.java"},
):
"Do not use Joda-Time. Use java.time instead.",
}
# Note that this regex only works for one kind of Flyway file. If we want to