Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions dependencies.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


# Dependencies of `io.spine.chords:spine-chords-client:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-client:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1.**No license information found**
Expand Down Expand Up @@ -1104,12 +1104,12 @@

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:08 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:20 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.chords:spine-chords-codegen-tests:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-codegen-tests:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
Expand Down Expand Up @@ -1899,12 +1899,12 @@ This report was generated on **Wed Jul 22 22:13:08 EEST 2026** using [Gradle-Lic

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:09 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:21 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.chords:spine-chords-core:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-core:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1.
Expand Down Expand Up @@ -2938,12 +2938,12 @@ This report was generated on **Wed Jul 22 22:13:09 EEST 2026** using [Gradle-Lic

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:10 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:22 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.chords:spine-chords-proto:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-proto:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1.**No license information found**
Expand Down Expand Up @@ -3976,12 +3976,12 @@ This report was generated on **Wed Jul 22 22:13:10 EEST 2026** using [Gradle-Lic

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:11 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:23 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.chords:spine-chords-proto-values:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-proto-values:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
Expand Down Expand Up @@ -4775,12 +4775,12 @@ This report was generated on **Wed Jul 22 22:13:11 EEST 2026** using [Gradle-Lic

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:12 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:23 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).




# Dependencies of `io.spine.chords:spine-chords-runtime:2.0.0-SNAPSHOT.91`
# Dependencies of `io.spine.chords:spine-chords-runtime:2.0.0-SNAPSHOT.92`

## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
Expand Down Expand Up @@ -5544,4 +5544,4 @@ This report was generated on **Wed Jul 22 22:13:12 EEST 2026** using [Gradle-Lic

The dependencies distributed under several licenses, are used according their commercial-use-friendly license.

This report was generated on **Wed Jul 22 22:13:13 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
This report was generated on **Thu Jul 23 01:48:24 EEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE).
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject.
-->
<groupId>io.spine.chords</groupId>
<artifactId>Chords</artifactId>
<version>2.0.0-SNAPSHOT.91</version>
<version>2.0.0-SNAPSHOT.92</version>

<inceptionYear>2015</inceptionYear>

Expand Down
57 changes: 44 additions & 13 deletions proto/src/main/kotlin/io/spine/chords/proto/time/DateTimeField.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2025, TeamDev. All rights reserved.
* Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -59,10 +59,10 @@ import io.spine.chords.proto.value.time.DefaultDatePattern
import java.time.Instant
import java.time.LocalDateTime
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatter.ofPattern
import java.time.format.DateTimeParseException
import java.util.*

private const val DefaultDateTimeFormat = "$DefaultDatePattern HH:mm"

Expand Down Expand Up @@ -108,18 +108,49 @@ public class DateTimeField : InputField<Timestamp>() {
)
}

override fun parseValue(rawText: String): Timestamp {
val offsetDateTime = try {
LocalDateTime.parse(
complementWithPattern(rawText, dateTimePattern).string,
ofPattern(dateTimePattern)
)
} catch (e: DateTimeParseException) {
throw ParseException("Enter a valid value", e)
}
val millis = Date.from(offsetDateTime.toInstant(WallClock.zoneOffset)).time
return Timestamps.fromMillis(millis)
override fun parseValue(rawText: String): Timestamp =
parseDateTime(rawText, dateTimePattern, WallClock.zoneOffset)
}

/**
* Parses date and time from raw input field text into a Protobuf [Timestamp].
*
* The [rawText] contains only editable characters of the date/time value. The
* separators specified by [dateTimePattern] are restored before parsing. The
* resulting local date/time is interpreted at [zoneOffset].
*
* @param rawText
* the editable characters entered into the input field.
* @param dateTimePattern
* the pattern used to restore separators and parse the date/time.
* @param zoneOffset
* the offset used to convert the local date/time into an instant.
* @return the parsed date/time represented as a Protobuf timestamp.
* @throws ParseException
* if the text cannot be parsed or the resulting instant is outside
* the range supported by Protobuf timestamps.
*/
internal fun parseDateTime(
rawText: String,
dateTimePattern: DateTimePattern,
zoneOffset: ZoneOffset
): Timestamp {
val localDateTime = try {
LocalDateTime.parse(
complementWithPattern(rawText, dateTimePattern).string,
ofPattern(dateTimePattern)
)
} catch (e: DateTimeParseException) {
throw ParseException("Enter a valid value", e)
}
val instant = localDateTime.toInstant(zoneOffset)
if (!Timestamps.isValid(instant.epochSecond, instant.nano)) {
throw ParseException("Enter a date/time within the supported range")
}
return Timestamp.newBuilder()
.setSeconds(instant.epochSecond)
.setNanos(instant.nano)
.build()
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.chords.proto.time

import com.google.protobuf.Timestamp
import com.google.protobuf.util.Timestamps
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.DisplayName
import io.kotest.matchers.shouldBe
import io.spine.chords.core.ParseException
import java.time.Instant
import java.time.ZoneOffset
import org.junit.jupiter.api.Test

private const val TestDateTimePattern = "yyyy-MM-dd HH:mm"
private const val OutOfRangeMessage = "Enter a date/time within the supported range"

@DisplayName("`DateTimeField` should")
internal class DateTimeFieldSpec {

@Test
fun `reject a local date-time before the Protobuf range`() {
val exception = shouldThrow<ParseException> {
parseDateTime("000101010000", TestDateTimePattern, ZoneOffset.ofHours(2))
}

exception.validationErrorMessage shouldBe OutOfRangeMessage
}

@Test
fun `accept the minimum Protobuf timestamp in a positive offset`() {
val result = parseDateTime(
"000101010200",
TestDateTimePattern,
ZoneOffset.ofHours(2)
)

result shouldBe Timestamps.MIN_VALUE
}

@Test
fun `reject a local date-time after the Protobuf range`() {
val exception = shouldThrow<ParseException> {
parseDateTime("999912312359", TestDateTimePattern, ZoneOffset.ofHours(-2))
}

exception.validationErrorMessage shouldBe OutOfRangeMessage
}

@Test
fun `parse an ordinary local date-time`() {
val result = parseDateTime("202507011230", TestDateTimePattern, ZoneOffset.UTC)
val expected = Timestamp.newBuilder()
.setSeconds(Instant.parse("2025-07-01T12:30:00Z").epochSecond)
.build()

result shouldBe expected
}
}
2 changes: 1 addition & 1 deletion version.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@
/**
* The version of all Chords libraries.
*/
val chordsVersion: String by extra("2.0.0-SNAPSHOT.91")
val chordsVersion: String by extra("2.0.0-SNAPSHOT.92")
Loading