From 8b473930b9dc75988ee30c2c4b8fa1f9388e4f96 Mon Sep 17 00:00:00 2001 From: Erik Christensen <40830816+erikc5000@users.noreply.github.com> Date: Tue, 18 May 2021 12:18:30 -0400 Subject: [PATCH] Add addition/subtraction of centuries and decades to date-times (#185) --- .../commonMain/kotlin/io/islandtime/Date.kt | 52 ++++- .../kotlin/io/islandtime/DateTime.kt | 104 +++++++++ .../kotlin/io/islandtime/DayOfWeek.kt | 5 +- .../kotlin/io/islandtime/Instant.kt | 49 ++++- .../commonMain/kotlin/io/islandtime/Month.kt | 14 +- .../kotlin/io/islandtime/OffsetDateTime.kt | 104 ++++++++- .../kotlin/io/islandtime/OffsetTime.kt | 48 ++++ .../commonMain/kotlin/io/islandtime/Time.kt | 38 ++++ .../commonMain/kotlin/io/islandtime/Year.kt | 42 +++- .../kotlin/io/islandtime/YearMonth.kt | 35 +++ .../kotlin/io/islandtime/ZonedDateTime.kt | 98 ++++++++- .../kotlin/io/islandtime/DateTest.kt | 162 ++++++++++---- .../kotlin/io/islandtime/DateTimeTest.kt | 207 +++++++++--------- .../kotlin/io/islandtime/YearMonthTest.kt | 171 +++++++++++++-- .../kotlin/io/islandtime/YearTest.kt | 142 +++++++++++- 15 files changed, 1073 insertions(+), 198 deletions(-) diff --git a/core/src/commonMain/kotlin/io/islandtime/Date.kt b/core/src/commonMain/kotlin/io/islandtime/Date.kt index c3167d4a6..9df3b9a08 100644 --- a/core/src/commonMain/kotlin/io/islandtime/Date.kt +++ b/core/src/commonMain/kotlin/io/islandtime/Date.kt @@ -111,6 +111,19 @@ class Date( } } + /** + * Returns this date with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): Date = plus(centuries.inYears) + + /** + * Returns this date with [decades] added to it. + */ + operator fun plus(decades: Decades): Date = plus(decades.inYears) + + /** + * Returns this date with [years] added to it. + */ operator fun plus(years: Years): Date { return if (years.value == 0L) { this @@ -120,6 +133,9 @@ class Date( } } + /** + * Returns this date with [months] added to it. + */ operator fun plus(months: Months): Date { return if (months.value == 0L) { this @@ -132,8 +148,14 @@ class Date( } } + /** + * Returns this date with [weeks] added to it. + */ operator fun plus(weeks: Weeks): Date = plus(weeks.inDays) + /** + * Returns this date with [days] added to it. + */ operator fun plus(days: Days): Date { return if (days.value == 0L) { this @@ -156,6 +178,19 @@ class Date( } } + /** + * Returns this date with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): Date = minus(centuries.inYears) + + /** + * Returns this date with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): Date = minus(decades.inYears) + + /** + * Returns this date with [years] subtracted from it. + */ operator fun minus(years: Years): Date { return if (years.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.years + 1.years @@ -164,6 +199,9 @@ class Date( } } + /** + * Returns this date with [months] subtracted from it. + */ operator fun minus(months: Months): Date { return if (months.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.months + 1.months @@ -172,14 +210,14 @@ class Date( } } - operator fun minus(weeks: Weeks): Date { - return if (weeks.value == Long.MIN_VALUE) { - this + Long.MAX_VALUE.days + 1.weeks - } else { - plus(weeks.negateUnchecked()) - } - } + /** + * Returns this date with [weeks] subtracted from it. + */ + operator fun minus(weeks: Weeks): Date = minus(weeks.inDays) + /** + * Returns this date with [days] subtracted from it. + */ operator fun minus(days: Days): Date { return if (days.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.days + 1.days diff --git a/core/src/commonMain/kotlin/io/islandtime/DateTime.kt b/core/src/commonMain/kotlin/io/islandtime/DateTime.kt index a4238f508..da322a728 100644 --- a/core/src/commonMain/kotlin/io/islandtime/DateTime.kt +++ b/core/src/commonMain/kotlin/io/islandtime/DateTime.kt @@ -138,6 +138,31 @@ class DateTime( return duration.toComponents { seconds, nanoseconds -> this + seconds + nanoseconds } } + /** + * Returns this date-tme with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): DateTime { + return if (centuries.value == 0L) { + this + } else { + copy(date = date + centuries) + } + } + + /** + * Returns this date-time with [decades] added to it. + */ + operator fun plus(decades: Decades): DateTime { + return if (decades.value == 0L) { + this + } else { + copy(date = date + decades) + } + } + + /** + * Returns this date-time with [years] added to it. + */ operator fun plus(years: Years): DateTime { return if (years.value == 0L) { this @@ -146,6 +171,9 @@ class DateTime( } } + /** + * Returns this date-time with [months] added to it. + */ operator fun plus(months: Months): DateTime { return if (months.value == 0L) { this @@ -154,6 +182,9 @@ class DateTime( } } + /** + * Returns this date-time with [weeks] added to it. + */ operator fun plus(weeks: Weeks): DateTime { return if (weeks.value == 0L) { this @@ -162,6 +193,9 @@ class DateTime( } } + /** + * Returns this date-time with [days] added to it. + */ operator fun plus(days: Days): DateTime { return if (days.value == 0L) { this @@ -170,6 +204,9 @@ class DateTime( } } + /** + * Returns this date-time with [hours] added to it. + */ operator fun plus(hours: Hours): DateTime { return if (hours.value == 0L) { this @@ -186,6 +223,9 @@ class DateTime( } } + /** + * Returns this date-time with [minutes] added to it. + */ operator fun plus(minutes: Minutes): DateTime { return if (minutes.value == 0L) { this @@ -211,6 +251,9 @@ class DateTime( } } + /** + * Returns this date-time with [seconds] added to it. + */ operator fun plus(seconds: Seconds): DateTime { return if (seconds.value == 0L) { this @@ -234,6 +277,9 @@ class DateTime( } } + /** + * Returns this date-time with [milliseconds] added to it. + */ operator fun plus(milliseconds: Milliseconds): DateTime { return if (milliseconds.value == 0L) { this @@ -242,6 +288,9 @@ class DateTime( } } + /** + * Returns this date-time with [microseconds] added to it. + */ operator fun plus(microseconds: Microseconds): DateTime { return if (microseconds.value == 0L) { this @@ -250,6 +299,9 @@ class DateTime( } } + /** + * Returns this date-time with [nanoseconds] added to it. + */ operator fun plus(nanoseconds: Nanoseconds): DateTime { return if (nanoseconds.value == 0L) { this @@ -287,6 +339,31 @@ class DateTime( return this - duration.seconds - duration.nanosecondAdjustment } + /** + * Returns this date-time with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): DateTime { + return if (centuries.value == 0L) { + this + } else { + copy(date = date - centuries) + } + } + + /** + * Returns this date-time with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): DateTime { + return if (decades.value == 0L) { + this + } else { + copy(date = date - decades) + } + } + + /** + * Returns this date-time with [years] subtracted from it. + */ operator fun minus(years: Years): DateTime { return if (years.value == 0L) { this @@ -295,6 +372,9 @@ class DateTime( } } + /** + * Returns this date-time with [months] subtracted from it. + */ operator fun minus(months: Months): DateTime { return if (months.value == 0L) { this @@ -303,6 +383,9 @@ class DateTime( } } + /** + * Returns this date-time with [weeks] subtracted from it. + */ operator fun minus(weeks: Weeks): DateTime { return if (weeks.value == 0L) { this @@ -311,6 +394,9 @@ class DateTime( } } + /** + * Returns this date-time with [days] subtracted from it. + */ operator fun minus(days: Days): DateTime { return if (days.value == 0L) { this @@ -319,6 +405,9 @@ class DateTime( } } + /** + * Returns this date-time with [hours] subtracted from it. + */ operator fun minus(hours: Hours): DateTime { return if (hours.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.hours + 1.hours @@ -327,6 +416,9 @@ class DateTime( } } + /** + * Returns this date-time with [minutes] subtracted from it. + */ operator fun minus(minutes: Minutes): DateTime { return if (minutes.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.minutes + 1.minutes @@ -335,6 +427,9 @@ class DateTime( } } + /** + * Returns this date-time with [seconds] subtracted from it. + */ operator fun minus(seconds: Seconds): DateTime { return if (seconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.seconds + 1.seconds @@ -343,6 +438,9 @@ class DateTime( } } + /** + * Returns this date-time with [milliseconds] subtracted from it. + */ operator fun minus(milliseconds: Milliseconds): DateTime { return if (milliseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.milliseconds + 1.milliseconds @@ -351,6 +449,9 @@ class DateTime( } } + /** + * Returns this date-time with [microseconds] subtracted from it. + */ operator fun minus(microseconds: Microseconds): DateTime { return if (microseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.microseconds + 1.microseconds @@ -359,6 +460,9 @@ class DateTime( } } + /** + * Returns this date-time with [nanoseconds] subtracted from it. + */ operator fun minus(nanoseconds: Nanoseconds): DateTime { return if (nanoseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.nanoseconds + 1.nanoseconds diff --git a/core/src/commonMain/kotlin/io/islandtime/DayOfWeek.kt b/core/src/commonMain/kotlin/io/islandtime/DayOfWeek.kt index a22a43bc0..4b2715810 100644 --- a/core/src/commonMain/kotlin/io/islandtime/DayOfWeek.kt +++ b/core/src/commonMain/kotlin/io/islandtime/DayOfWeek.kt @@ -69,12 +69,13 @@ enum class DayOfWeek { } /** - * Adds days to this day of the week, wrapping when the beginning or end of the week is reached. + * Returns this day of the week with [days] added to it, wrapping when the beginning or end of the week is reached. */ operator fun plus(days: Days): DayOfWeek = plus((days.value % DAYS_PER_WEEK).toInt()) /** - * Subtracts days from this day of the week, wrapping when the beginning or end of the week is reached. + * Returns this day of the week with [days] subtracted from it, wrapping when the beginning or end of the week is + * reached. */ operator fun minus(days: Days): DayOfWeek = plus(-(days.value % DAYS_PER_WEEK).toInt()) diff --git a/core/src/commonMain/kotlin/io/islandtime/Instant.kt b/core/src/commonMain/kotlin/io/islandtime/Instant.kt index 18b2732fc..a4aa80c50 100644 --- a/core/src/commonMain/kotlin/io/islandtime/Instant.kt +++ b/core/src/commonMain/kotlin/io/islandtime/Instant.kt @@ -46,25 +46,49 @@ class Instant private constructor( } } + /** + * Returns this instant with a number of 24-hour [days] added to it. + */ operator fun plus(days: Days): Instant = plus(days.inSeconds.toLong(), 0) + + /** + * Returns this instant with [hours] added to it. + */ override operator fun plus(hours: Hours): Instant = plus(hours.inSeconds.toLong(), 0) + + /** + * Returns this instant with [minutes] added to it. + */ override operator fun plus(minutes: Minutes): Instant = plus(minutes.inSeconds.toLong(), 0) + + /** + * Returns this instant with [seconds] added to it. + */ override operator fun plus(seconds: Seconds): Instant = plus(seconds.toLong(), 0) + /** + * Returns this instant with [milliseconds] added to it. + */ override operator fun plus(milliseconds: Milliseconds): Instant { return plus( milliseconds.inWholeSeconds.toLong(), - (milliseconds.value % MILLISECONDS_PER_SECOND).toInt() * NANOSECONDS_PER_MILLISECOND + (milliseconds % MILLISECONDS_PER_SECOND).toIntUnchecked() * NANOSECONDS_PER_MILLISECOND ) } + /** + * Returns this instant with [microseconds] added to it. + */ override operator fun plus(microseconds: Microseconds): Instant { return plus( microseconds.inWholeSeconds.toLong(), - (microseconds.value % MICROSECONDS_PER_SECOND).toInt() * NANOSECONDS_PER_MICROSECOND + (microseconds % MICROSECONDS_PER_SECOND).toIntUnchecked() * NANOSECONDS_PER_MICROSECOND ) } + /** + * Returns this instant with [nanoseconds] added to it. + */ override operator fun plus(nanoseconds: Nanoseconds): Instant { return plus( nanoseconds.inWholeSeconds.toLong(), @@ -80,6 +104,9 @@ class Instant private constructor( } } + /** + * Returns this instant with a number of 24-hour [days] subtracted from it. + */ operator fun minus(days: Days): Instant { return if (days.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.days + 1.days @@ -88,6 +115,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [hours] subtracted from it. + */ override operator fun minus(hours: Hours): Instant { return if (hours.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.hours + 1.hours @@ -96,6 +126,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [minutes] subtracted from it. + */ override operator fun minus(minutes: Minutes): Instant { return if (minutes.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.minutes + 1.minutes @@ -104,6 +137,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [seconds] subtracted from it. + */ override operator fun minus(seconds: Seconds): Instant { return if (seconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.seconds + 1.seconds @@ -112,6 +148,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [milliseconds] subtracted from it. + */ override operator fun minus(milliseconds: Milliseconds): Instant { return if (milliseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.milliseconds + 1.milliseconds @@ -120,6 +159,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [microseconds] subtracted from it. + */ override operator fun minus(microseconds: Microseconds): Instant { return if (microseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.microseconds + 1.microseconds @@ -128,6 +170,9 @@ class Instant private constructor( } } + /** + * Returns this instant with [nanoseconds] subtracted from it. + */ override operator fun minus(nanoseconds: Nanoseconds): Instant { return if (nanoseconds.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.nanoseconds + 1.nanoseconds diff --git a/core/src/commonMain/kotlin/io/islandtime/Month.kt b/core/src/commonMain/kotlin/io/islandtime/Month.kt index 27d37d0a3..4feea1132 100644 --- a/core/src/commonMain/kotlin/io/islandtime/Month.kt +++ b/core/src/commonMain/kotlin/io/islandtime/Month.kt @@ -30,7 +30,7 @@ enum class Month { val number: Int get() = ordinal + 1 /** - * Returns the last day of the month in a common year. + * The last day of the month in a common year. */ val lastDayInCommonYear: Int get() = when (this) { @@ -40,7 +40,7 @@ enum class Month { } /** - * Returns the last day of the month in a leap year. + * The last day of the month in a leap year. */ val lastDayInLeapYear: Int get() = when (this) { @@ -86,7 +86,7 @@ enum class Month { val lengthInCommonYear: Days get() = lastDayInCommonYear.days /** - * The number of days in the month in a leap month. + * The number of days in the month in a leap year. */ val lengthInLeapYear: Days get() = lastDayInLeapYear.days @@ -119,7 +119,7 @@ enum class Month { } /** - * Returns the last day of the month in a particular year. + * Returns the last day of the month in [year]. */ fun lastDayIn(year: Int): Int = when (this) { FEBRUARY -> if (isLeapYear(year)) 29 else 28 @@ -127,7 +127,7 @@ enum class Month { } /** - * Returns the number of days in the month for a particular year. + * Returns the number of days in the month in [year]. * @param year retrieve the length of the month within this year * @return the number of days in the month */ @@ -167,12 +167,12 @@ enum class Month { fun dayRangeIn(year: Int): IntRange = 1..lastDayIn(year) /** - * Adds months to this month, wrapping when the beginning or end of the year is reached. + * Returns this month with [months] added to it, wrapping when the beginning or end of the year is reached. */ operator fun plus(months: Months): Month = plus((months.value % 12).toInt()) /** - * Subtracts months from this month, wrapping when the beginning or end of the year is reached. + * Returns this month with [months] subtracted from it, wrapping when the beginning or end of the year is reached. */ operator fun minus(months: Months): Month = plus(-(months.value % 12).toInt()) diff --git a/core/src/commonMain/kotlin/io/islandtime/OffsetDateTime.kt b/core/src/commonMain/kotlin/io/islandtime/OffsetDateTime.kt index e05e818c5..e66adbad3 100644 --- a/core/src/commonMain/kotlin/io/islandtime/OffsetDateTime.kt +++ b/core/src/commonMain/kotlin/io/islandtime/OffsetDateTime.kt @@ -166,7 +166,7 @@ class OffsetDateTime( get() = dateTime.millisecondOfUnixEpochAt(offset) /** - * Changes the offset of this [OffsetDateTime], adjusting the date and time components such that the instant + * Returns this date-time with a new UTC offset, adjusting the date and time components such that the instant * represented by it remains the same. */ fun adjustedTo(newOffset: UtcOffset): OffsetDateTime { @@ -188,36 +188,134 @@ class OffsetDateTime( operator fun plus(duration: Duration): OffsetDateTime = copy(dateTime = dateTime + duration) + /** + * Returns this date-tme with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): OffsetDateTime = copy(dateTime = dateTime + centuries) + + /** + * Returns this date-time with [decades] added to it. + */ + operator fun plus(decades: Decades): OffsetDateTime = copy(dateTime = dateTime + decades) + + /** + * Returns this date-time with [years] added to it. + */ operator fun plus(years: Years): OffsetDateTime = copy(dateTime = dateTime + years) + + /** + * Returns this date-time with [months] added to it. + */ operator fun plus(months: Months): OffsetDateTime = copy(dateTime = dateTime + months) + + /** + * Returns this date-time with [weeks] added to it. + */ operator fun plus(weeks: Weeks): OffsetDateTime = copy(dateTime = dateTime + weeks) + + /** + * Returns this date-time with [days] added to it. + */ operator fun plus(days: Days): OffsetDateTime = copy(dateTime = dateTime + days) + + /** + * Returns this date-time with [hours] added to it. + */ override operator fun plus(hours: Hours): OffsetDateTime = copy(dateTime = dateTime + hours) + + /** + * Returns this date-time with [minutes] added to it. + */ override operator fun plus(minutes: Minutes): OffsetDateTime = copy(dateTime = dateTime + minutes) + + /** + * Returns this date-time with [seconds] added to it. + */ override operator fun plus(seconds: Seconds): OffsetDateTime = copy(dateTime = dateTime + seconds) + + /** + * Returns this date-time with [milliseconds] added to it. + */ override operator fun plus(milliseconds: Milliseconds): OffsetDateTime = copy(dateTime = dateTime + milliseconds) + + /** + * Returns this date-time with [microseconds] added to it. + */ override operator fun plus(microseconds: Microseconds): OffsetDateTime = copy(dateTime = dateTime + microseconds) + + /** + * Returns this date-time with [nanoseconds] added to it. + */ override operator fun plus(nanoseconds: Nanoseconds): OffsetDateTime = copy(dateTime = dateTime + nanoseconds) /** * Returns this date-time with [period] subtracted from it. * - * Years are added first, then months, then days. If the day exceeds the maximum month length at any step, it will - * be coerced into the valid range. + * Years are subtracted first, then months, then days. If the day exceeds the maximum month length at any step, it + * will be coerced into the valid range. */ operator fun minus(period: Period): OffsetDateTime = copy(dateTime = dateTime - period) operator fun minus(duration: Duration): OffsetDateTime = copy(dateTime = dateTime - duration) + /** + * Returns this date-time with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): OffsetDateTime = copy(dateTime = dateTime - centuries) + + /** + * Returns this date-time with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): OffsetDateTime = copy(dateTime = dateTime - decades) + + /** + * Returns this date-time with [years] subtracted from it. + */ operator fun minus(years: Years): OffsetDateTime = copy(dateTime = dateTime - years) + + /** + * Returns this date-time with [months] subtracted from it. + */ operator fun minus(months: Months): OffsetDateTime = copy(dateTime = dateTime - months) + + /** + * Returns this date-time with [weeks] subtracted from it. + */ operator fun minus(weeks: Weeks): OffsetDateTime = copy(dateTime = dateTime - weeks) + + /** + * Returns this date-time with [days] subtracted from it. + */ operator fun minus(days: Days): OffsetDateTime = copy(dateTime = dateTime - days) + + /** + * Returns this date-time with [hours] subtracted from it. + */ override operator fun minus(hours: Hours): OffsetDateTime = copy(dateTime = dateTime - hours) + + /** + * Returns this date-time with [minutes] subtracted from it. + */ override operator fun minus(minutes: Minutes): OffsetDateTime = copy(dateTime = dateTime - minutes) + + /** + * Returns this date-time with [seconds] subtracted from it. + */ override operator fun minus(seconds: Seconds): OffsetDateTime = copy(dateTime = dateTime - seconds) + + /** + * Returns this date-time with [milliseconds] subtracted from it. + */ override operator fun minus(milliseconds: Milliseconds): OffsetDateTime = copy(dateTime = dateTime - milliseconds) + + /** + * Returns this date-time with [microseconds] subtracted from it. + */ override operator fun minus(microseconds: Microseconds): OffsetDateTime = copy(dateTime = dateTime - microseconds) + + /** + * Returns this date-time with [nanoseconds] subtracted from it. + */ override operator fun minus(nanoseconds: Nanoseconds): OffsetDateTime = copy(dateTime = dateTime - nanoseconds) operator fun rangeTo(other: OffsetDateTime): OffsetDateTimeInterval = diff --git a/core/src/commonMain/kotlin/io/islandtime/OffsetTime.kt b/core/src/commonMain/kotlin/io/islandtime/OffsetTime.kt index dce78bc6c..997153574 100644 --- a/core/src/commonMain/kotlin/io/islandtime/OffsetTime.kt +++ b/core/src/commonMain/kotlin/io/islandtime/OffsetTime.kt @@ -68,19 +68,67 @@ class OffsetTime( } operator fun plus(duration: Duration): OffsetTime = copy(time = time + duration) + + /** + * Returns this time with [hours] added to it. + */ operator fun plus(hours: Hours): OffsetTime = copy(time = time + hours) + + /** + * Returns this time with [minutes] added to it. + */ operator fun plus(minutes: Minutes): OffsetTime = copy(time = time + minutes) + + /** + * Returns this time with [seconds] added to it. + */ operator fun plus(seconds: Seconds): OffsetTime = copy(time = time + seconds) + + /** + * Returns this time with [milliseconds] added to it. + */ operator fun plus(milliseconds: Milliseconds): OffsetTime = copy(time = time + milliseconds) + + /** + * Returns this time with [microseconds] added to it. + */ operator fun plus(microseconds: Microseconds): OffsetTime = copy(time = time + microseconds) + + /** + * Returns this time with [nanoseconds] added to it. + */ operator fun plus(nanoseconds: Nanoseconds): OffsetTime = copy(time = time + nanoseconds) operator fun minus(duration: Duration): OffsetTime = copy(time = time - duration) + + /** + * Returns this time with [hours] subtracted from it. + */ operator fun minus(hours: Hours): OffsetTime = copy(time = time - hours) + + /** + * Returns this time with [minutes] subtracted from it. + */ operator fun minus(minutes: Minutes): OffsetTime = copy(time = time - minutes) + + /** + * Returns this time with [seconds] subtracted from it. + */ operator fun minus(seconds: Seconds): OffsetTime = copy(time = time - seconds) + + /** + * Returns this time with [milliseconds] subtracted from it. + */ operator fun minus(milliseconds: Milliseconds): OffsetTime = copy(time = time - milliseconds) + + /** + * Returns this time with [microseconds] subtracted from it. + */ operator fun minus(microseconds: Microseconds): OffsetTime = copy(time = time - microseconds) + + /** + * Returns this time with [nanoseconds] subtracted from it. + */ operator fun minus(nanoseconds: Nanoseconds): OffsetTime = copy(time = time - nanoseconds) /** diff --git a/core/src/commonMain/kotlin/io/islandtime/Time.kt b/core/src/commonMain/kotlin/io/islandtime/Time.kt index bd8ac2a0b..516f68344 100644 --- a/core/src/commonMain/kotlin/io/islandtime/Time.kt +++ b/core/src/commonMain/kotlin/io/islandtime/Time.kt @@ -78,6 +78,9 @@ class Time( return this + duration.seconds + duration.nanosecondAdjustment } + /** + * Returns this time with [hours] added to it. + */ operator fun plus(hours: Hours): Time { val wrappedHours = (hours % HOURS_PER_DAY).toInt() @@ -89,6 +92,9 @@ class Time( } } + /** + * Returns this time with [minutes] added to it. + */ operator fun plus(minutes: Minutes): Time { return if (minutes.value == 0L) { this @@ -107,6 +113,9 @@ class Time( } } + /** + * Returns this time with [seconds] added to it. + */ operator fun plus(seconds: Seconds): Time { return if (seconds.value == 0L) { this @@ -123,14 +132,23 @@ class Time( } } + /** + * Returns this time with [milliseconds] added to it. + */ operator fun plus(milliseconds: Milliseconds): Time { return plusWrapped((milliseconds % MILLISECONDS_PER_DAY).inNanosecondsUnchecked) } + /** + * Returns this time with [microseconds] added to it. + */ operator fun plus(microseconds: Microseconds): Time { return plusWrapped((microseconds % MICROSECONDS_PER_DAY).inNanosecondsUnchecked) } + /** + * Returns this time with [nanoseconds] added to it. + */ operator fun plus(nanoseconds: Nanoseconds): Time = plusWrapped(nanoseconds % NANOSECONDS_PER_DAY) private fun plusWrapped(wrappedNanos: Nanoseconds): Time { @@ -146,18 +164,38 @@ class Time( return this - duration.seconds - duration.nanosecondAdjustment } + /** + * Returns this time with [hours] subtracted from it. + */ operator fun minus(hours: Hours): Time = plus((hours % HOURS_PER_DAY).negateUnchecked()) + + /** + * Returns this time with [minutes] subtracted from it. + */ operator fun minus(minutes: Minutes): Time = plus((minutes % MINUTES_PER_DAY).negateUnchecked()) + + /** + * Returns this time with [seconds] subtracted from it. + */ operator fun minus(seconds: Seconds): Time = plus((seconds % SECONDS_PER_DAY).negateUnchecked()) + /** + * Returns this time with [milliseconds] subtracted from it. + */ operator fun minus(milliseconds: Milliseconds): Time { return plusWrapped((milliseconds % MILLISECONDS_PER_DAY).inNanosecondsUnchecked.negateUnchecked()) } + /** + * Returns this time with [microseconds] subtracted from it. + */ operator fun minus(microseconds: Microseconds): Time { return plusWrapped((microseconds % MICROSECONDS_PER_DAY).inNanosecondsUnchecked.negateUnchecked()) } + /** + * Returns this time with [nanoseconds] subtracted from it. + */ operator fun minus(nanoseconds: Nanoseconds): Time { return plusWrapped((nanoseconds % NANOSECONDS_PER_DAY).negateUnchecked()) } diff --git a/core/src/commonMain/kotlin/io/islandtime/Year.kt b/core/src/commonMain/kotlin/io/islandtime/Year.kt index 177b51e14..6067d5f11 100644 --- a/core/src/commonMain/kotlin/io/islandtime/Year.kt +++ b/core/src/commonMain/kotlin/io/islandtime/Year.kt @@ -2,10 +2,7 @@ package io.islandtime import io.islandtime.base.DateTimeField import io.islandtime.internal.toZeroPaddedString -import io.islandtime.measures.Days -import io.islandtime.measures.Years -import io.islandtime.measures.days -import io.islandtime.measures.years +import io.islandtime.measures.* import io.islandtime.parser.* import io.islandtime.ranges.DateRange import kotlin.jvm.JvmInline @@ -68,10 +65,34 @@ value class Year(val value: Int) : Comparable { */ val endDate: Date get() = Date(value, Month.DECEMBER, 31) - operator fun plus(years: Years): Year { - return Year(value + years.value) - } + /** + * Returns this year with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): Year = plus(centuries.inYears) + + /** + * Returns this year with [decades] added to it. + */ + operator fun plus(decades: Decades): Year = plus(decades.inYears) + + /** + * Returns this year with [years] added to it. + */ + operator fun plus(years: Years): Year = Year(value + years.value) + + /** + * Returns this year with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): Year = minus(centuries.inYears) + + /** + * Returns this year with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): Year = minus(decades.inYears) + /** + * Returns this year with [years] subtracted from it. + */ operator fun minus(years: Years): Year { return if (years.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.years + 1L.years @@ -80,7 +101,14 @@ value class Year(val value: Int) : Comparable { } } + /** + * Checks if this year contains the specified year-month. + */ operator fun contains(yearMonth: YearMonth): Boolean = yearMonth.year == value + + /** + * Checks if this year contains the specified date. + */ operator fun contains(date: Date): Boolean = date.year == value override fun compareTo(other: Year): Int = value - other.value diff --git a/core/src/commonMain/kotlin/io/islandtime/YearMonth.kt b/core/src/commonMain/kotlin/io/islandtime/YearMonth.kt index 14dda0d85..4347f7b07 100644 --- a/core/src/commonMain/kotlin/io/islandtime/YearMonth.kt +++ b/core/src/commonMain/kotlin/io/islandtime/YearMonth.kt @@ -133,6 +133,19 @@ class YearMonth( */ fun copy(year: Int = this.year, monthNumber: Int): YearMonth = YearMonth(year, monthNumber) + /** + * Returns this year-month with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): YearMonth = plus(centuries.inYears) + + /** + * Returns this year-month with [decades] added to it. + */ + operator fun plus(decades: Decades): YearMonth = plus(decades.inYears) + + /** + * Returns this year-month with [years] added to it. + */ operator fun plus(years: Years): YearMonth { return if (years.value == 0L) { this @@ -142,6 +155,9 @@ class YearMonth( } } + /** + * Returns this year-month with [months] added to it. + */ operator fun plus(months: Months): YearMonth { return if (months.value == 0L) { this @@ -153,6 +169,19 @@ class YearMonth( } } + /** + * Returns this year-month with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): YearMonth = minus(centuries.inYears) + + /** + * Returns this year-month with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): YearMonth = minus(decades.inYears) + + /** + * Returns this year-month with [years] subtracted from it. + */ operator fun minus(years: Years): YearMonth { return if (years.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.years + 1L.years @@ -161,6 +190,9 @@ class YearMonth( } } + /** + * Returns this year-month with [months] subtracted from it. + */ operator fun minus(months: Months): YearMonth { return if (months.value == Long.MIN_VALUE) { this + Long.MAX_VALUE.months + 1L.months @@ -169,6 +201,9 @@ class YearMonth( } } + /** + * Checks if this year contains the specified date. + */ operator fun contains(date: Date): Boolean = date.year == year && date.month == month companion object { diff --git a/core/src/commonMain/kotlin/io/islandtime/ZonedDateTime.kt b/core/src/commonMain/kotlin/io/islandtime/ZonedDateTime.kt index 0c6682336..4326a509a 100644 --- a/core/src/commonMain/kotlin/io/islandtime/ZonedDateTime.kt +++ b/core/src/commonMain/kotlin/io/islandtime/ZonedDateTime.kt @@ -153,46 +153,140 @@ class ZonedDateTime private constructor( operator fun plus(period: Period): ZonedDateTime = copy(dateTime = dateTime + period) operator fun plus(duration: Duration): ZonedDateTime = resolveInstant(dateTime + duration) + + /** + * Returns this date-tme with [centuries] added to it. + */ + operator fun plus(centuries: Centuries): ZonedDateTime = copy(dateTime = dateTime + centuries) + + /** + * Returns this date-time with [decades] added to it. + */ + operator fun plus(decades: Decades): ZonedDateTime = copy(dateTime = dateTime + decades) + + /** + * Returns this date-time with [years] added to it. + */ operator fun plus(years: Years): ZonedDateTime = copy(dateTime = dateTime + years) + + /** + * Returns this date-time with [months] added to it. + */ operator fun plus(months: Months): ZonedDateTime = copy(dateTime = dateTime + months) + + /** + * Returns this date-time with [weeks] added to it. + */ operator fun plus(weeks: Weeks): ZonedDateTime = copy(dateTime = dateTime + weeks) + + /** + * Returns this date-time with [days] added to it. + */ operator fun plus(days: Days): ZonedDateTime = copy(dateTime = dateTime + days) + + /** + * Returns this date-time with [hours] added to it. + */ override operator fun plus(hours: Hours): ZonedDateTime = resolveInstant(dateTime + hours) + + /** + * Returns this date-time with [minutes] added to it. + */ override operator fun plus(minutes: Minutes): ZonedDateTime = resolveInstant(dateTime + minutes) + + /** + * Returns this date-time with [seconds] added to it. + */ override operator fun plus(seconds: Seconds): ZonedDateTime = resolveInstant(dateTime + seconds) + /** + * Returns this date-time with [milliseconds] added to it. + */ override operator fun plus(milliseconds: Milliseconds): ZonedDateTime = resolveInstant(dateTime + milliseconds) + /** + * Returns this date-time with [microseconds] added to it. + */ override operator fun plus(microseconds: Microseconds): ZonedDateTime = resolveInstant(dateTime + microseconds) + /** + * Returns this date-time with [nanoseconds] added to it. + */ override operator fun plus(nanoseconds: Nanoseconds): ZonedDateTime = resolveInstant(dateTime + nanoseconds) /** * Returns this date-time with [period] subtracted from it. * - * Years are added first, then months, then days. If the day exceeds the maximum month length at any step, it will - * be coerced into the valid range. + * Years are subtracted first, then months, then days. If the day exceeds the maximum month length at any step, it + * will be coerced into the valid range. */ operator fun minus(period: Period): ZonedDateTime = copy(dateTime = dateTime - period) operator fun minus(duration: Duration): ZonedDateTime = resolveInstant(dateTime - duration) + + /** + * Returns this date-time with [centuries] subtracted from it. + */ + operator fun minus(centuries: Centuries): ZonedDateTime = copy(dateTime = dateTime - centuries) + + /** + * Returns this date-time with [decades] subtracted from it. + */ + operator fun minus(decades: Decades): ZonedDateTime = copy(dateTime = dateTime - decades) + + /** + * Returns this date-time with [years] subtracted from it. + */ operator fun minus(years: Years): ZonedDateTime = copy(dateTime = dateTime - years) + + /** + * Returns this date-time with [months] subtracted from it. + */ operator fun minus(months: Months): ZonedDateTime = copy(dateTime = dateTime - months) + + /** + * Returns this date-time with [weeks] subtracted from it. + */ operator fun minus(weeks: Weeks): ZonedDateTime = copy(dateTime = dateTime - weeks) + + /** + * Returns this date-time with [days] subtracted from it. + */ operator fun minus(days: Days): ZonedDateTime = copy(dateTime = dateTime - days) + + /** + * Returns this date-time with [hours] subtracted from it. + */ override operator fun minus(hours: Hours): ZonedDateTime = resolveInstant(dateTime - hours) + + /** + * Returns this date-time with [minutes] subtracted from it. + */ override operator fun minus(minutes: Minutes): ZonedDateTime = resolveInstant(dateTime - minutes) + + /** + * Returns this date-time with [seconds] subtracted from it. + */ override operator fun minus(seconds: Seconds): ZonedDateTime = resolveInstant(dateTime - seconds) + /** + * Returns this date-time with [milliseconds] subtracted from it. + */ override operator fun minus(milliseconds: Milliseconds): ZonedDateTime = resolveInstant(dateTime - milliseconds) + /** + * Returns this date-time with [microseconds] subtracted from it. + */ override operator fun minus(microseconds: Microseconds): ZonedDateTime = resolveInstant(dateTime - microseconds) + /** + * Returns this date-time with [nanoseconds] subtracted from it. + */ override operator fun minus(nanoseconds: Nanoseconds): ZonedDateTime = resolveInstant(dateTime - nanoseconds) diff --git a/core/src/commonTest/kotlin/io/islandtime/DateTest.kt b/core/src/commonTest/kotlin/io/islandtime/DateTest.kt index 8813721e4..f207f42d9 100644 --- a/core/src/commonTest/kotlin/io/islandtime/DateTest.kt +++ b/core/src/commonTest/kotlin/io/islandtime/DateTest.kt @@ -3,7 +3,10 @@ package io.islandtime import io.islandtime.measures.* import io.islandtime.parser.* import io.islandtime.test.AbstractIslandTimeTest -import kotlin.test.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue class DateTest : AbstractIslandTimeTest() { @Test @@ -177,7 +180,6 @@ class DateTest : AbstractIslandTimeTest() { fun `add zero days`() { val date = Date(2019, Month.JANUARY, 1) assertEquals(date, date + 0.days) - assertEquals(date, date + 0L.days) } @Test @@ -196,11 +198,6 @@ class DateTest : AbstractIslandTimeTest() { Date(1970, Month.MARCH, 1), Date(1969, Month.MARCH, 1) + 365.days ) - - assertEquals( - Date(1970, Month.MARCH, 1), - Date(1969, Month.MARCH, 1) + 365L.days - ) } @Test @@ -225,7 +222,6 @@ class DateTest : AbstractIslandTimeTest() { fun `subtract zero days`() { val date = Date(2019, Month.JANUARY, 1) assertEquals(date, date - 0.days) - assertEquals(date, date - 0L.days) } @Test @@ -302,11 +298,6 @@ class DateTest : AbstractIslandTimeTest() { Date(1930, Month.JANUARY, 28), Date(1930, Month.JANUARY, 28) + 0.weeks ) - - assertEquals( - Date(2030, Month.JANUARY, 28), - Date(2030, Month.JANUARY, 28) + 0L.weeks - ) } @Test @@ -315,11 +306,6 @@ class DateTest : AbstractIslandTimeTest() { Date(1930, Month.JANUARY, 28), Date(1930, Month.JANUARY, 28) - 0.weeks ) - - assertEquals( - Date(2030, Month.JANUARY, 28), - Date(2030, Month.JANUARY, 28) - 0L.weeks - ) } @Test @@ -346,11 +332,6 @@ class DateTest : AbstractIslandTimeTest() { Date(2019, Month.FEBRUARY, 4), Date(2019, Month.JANUARY, 28) + 1.weeks ) - - assertEquals( - Date(2019, Month.FEBRUARY, 4), - Date(2019, Month.JANUARY, 28) + 1L.weeks - ) } @Test @@ -359,11 +340,6 @@ class DateTest : AbstractIslandTimeTest() { Date(2019, Month.JANUARY, 21), Date(2019, Month.JANUARY, 28) + (-1).weeks ) - - assertEquals( - Date(2019, Month.JANUARY, 21), - Date(2019, Month.JANUARY, 28) + (-1L).weeks - ) } @Test @@ -372,11 +348,6 @@ class DateTest : AbstractIslandTimeTest() { Date(2019, Month.JANUARY, 21), Date(2019, Month.JANUARY, 28) - 1.weeks ) - - assertEquals( - Date(2019, Month.JANUARY, 21), - Date(2019, Month.JANUARY, 28) - 1L.weeks - ) } @Test @@ -385,11 +356,6 @@ class DateTest : AbstractIslandTimeTest() { Date(2019, Month.FEBRUARY, 4), Date(2019, Month.JANUARY, 28) - (-1).weeks ) - - assertEquals( - Date(2019, Month.FEBRUARY, 4), - Date(2019, Month.JANUARY, 28) - (-1L).weeks - ) } @Test @@ -410,7 +376,6 @@ class DateTest : AbstractIslandTimeTest() { fun `add zero months`() { val date = Date(2019, Month.JANUARY, 28) assertEquals(date, date + 0.months) - assertEquals(date, date + 0L.months) } @Test @@ -463,7 +428,6 @@ class DateTest : AbstractIslandTimeTest() { fun `subtract zero months`() { val date = Date(2019, Month.JANUARY, 28) assertEquals(date, date - 0.months) - assertEquals(date, date - 0L.months) } @Test @@ -520,7 +484,6 @@ class DateTest : AbstractIslandTimeTest() { fun `add zero years`() { val date = Date(2019, Month.JANUARY, 28) assertEquals(date, date + 0.years) - assertEquals(date, date + 0L.years) } @Test @@ -563,7 +526,6 @@ class DateTest : AbstractIslandTimeTest() { fun `subtract zero years`() { val date = Date(2019, Month.JANUARY, 28) assertEquals(date, date - 0.years) - assertEquals(date, date - 0L.years) } @Test @@ -602,6 +564,122 @@ class DateTest : AbstractIslandTimeTest() { ) } + @Test + fun `throws an exception when adding or subtracting decades puts the date out of range`() { + assertFailsWith { Date.MAX + 1.decades } + assertFailsWith { Date.MIN - 1.decades } + } + + @Test + fun `throws an exception when adding or subtracting decades causes overflow`() { + assertFailsWith { Date(9999, Month.JANUARY, 28) + Long.MAX_VALUE.decades } + assertFailsWith { Date(1, Month.JANUARY, 28) + Long.MIN_VALUE.decades } + assertFailsWith { Date(9999, Month.JANUARY, 28) - Long.MAX_VALUE.decades } + assertFailsWith { Date(1, Month.JANUARY, 28) - Long.MIN_VALUE.decades } + } + + @Test + fun `add zero decades`() { + val date = Date(2019, Month.JANUARY, 28) + assertEquals(date, date + 0.decades) + } + + @Test + fun `add positive decades`() { + assertEquals( + Date(2030, Month.FEBRUARY, 28), + Date(2020, Month.FEBRUARY, 29) + 1.decades + ) + } + + @Test + fun `add negative decades`() { + assertEquals( + Date(2009, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) + (-1).decades + ) + } + + @Test + fun `subtract zero decades`() { + val date = Date(2019, Month.JANUARY, 28) + assertEquals(date, date - 0.decades) + } + + @Test + fun `subtract positive decades`() { + assertEquals( + Date(2009, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) - 1.decades + ) + } + + @Test + fun `subtract negative decades`() { + assertEquals( + Date(2029, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) - (-1).decades + ) + } + + @Test + fun `throws an exception when adding or subtracting centuries puts the date out of range`() { + assertFailsWith { Date.MAX + 1.centuries } + assertFailsWith { Date.MIN - 1.centuries } + } + + @Test + fun `throws an exception when adding or subtracting centuries causes overflow`() { + assertFailsWith { Date(9999, Month.JANUARY, 28) + Long.MAX_VALUE.centuries } + assertFailsWith { Date(1, Month.JANUARY, 28) + Long.MIN_VALUE.centuries } + assertFailsWith { Date(9999, Month.JANUARY, 28) - Long.MAX_VALUE.centuries } + assertFailsWith { Date(1, Month.JANUARY, 28) - Long.MIN_VALUE.centuries } + } + + @Test + fun `add zero centuries`() { + val date = Date(2019, Month.JANUARY, 28) + assertEquals(date, date + 0.centuries) + } + + @Test + fun `add positive centuries`() { + assertEquals( + Date(2119, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) + 1.centuries + ) + } + + @Test + fun `add negative centuries`() { + assertEquals( + Date(1919, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) + (-1).centuries + ) + } + + @Test + fun `subtract zero centuries`() { + val date = Date(2019, Month.JANUARY, 28) + assertEquals(date, date - 0.centuries) + } + + @Test + fun `subtract positive centuries`() { + assertEquals( + Date(1919, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) - 1.centuries + ) + } + + @Test + fun `subtract negative centuries`() { + assertEquals( + Date(2119, Month.JANUARY, 31), + Date(2019, Month.JANUARY, 31) - (-1).centuries + ) + } + @Test fun `daysSinceUnixEpoch property works correctly`() { assertEquals(0L.days, Date(1970, Month.JANUARY, 1).daysSinceUnixEpoch) diff --git a/core/src/commonTest/kotlin/io/islandtime/DateTimeTest.kt b/core/src/commonTest/kotlin/io/islandtime/DateTimeTest.kt index 65c4fa0ce..9bf10f111 100644 --- a/core/src/commonTest/kotlin/io/islandtime/DateTimeTest.kt +++ b/core/src/commonTest/kotlin/io/islandtime/DateTimeTest.kt @@ -301,6 +301,8 @@ class DateTimeTest : AbstractIslandTimeTest() { @Test fun `throws an exception when addition puts the date-time out of range`() { listOf( + { DateTime.MIN + (-1).centuries }, + { DateTime.MIN + (-1).decades }, { DateTime.MIN + (-1).years }, { DateTime.MIN + (-1).months }, { DateTime.MIN + (-1).weeks }, @@ -311,6 +313,8 @@ class DateTimeTest : AbstractIslandTimeTest() { { DateTime.MIN + (-1).milliseconds }, { DateTime.MIN + (-1).microseconds }, { DateTime.MIN + (-1).nanoseconds }, + { DateTime.MAX + 1.centuries }, + { DateTime.MAX + 1.decades }, { DateTime.MAX + 1.years }, { DateTime.MAX + 1.months }, { DateTime.MAX + 1.weeks }, @@ -335,6 +339,8 @@ class DateTimeTest : AbstractIslandTimeTest() { @Test fun `throws an exception when subtraction puts the date-time out of range`() { listOf( + { DateTime.MIN - 1.centuries }, + { DateTime.MIN - 1.decades }, { DateTime.MIN - 1.years }, { DateTime.MIN - 1.months }, { DateTime.MIN - 1.weeks }, @@ -345,6 +351,8 @@ class DateTimeTest : AbstractIslandTimeTest() { { DateTime.MIN - 1.milliseconds }, { DateTime.MIN - 1.microseconds }, { DateTime.MIN - 1.nanoseconds }, + { DateTime.MAX - (-1).centuries }, + { DateTime.MAX - (-1).decades }, { DateTime.MAX - (-1).years }, { DateTime.MAX - (-1).months }, { DateTime.MAX - (-1).weeks }, @@ -367,76 +375,143 @@ class DateTimeTest : AbstractIslandTimeTest() { } @Test - fun `adding or subtracting zero years has no effect`() { + fun `adding or subtracting zero centuries has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + assertEquals(date, date + 0.centuries) + assertEquals(date, date - 0.centuries) + } - listOf( - { date + 0.years }, - { date + 0L.years }, - { date - 0.years }, - { date - 0L.years } - ).forEach { - assertEquals(date, it()) - } + @Test + fun `add positive centuries`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + + assertEquals( + Date(2469, Month.DECEMBER, 1) at Time.NOON, + date + 5.centuries + ) } @Test - fun `add positive years`() { + fun `add negative centuries`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1974, Month.DECEMBER, 1) at Time.NOON, - date + 5.years + Date(1469, Month.DECEMBER, 1) at Time.NOON, + date + (-5).centuries ) + } + + @Test + fun `subtract positive centuries`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1974, Month.DECEMBER, 1) at Time.NOON, - date + 5L.years + Date(1469, Month.DECEMBER, 1) at Time.NOON, + date - 5.centuries ) } @Test - fun `add negative years`() { + fun `subtract negative centuries`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1964, Month.DECEMBER, 1) at Time.NOON, - date + (-5).years + Date(2469, Month.DECEMBER, 1) at Time.NOON, + date - (-5).centuries ) + } + + @Test + fun `adding or subtracting zero decades has no effect`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + assertEquals(date, date + 0.decades) + assertEquals(date, date - 0.decades) + } + + @Test + fun `add positive decades`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1964, Month.DECEMBER, 1) at Time.NOON, - date + (-5L).years + Date(2019, Month.DECEMBER, 1) at Time.NOON, + date + 5.decades ) } @Test - fun `subtract positive years`() { + fun `add negative decades`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1964, Month.DECEMBER, 1) at Time.NOON, - date - 5.years + Date(1919, Month.DECEMBER, 1) at Time.NOON, + date + (-5).decades ) + } + + @Test + fun `subtract positive decades`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( - Date(1964, Month.DECEMBER, 1) at Time.NOON, - date - 5L.years + Date(1919, Month.DECEMBER, 1) at Time.NOON, + date - 5.decades ) } @Test - fun `subtract negative years`() { + fun `subtract negative decades`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + + assertEquals( + Date(2019, Month.DECEMBER, 1) at Time.NOON, + date - (-5).decades + ) + } + + @Test + fun `adding or subtracting zero years has no effect`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + assertEquals(date, date + 0.years) + assertEquals(date, date - 0.years) + } + + @Test + fun `add positive years`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( Date(1974, Month.DECEMBER, 1) at Time.NOON, - date - (-5).years + date + 5.years + ) + } + + @Test + fun `add negative years`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + + assertEquals( + Date(1964, Month.DECEMBER, 1) at Time.NOON, + date + (-5).years ) + } + + @Test + fun `subtract positive years`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON + + assertEquals( + Date(1964, Month.DECEMBER, 1) at Time.NOON, + date - 5.years + ) + } + + @Test + fun `subtract negative years`() { + val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals( Date(1974, Month.DECEMBER, 1) at Time.NOON, - date - (-5L).years + date - (-5).years ) } @@ -444,9 +519,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero months has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.months) - assertEquals(date, date + 0L.months) assertEquals(date, date - 0.months) - assertEquals(date, date - 0L.months) } @Test @@ -457,11 +530,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1970, Month.MAY, 1) at Time.NOON, date + 5.months ) - - assertEquals( - Date(1970, Month.MAY, 1) at Time.NOON, - date + 5L.months - ) } @Test @@ -472,11 +540,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.JULY, 1) at Time.NOON, date + (-5).months ) - - assertEquals( - Date(1969, Month.JULY, 1) at Time.NOON, - date + (-5L).months - ) } @Test @@ -487,11 +550,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.JULY, 1) at Time.NOON, date - 5.months ) - - assertEquals( - Date(1969, Month.JULY, 1) at Time.NOON, - date - 5L.months - ) } @Test @@ -502,20 +560,13 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1970, Month.MAY, 1) at Time.NOON, date - (-5).months ) - - assertEquals( - Date(1970, Month.MAY, 1) at Time.NOON, - date - (-5L).months - ) } @Test fun `adding or subtracting zero weeks has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.weeks) - assertEquals(date, date + 0L.weeks) assertEquals(date, date - 0.weeks) - assertEquals(date, date - 0L.weeks) } @Test @@ -526,11 +577,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1970, Month.JANUARY, 5) at Time.NOON, date + 5.weeks ) - - assertEquals( - Date(1970, Month.JANUARY, 5) at Time.NOON, - date + 5L.weeks - ) } @Test @@ -541,11 +587,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.OCTOBER, 27) at Time.NOON, date + (-5).weeks ) - - assertEquals( - Date(1969, Month.OCTOBER, 27) at Time.NOON, - date + (-5L).weeks - ) } @Test @@ -556,11 +597,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.OCTOBER, 27) at Time.NOON, date - 5.weeks ) - - assertEquals( - Date(1969, Month.OCTOBER, 27) at Time.NOON, - date - 5L.weeks - ) } @Test @@ -571,20 +607,13 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1970, Month.JANUARY, 5) at Time.NOON, date - (-5).weeks ) - - assertEquals( - Date(1970, Month.JANUARY, 5) at Time.NOON, - date - (-5L).weeks - ) } @Test fun `adding or subtracting zero days has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.days) - assertEquals(date, date + 0L.days) assertEquals(date, date - 0.days) - assertEquals(date, date - 0L.days) } @Test @@ -595,11 +624,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.DECEMBER, 6) at Time.NOON, date + 5.days ) - - assertEquals( - Date(1969, Month.DECEMBER, 6) at Time.NOON, - date + 5L.days - ) } @Test @@ -610,11 +634,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.NOVEMBER, 26) at Time.NOON, date + (-5).days ) - - assertEquals( - Date(1969, Month.NOVEMBER, 26) at Time.NOON, - date + (-5L).days - ) } @Test @@ -625,11 +644,6 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.NOVEMBER, 26) at Time.NOON, date - 5.days ) - - assertEquals( - Date(1969, Month.NOVEMBER, 26) at Time.NOON, - date - 5L.days - ) } @Test @@ -640,20 +654,13 @@ class DateTimeTest : AbstractIslandTimeTest() { Date(1969, Month.DECEMBER, 6) at Time.NOON, date - (-5).days ) - - assertEquals( - Date(1969, Month.DECEMBER, 6) at Time.NOON, - date - (-5L).days - ) } @Test fun `adding or subtracting zero hours has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.hours) - assertEquals(date, date + 0L.hours) assertEquals(date, date - 0.hours) - assertEquals(date, date - 0L.hours) } @Test @@ -683,9 +690,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero minutes has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.minutes) - assertEquals(date, date + 0L.minutes) assertEquals(date, date - 0.minutes) - assertEquals(date, date - 0L.minutes) } @Test @@ -722,9 +727,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero seconds has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.seconds) - assertEquals(date, date + 0L.seconds) assertEquals(date, date - 0.seconds) - assertEquals(date, date - 0L.seconds) } @Test @@ -766,9 +769,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero milliseconds has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.milliseconds) - assertEquals(date, date + 0L.milliseconds) assertEquals(date, date - 0.milliseconds) - assertEquals(date, date - 0L.milliseconds) } @Test @@ -804,9 +805,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero microseconds has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.microseconds) - assertEquals(date, date + 0L.microseconds) assertEquals(date, date - 0.microseconds) - assertEquals(date, date - 0L.microseconds) } @Test @@ -842,9 +841,7 @@ class DateTimeTest : AbstractIslandTimeTest() { fun `adding or subtracting zero nanoseconds has no effect`() { val date = Date(1969, Month.DECEMBER, 1) at Time.NOON assertEquals(date, date + 0.nanoseconds) - assertEquals(date, date + 0L.nanoseconds) assertEquals(date, date - 0.nanoseconds) - assertEquals(date, date - 0L.nanoseconds) } @Test diff --git a/core/src/commonTest/kotlin/io/islandtime/YearMonthTest.kt b/core/src/commonTest/kotlin/io/islandtime/YearMonthTest.kt index 225cdcc30..8dc129bbe 100644 --- a/core/src/commonTest/kotlin/io/islandtime/YearMonthTest.kt +++ b/core/src/commonTest/kotlin/io/islandtime/YearMonthTest.kt @@ -1,8 +1,8 @@ package io.islandtime -import io.islandtime.ranges.DateRange import io.islandtime.measures.* import io.islandtime.parser.DateTimeParseException +import io.islandtime.ranges.DateRange import io.islandtime.test.AbstractIslandTimeTest import kotlin.test.* @@ -142,9 +142,7 @@ class YearMonthTest : AbstractIslandTimeTest() { fun `throws an exception when adding months puts the YearMonth out of range`() { listOf( { YearMonth.MAX + 1.months }, - { YearMonth.MAX + 1L.months }, { YearMonth.MIN + (-1).months }, - { YearMonth.MIN + (-1L).months }, { YearMonth(999_992_000, Month.JANUARY) + 8000.years.inMonths }, { YearMonth(-999_998_000, Month.DECEMBER) + (-2000).years.inMonths }, { YearMonth(999_992_000, Month.DECEMBER) + (Int.MAX_VALUE + 1L).months }, @@ -192,9 +190,7 @@ class YearMonthTest : AbstractIslandTimeTest() { fun `throws an exception when subtracting months puts the YearMonth out of range`() { listOf( { YearMonth.MIN - 1.months }, - { YearMonth.MIN - 1L.months }, { YearMonth.MAX - (-1).months }, - { YearMonth.MAX - (-1L).months }, { YearMonth(-999_998_000, Month.JANUARY) - 2000.years.inMonths }, { YearMonth(999_992_000, Month.DECEMBER) - (-8000).years.inMonths }, { YearMonth(-999_000_000, Month.DECEMBER) - (Int.MAX_VALUE + 1L).months }, @@ -211,11 +207,6 @@ class YearMonthTest : AbstractIslandTimeTest() { YearMonth(2010, Month.APRIL), YearMonth(2010, Month.APRIL) + 0.years ) - - assertEquals( - YearMonth(2010, Month.APRIL), - YearMonth(2010, Month.APRIL) + 0L.years - ) } @Test @@ -248,9 +239,7 @@ class YearMonthTest : AbstractIslandTimeTest() { fun `throws an exception when adding years puts the YearMonth out of range`() { listOf( { YearMonth.MAX + 1.years }, - { YearMonth.MAX + 1L.years }, { YearMonth.MIN + (-1).years }, - { YearMonth.MIN + (-1L).years }, { YearMonth(999_992_000, Month.JANUARY) + 8000.years }, { YearMonth(-999_998_000, Month.DECEMBER) + (-2000).years }, { YearMonth(999_992_000, Month.DECEMBER) + (Int.MAX_VALUE + 1L).years }, @@ -298,9 +287,7 @@ class YearMonthTest : AbstractIslandTimeTest() { fun `throws an exception when subtracting years puts the YearMonth out of range`() { listOf( { YearMonth.MIN - 1.years }, - { YearMonth.MIN - 1L.years }, { YearMonth.MAX - (-1).years }, - { YearMonth.MAX - (-1L).years }, { YearMonth(-999_998_000, Month.JANUARY) - 2000.years }, { YearMonth(999_992_000, Month.DECEMBER) - (-8000).years }, { YearMonth(1, Month.DECEMBER) - (Int.MAX_VALUE + 1L).years }, @@ -311,6 +298,162 @@ class YearMonthTest : AbstractIslandTimeTest() { } } + @Test + fun `adding zero decades doesn't change the YearMonth`() { + assertEquals( + YearMonth(2010, Month.APRIL), + YearMonth(2010, Month.APRIL) + 0.decades + ) + } + + @Test + fun `adds positive decades`() { + assertEquals( + YearMonth(2020, Month.APRIL), + YearMonth(2010, Month.APRIL) + 1.decades + ) + } + + @Test + fun `adds negative decades`() { + assertEquals( + YearMonth(2000, Month.APRIL), + YearMonth(2010, Month.APRIL) + (-1).decades + ) + } + + @Test + fun `throws an exception when adding decades puts the YearMonth out of range`() { + listOf( + { YearMonth.MAX + 1.decades }, + { YearMonth.MIN + (-1).decades } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when adding decades causes overflow`() { + assertFailsWith { YearMonth(9999, Month.DECEMBER) + Long.MAX_VALUE.decades } + } + + @Test + fun `subtracting zero decades doesn't change the YearMonth`() { + assertEquals( + YearMonth(2012, Month.APRIL), + YearMonth(2012, Month.APRIL) - 0.decades + ) + } + + @Test + fun `subtracts positive decades`() { + assertEquals( + YearMonth(2000, Month.APRIL), + YearMonth(2010, Month.APRIL) - 1.decades + ) + } + + @Test + fun `subtracts negative decades`() { + assertEquals( + YearMonth(2020, Month.APRIL), + YearMonth(2010, Month.APRIL) - (-1).decades + ) + } + + @Test + fun `throws an exception when subtracting decades puts the YearMonth out of range`() { + listOf( + { YearMonth.MIN - 1.decades }, + { YearMonth.MAX - (-1).decades } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when subtracting decades causes overflow`() { + assertFailsWith { YearMonth(9999, Month.DECEMBER) - Long.MAX_VALUE.decades } + } + + @Test + fun `adding zero centuries doesn't change the YearMonth`() { + assertEquals( + YearMonth(2010, Month.APRIL), + YearMonth(2010, Month.APRIL) + 0.centuries + ) + } + + @Test + fun `adds positive centuries`() { + assertEquals( + YearMonth(2110, Month.APRIL), + YearMonth(2010, Month.APRIL) + 1.centuries + ) + } + + @Test + fun `adds negative centuries`() { + assertEquals( + YearMonth(1910, Month.APRIL), + YearMonth(2010, Month.APRIL) + (-1).centuries + ) + } + + @Test + fun `throws an exception when adding centuries puts the YearMonth out of range`() { + listOf( + { YearMonth.MAX + 1.centuries }, + { YearMonth.MIN + (-1).centuries } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when adding centuries causes overflow`() { + assertFailsWith { YearMonth(9999, Month.DECEMBER) + Long.MAX_VALUE.centuries } + } + + @Test + fun `subtracting zero centuries doesn't change the YearMonth`() { + assertEquals( + YearMonth(2012, Month.APRIL), + YearMonth(2012, Month.APRIL) - 0.centuries + ) + } + + @Test + fun `subtracts positive centuries`() { + assertEquals( + YearMonth(1910, Month.APRIL), + YearMonth(2010, Month.APRIL) - 1.centuries + ) + } + + @Test + fun `subtracts negative centuries`() { + assertEquals( + YearMonth(2110, Month.APRIL), + YearMonth(2010, Month.APRIL) - (-1).centuries + ) + } + + @Test + fun `throws an exception when subtracting centuries puts the YearMonth out of range`() { + listOf( + { YearMonth.MIN - 1.centuries }, + { YearMonth.MAX - (-1).centuries } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when subtracting centuries causes overflow`() { + assertFailsWith { YearMonth(9999, Month.DECEMBER) - Long.MAX_VALUE.centuries } + } + @Test fun `contains Date`() { val yearMonth = YearMonth(2019, Month.JANUARY) diff --git a/core/src/commonTest/kotlin/io/islandtime/YearTest.kt b/core/src/commonTest/kotlin/io/islandtime/YearTest.kt index 09f4ad700..f6d3e29d9 100644 --- a/core/src/commonTest/kotlin/io/islandtime/YearTest.kt +++ b/core/src/commonTest/kotlin/io/islandtime/YearTest.kt @@ -1,12 +1,14 @@ package io.islandtime -import io.islandtime.ranges.DateRange +import io.islandtime.measures.centuries import io.islandtime.measures.days +import io.islandtime.measures.decades import io.islandtime.measures.years import io.islandtime.parser.DateTimeParseException import io.islandtime.parser.dateTimeParser import io.islandtime.parser.monthNumber import io.islandtime.parser.year +import io.islandtime.ranges.DateRange import io.islandtime.test.AbstractIslandTimeTest import kotlin.test.* @@ -105,9 +107,7 @@ class YearTest : AbstractIslandTimeTest() { @Test fun `adding or subtracting zero years has no effect`() { assertEquals(Year(2009), Year(2009) + 0.years) - assertEquals(Year(2009), Year(2009) + 0L.years) assertEquals(Year(2009), Year(2009) - 0.years) - assertEquals(Year(2009), Year(2009) - 0L.years) } @Test @@ -129,11 +129,9 @@ class YearTest : AbstractIslandTimeTest() { fun `throws an exception when adding years puts the year outside the supported range`() { listOf( { Year.MAX + 1.years }, - { Year.MAX + 1L.years }, { Year.MAX + Int.MAX_VALUE.years }, { Year.MAX + Long.MAX_VALUE.years }, { Year.MIN + (-1).years }, - { Year.MIN + (-1L).years }, { Year.MIN + Int.MIN_VALUE.years }, { Year.MIN + Long.MIN_VALUE.years } ).forEach { @@ -160,11 +158,9 @@ class YearTest : AbstractIslandTimeTest() { fun `throws an exception when subtracting years puts the year outside the supported range`() { listOf( { Year.MAX - (-1).years }, - { Year.MAX - (-1L).years }, { Year.MAX - Int.MIN_VALUE.years }, { Year.MAX - Long.MIN_VALUE.years }, { Year.MIN - 1.years }, - { Year.MIN - 1L.years }, { Year.MIN - Int.MAX_VALUE.years }, { Year.MIN - Long.MAX_VALUE.years } ).forEach { @@ -172,6 +168,138 @@ class YearTest : AbstractIslandTimeTest() { } } + @Test + fun `adding or subtracting zero decades has no effect`() { + assertEquals(Year(2009), Year(2009) + 0.decades) + assertEquals(Year(2009), Year(2009) - 0.decades) + } + + @Test + fun `add positive decades`() { + assertEquals(Year(1979), Year(1969) + 1.decades) + } + + @Test + fun `add negative decades`() { + assertEquals(Year(-8), Year(2) + (-1).decades) + } + + @Test + fun `throws an exception when adding decades puts the year outside the supported range`() { + listOf( + { Year.MAX + 1.decades }, + { Year.MIN + (-1).decades }, + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when adding decades causes overflow`() { + listOf( + { Year.MAX + Long.MAX_VALUE.decades }, + { Year.MIN + Long.MIN_VALUE.decades } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `subtract positive decades`() { + assertEquals(Year(2000), Year(2010) - 1.decades) + } + + @Test + fun `subtract negative decades`() { + assertEquals(Year(1979), Year(1969) - (-1).decades) + } + + @Test + fun `throws an exception when subtracting decades puts the year outside the supported range`() { + listOf( + { Year.MAX - (-1).decades }, + { Year.MIN - 1.decades }, + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when subtracting decades causes overflow`() { + listOf( + { Year.MAX - Long.MIN_VALUE.decades }, + { Year.MIN - Long.MAX_VALUE.decades } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `adding or subtracting zero centuries has no effect`() { + assertEquals(Year(2009), Year(2009) + 0.centuries) + assertEquals(Year(2009), Year(2009) - 0.centuries) + } + + @Test + fun `add positive centuries`() { + assertEquals(Year(2069), Year(1969) + 1.centuries) + } + + @Test + fun `add negative centuries`() { + assertEquals(Year(-98), Year(2) + (-1).centuries) + } + + @Test + fun `throws an exception when adding centuries puts the year outside the supported range`() { + listOf( + { Year.MAX + 1.centuries }, + { Year.MIN + (-1).centuries }, + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when adding centuries causes overflow`() { + listOf( + { Year.MAX + Long.MAX_VALUE.centuries }, + { Year.MIN + Long.MIN_VALUE.centuries } + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `subtract positive centuries`() { + assertEquals(Year(1910), Year(2010) - 1.centuries) + } + + @Test + fun `subtract negative centuries`() { + assertEquals(Year(2069), Year(1969) - (-1).centuries) + } + + @Test + fun `throws an exception when subtracting centuries puts the year outside the supported range`() { + listOf( + { Year.MAX - (-1).centuries }, + { Year.MIN - 1.centuries }, + ).forEach { + assertFailsWith { it() } + } + } + + @Test + fun `throws an exception when subtracting centuries causes overflow`() { + listOf( + { Year.MAX - Long.MIN_VALUE.centuries }, + { Year.MIN - Long.MAX_VALUE.centuries } + ).forEach { + assertFailsWith { it() } + } + } + @Test fun `contains YearMonth`() { assertTrue { YearMonth(2019, Month.JANUARY) in Year(2019) }