Skip to content

Ensure better ISO 8601 compliance #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

dkhalanskyjb
Copy link
Collaborator

ISO 8601 defines the period of one month as a fixed number of calendar days, specified by the calendar.

Before this change, we treated a month as a separate time scale unit during DatePeriod arithmetics, namely, we resolved the LocalDateTime on which we did arithmetics internally after adding the months but before adding the days.

This change makes it so that adding months and days is done as a single change, only consulting the calendar, and the time zone is only used once all calendar-based operations are performed.

The code that calculates the DateTimePeriod between two Instant values is changed symmetrically.

ISO 8601 defines the period of one month as a fixed number of
calendar days, specified by the calendar.

Before this change, we treated a month as a separate time scale
unit during `DatePeriod` arithmetics, namely, we resolved the
`LocalDateTime` on which we did arithmetics internally after adding
the months but before adding the days.

This change makes it so that adding months and days is done as a
single change, only consulting the calendar, and the time zone is
only used once all calendar-based operations are performed.

The code that calculates the `DateTimePeriod` between two
`Instant` values is changed symmetrically.
throw DateTimeArithmeticException("The number of months between $this and $other does not fit in an Int")
}
thisDate = thisDate.plus(days, DateTimeUnit.DAY) // won't throw: thisLdt + days <= otherLdt
val thisInstant = LocalDateTime(thisDate, thisLdt.time).toInstant(timeZone)
Copy link
Member

Choose a reason for hiding this comment

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

Does this toInstant use the same resolve mode as ZDT.plus(days) that was used before?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not exactly.

Imagine a situation:

  • UTC offset before is +1:00;
  • An overlap happens;
  • UTC offset after is +0:00.

If we subtract, say, a day and land into this overlap, then, as is currently implemented, the +0:00 offset will be used. In this PR, the UTC offset +1:00 will be used instead.

Copy link
Member

Choose a reason for hiding this comment

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

I believe it would be better to preserve resolve behavior in these operations, so that
Instant + DatePeriod(days = 1) == Instant.plus(1, DAY)

@@ -11,6 +11,7 @@ import kotlinx.datetime.internal.*
import kotlinx.datetime.serializers.InstantIso8601Serializer
import kotlinx.serialization.Serializable
import java.time.DateTimeException
import java.time.ZonedDateTime
Copy link
Member

Choose a reason for hiding this comment

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

Accidental import?

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.

2 participants