From db5e349e3d043be0b32626ad8b91011af297a8db Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:03:30 +0000 Subject: [PATCH 1/6] Add support for java.time.ZonedDateTime - Created JavaZonedDateTimeResolver to generate random ZonedDateTime instances. - Registered JavaZonedDateTimeResolver in SomeConfig.buildResolvers(). - Added comprehensive unit tests for JavaZonedDateTimeResolver. Co-authored-by: MessiasLima <10220064+MessiasLima@users.noreply.github.com> --- .../dev/appoutlet/some/config/SomeConfig.kt | 2 + .../resolver/JavaZonedDateTimeResolver.kt | 34 +++++++++++++ .../resolver/JavaZonedDateTimeResolverTest.kt | 48 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt create mode 100644 src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt diff --git a/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt b/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt index 2ac3da2e..afb9310c 100644 --- a/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt +++ b/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt @@ -18,6 +18,7 @@ import dev.appoutlet.some.resolver.IntResolver import dev.appoutlet.some.resolver.JavaDurationResolver import dev.appoutlet.some.resolver.JavaInstantResolver import dev.appoutlet.some.resolver.JavaUuidResolver +import dev.appoutlet.some.resolver.JavaZonedDateTimeResolver import dev.appoutlet.some.resolver.KotlinDurationResolver import dev.appoutlet.some.resolver.KotlinInstantResolver import dev.appoutlet.some.resolver.KotlinUuidResolver @@ -114,6 +115,7 @@ data class SomeConfig( JavaUuidResolver(), JavaInstantResolver(random), JavaDurationResolver(random), + JavaZonedDateTimeResolver(random), BigDecimalResolver(random), BigIntegerResolver(random), LocalDateResolver(random), diff --git a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt new file mode 100644 index 00000000..543cb019 --- /dev/null +++ b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt @@ -0,0 +1,34 @@ +package dev.appoutlet.some.resolver + +import dev.appoutlet.some.core.ResolverChain +import dev.appoutlet.some.core.TypeResolver +import java.time.LocalDate +import java.time.LocalTime +import java.time.Year +import java.time.ZoneOffset +import java.time.ZonedDateTime +import kotlin.random.Random +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +private const val HOURS_IN_DAY = 24 +private const val MINUTES_IN_HOUR = 60 +private const val SECONDS_IN_MINUTE = 60 +private const val START_YEAR = 1970 +private const val END_YEAR = 2100 + +class JavaZonedDateTimeResolver(private val random: Random) : TypeResolver { + override fun canResolve(type: KType): Boolean { + return type == typeOf() + } + + override fun resolve(type: KType, chain: ResolverChain): Any { + val year = random.nextInt(START_YEAR, END_YEAR + 1) + val dayOfYear = random.nextInt(1, Year.of(year).length() + 1) + val hour = random.nextInt(HOURS_IN_DAY) + val minute = random.nextInt(MINUTES_IN_HOUR) + val second = random.nextInt(SECONDS_IN_MINUTE) + val date = LocalDate.ofYearDay(year, dayOfYear) + return ZonedDateTime.of(date, LocalTime.of(hour, minute, second), ZoneOffset.UTC) + } +} diff --git a/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt b/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt new file mode 100644 index 00000000..fcb5863a --- /dev/null +++ b/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt @@ -0,0 +1,48 @@ +package dev.appoutlet.some.resolver + +import dev.appoutlet.some.test.defaultTestChain +import java.time.Instant +import java.time.ZonedDateTime +import kotlin.random.Random +import kotlin.reflect.typeOf +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertIs +import kotlin.test.assertTrue + +class JavaZonedDateTimeResolverTest { + @Test + fun `JavaZonedDateTimeResolver generates ZonedDateTime values`() { + val resolver = JavaZonedDateTimeResolver(Random.Default) + + val result = resolver.resolve(typeOf(), defaultTestChain) + assertIs(result) + } + + @Test + fun `JavaZonedDateTimeResolver generates ZonedDateTime within valid range`() { + val resolver = JavaZonedDateTimeResolver(Random.Default) + val start = ZonedDateTime.parse("1970-01-01T00:00:00Z") + val end = ZonedDateTime.parse("2101-01-01T00:00:00Z") + + repeat(100) { + val result = resolver.resolve(typeOf(), defaultTestChain) as ZonedDateTime + assertTrue(result.isAfter(start) || result.isEqual(start), "ZonedDateTime should be after or at 1970-01-01") + assertTrue(result.isBefore(end), "ZonedDateTime should be before 2101-01-01") + } + } + + @Test + fun `JavaZonedDateTimeResolver canResolve detects ZonedDateTime type`() { + val resolver = JavaZonedDateTimeResolver(Random.Default) + assertTrue(resolver.canResolve(typeOf())) + } + + @Test + fun `JavaZonedDateTimeResolver rejects other types`() { + val resolver = JavaZonedDateTimeResolver(Random.Default) + assertFalse(resolver.canResolve(typeOf()), "Should not resolve String") + assertFalse(resolver.canResolve(typeOf()), "Should not resolve Int") + assertFalse(resolver.canResolve(typeOf()), "Should not resolve java.time.Instant") + } +} From a4d355531fdf9c9c4814e9244bc34c59bf992817 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 23:32:19 +0000 Subject: [PATCH 2/6] Update documentation for ZonedDateTime support - Added java.time.ZonedDateTime to the list of supported types in docs/supported-types.md. Co-authored-by: MessiasLima <10220064+MessiasLima@users.noreply.github.com> --- docs/supported-types.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/supported-types.md b/docs/supported-types.md index 99ed5ecb..4c031d02 100644 --- a/docs/supported-types.md +++ b/docs/supported-types.md @@ -32,6 +32,7 @@ For types not listed here, register a [custom factory](custom-factories.md). | `java.math.BigInteger` | `some()` | | | `java.time.LocalDate` | `some()` | | | `java.time.LocalDateTime` | `some()` | | +| `java.time.ZonedDateTime` | `some()` | | | **Collections** | | | | `List` | `some>()` | See [CollectionStrategy](configuration/collection-strategy.md) | | `MutableList` | `some>()` | | From e7af4d18070337e84818f76b4dc108c04aa7c05e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 23:38:01 +0000 Subject: [PATCH 3/6] Update AGENTS.md for ZonedDateTime support - Added JavaZonedDateTimeResolver to the resolver registration order in AGENTS.md. Co-authored-by: MessiasLima <10220064+MessiasLima@users.noreply.github.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index a4c7624d..942859bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -132,6 +132,6 @@ Order matters - first match wins: 3. ObjectResolver, EnumResolver, SealedClassResolver, ValueClassResolver 4. Primitive resolvers (String, Int, Long, etc.) 5. **Kotlin native types FIRST** (KotlinUuidResolver, KotlinInstantResolver, KotlinDurationResolver) -6. **Java types SECOND** (JavaUuidResolver, JavaInstantResolver, JavaDurationResolver) +6. **Java types SECOND** (JavaUuidResolver, JavaInstantResolver, JavaDurationResolver, JavaZonedDateTimeResolver) 7. Collection resolvers (List, Set, Map, Array) 8. ClassResolver (fallback for classes with constructors) \ No newline at end of file From c76bd71a1dd69890147054caa55689b24aadc9b3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 04:46:35 +0000 Subject: [PATCH 4/6] Use random ZoneId in JavaZonedDateTimeResolver - Replaced ZoneOffset.UTC with a random ZoneId from the available set. Co-authored-by: MessiasLima <10220064+MessiasLima@users.noreply.github.com> --- .../appoutlet/some/resolver/JavaZonedDateTimeResolver.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt index 543cb019..bc1ba81e 100644 --- a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt +++ b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt @@ -5,7 +5,7 @@ import dev.appoutlet.some.core.TypeResolver import java.time.LocalDate import java.time.LocalTime import java.time.Year -import java.time.ZoneOffset +import java.time.ZoneId import java.time.ZonedDateTime import kotlin.random.Random import kotlin.reflect.KType @@ -29,6 +29,8 @@ class JavaZonedDateTimeResolver(private val random: Random) : TypeResolver { val minute = random.nextInt(MINUTES_IN_HOUR) val second = random.nextInt(SECONDS_IN_MINUTE) val date = LocalDate.ofYearDay(year, dayOfYear) - return ZonedDateTime.of(date, LocalTime.of(hour, minute, second), ZoneOffset.UTC) + val zoneIds = ZoneId.getAvailableZoneIds().toList() + val zoneId = ZoneId.of(zoneIds[random.nextInt(zoneIds.size)]) + return ZonedDateTime.of(date, LocalTime.of(hour, minute, second), zoneId) } } From cf060c0b017879aed2850b7a9ba2230ab96b4fd1 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 04:54:14 +0000 Subject: [PATCH 5/6] Optimize JavaZonedDateTimeResolver and add KDocs - Optimized ZonedDateTime generation using epoch seconds. - Added detailed KDocs to JavaZonedDateTimeResolver. - Cached available ZoneIds for better performance. Co-authored-by: MessiasLima <10220064+MessiasLima@users.noreply.github.com> --- epochs.sh.kt | 9 ++++++ .../resolver/JavaZonedDateTimeResolver.kt | 31 +++++++++---------- 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 epochs.sh.kt diff --git a/epochs.sh.kt b/epochs.sh.kt new file mode 100644 index 00000000..ec2d5edc --- /dev/null +++ b/epochs.sh.kt @@ -0,0 +1,9 @@ +import java.time.LocalDateTime +import java.time.ZoneOffset + +fun main() { + val start = LocalDateTime.of(1970, 1, 1, 0, 0, 0).toEpochSecond(ZoneOffset.UTC) + val end = LocalDateTime.of(2100, 12, 31, 23, 59, 59).toEpochSecond(ZoneOffset.UTC) + println("START_EPOCH=$start") + println("END_EPOCH=$end") +} diff --git a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt index bc1ba81e..661b5fad 100644 --- a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt +++ b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt @@ -2,35 +2,34 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.TypeResolver -import java.time.LocalDate -import java.time.LocalTime -import java.time.Year +import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -private const val HOURS_IN_DAY = 24 -private const val MINUTES_IN_HOUR = 60 -private const val SECONDS_IN_MINUTE = 60 -private const val START_YEAR = 1970 -private const val END_YEAR = 2100 +private const val START_EPOCH = 0L // 1970-01-01T00:00:00Z +private const val END_EPOCH = 4133894400L // 2101-01-01T00:00:00Z +/** + * Resolves [ZonedDateTime] instances. + * + * Generated values fall within the range 1970-01-01 to 2100-12-31. + * Each instance uses a randomly selected [ZoneId] from the available set on the JVM. + * + * @param random The random source used for generation. + */ class JavaZonedDateTimeResolver(private val random: Random) : TypeResolver { + private val zoneIds by lazy { ZoneId.getAvailableZoneIds().toList() } + override fun canResolve(type: KType): Boolean { return type == typeOf() } override fun resolve(type: KType, chain: ResolverChain): Any { - val year = random.nextInt(START_YEAR, END_YEAR + 1) - val dayOfYear = random.nextInt(1, Year.of(year).length() + 1) - val hour = random.nextInt(HOURS_IN_DAY) - val minute = random.nextInt(MINUTES_IN_HOUR) - val second = random.nextInt(SECONDS_IN_MINUTE) - val date = LocalDate.ofYearDay(year, dayOfYear) - val zoneIds = ZoneId.getAvailableZoneIds().toList() + val epochSecond = random.nextLong(START_EPOCH, END_EPOCH) val zoneId = ZoneId.of(zoneIds[random.nextInt(zoneIds.size)]) - return ZonedDateTime.of(date, LocalTime.of(hour, minute, second), zoneId) + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), zoneId) } } From 0e23c9d617a6e9171cbfbd4d8290a6d9a27fbf97 Mon Sep 17 00:00:00 2001 From: Messias Junior Date: Mon, 15 Jun 2026 12:42:21 +0100 Subject: [PATCH 6/6] min and max constants --- .../some/resolver/JavaZonedDateTimeResolver.kt | 9 +++------ .../some/resolver/JavaZonedDateTimeResolverTest.kt | 13 ------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt index 661b5fad..d2454764 100644 --- a/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt +++ b/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt @@ -9,9 +9,6 @@ import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -private const val START_EPOCH = 0L // 1970-01-01T00:00:00Z -private const val END_EPOCH = 4133894400L // 2101-01-01T00:00:00Z - /** * Resolves [ZonedDateTime] instances. * @@ -28,8 +25,8 @@ class JavaZonedDateTimeResolver(private val random: Random) : TypeResolver { } override fun resolve(type: KType, chain: ResolverChain): Any { - val epochSecond = random.nextLong(START_EPOCH, END_EPOCH) - val zoneId = ZoneId.of(zoneIds[random.nextInt(zoneIds.size)]) - return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), zoneId) + val epochSecond = random.nextLong(Instant.MIN.epochSecond, Instant.MAX.epochSecond) + val zoneId = zoneIds[random.nextInt(zoneIds.size)] + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.of(zoneId)) } } diff --git a/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt b/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt index fcb5863a..cbe301e4 100644 --- a/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt +++ b/src/test/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolverTest.kt @@ -19,19 +19,6 @@ class JavaZonedDateTimeResolverTest { assertIs(result) } - @Test - fun `JavaZonedDateTimeResolver generates ZonedDateTime within valid range`() { - val resolver = JavaZonedDateTimeResolver(Random.Default) - val start = ZonedDateTime.parse("1970-01-01T00:00:00Z") - val end = ZonedDateTime.parse("2101-01-01T00:00:00Z") - - repeat(100) { - val result = resolver.resolve(typeOf(), defaultTestChain) as ZonedDateTime - assertTrue(result.isAfter(start) || result.isEqual(start), "ZonedDateTime should be after or at 1970-01-01") - assertTrue(result.isBefore(end), "ZonedDateTime should be before 2101-01-01") - } - } - @Test fun `JavaZonedDateTimeResolver canResolve detects ZonedDateTime type`() { val resolver = JavaZonedDateTimeResolver(Random.Default)