diff --git a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt index 94f415b8a..5a4e369f8 100644 --- a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt +++ b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt @@ -23,6 +23,7 @@ import io.fluidsonic.locale.Locale import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.Month import kotlinx.datetime.TimeZone import kotlinx.datetime.offsetAt import kotlinx.datetime.toInstant @@ -47,7 +48,7 @@ data class LocalDate(val daysSince2000: Int) { var monthCache = -1 var dayCache = -1 - constructor(year: Int, month: Int, day: Int) : + constructor(year: Int, month: Month, day: Int) : this(daysSince2000(year, month, day)) val dayOfWeek: DayOfWeek @@ -295,16 +296,16 @@ val nonLeapOffset = arrayOf( 212, 243, 273, 304, 334, 365 ) -private fun daysSince2000(year: Int, month: Int, day: Int): Int { +internal fun daysSince2000(year: Int, month: Month, day: Int): Int { var result = 365 * (year - 2000) result += ceil((year - 2000) / 4.0).toInt() result -= ceil((year - 2000) / 100.0).toInt() result += ceil((year - 2000) / 400.0).toInt() result += if (isLeapYear(year)) { - leapOffset[month - 1] + leapOffset[month.ordinal] } else { - nonLeapOffset[month - 1] + nonLeapOffset[month.ordinal] } result += (day - 1) return result diff --git a/uhabits-core/src/commonTest/kotlin/org/isoron/platform/time/DatesTest.kt b/uhabits-core/src/commonTest/kotlin/org/isoron/platform/time/DatesTest.kt index d27599f8f..f036b1c53 100644 --- a/uhabits-core/src/commonTest/kotlin/org/isoron/platform/time/DatesTest.kt +++ b/uhabits-core/src/commonTest/kotlin/org/isoron/platform/time/DatesTest.kt @@ -418,6 +418,21 @@ class DatesTest : BaseUnitTest() { assertEquals(expected, upcomingTimeMillis) } + @Test + fun testDaysSince2000() { + val zeroDays = daysSince2000(2000, Month.JANUARY, 1) + assertEquals(0, zeroDays) + + val oneYearWithLeapYear = daysSince2000(2001, Month.JANUARY, 1) + assertEquals(366, oneYearWithLeapYear) + + val fourYearsWithLeapYear = daysSince2000(2004, Month.JANUARY, 1) + assertEquals(1461, fourYearsWithLeapYear) + + val oneYearPrior = daysSince2000(1999, Month.JANUARY, 1) + assertEquals(-365, oneYearPrior) + } + private fun unixTime(year: Int, month: Month, day: Int): Long { return unixTime(year, month, day, 0, 0) } @@ -434,4 +449,8 @@ class DatesTest : BaseUnitTest() { year, month, day, hour, minute, (milliseconds / 1000).toInt(), 0 ).toInstant(TimeZone.UTC).toEpochMilliseconds() } + + companion object { + const val JAN_1_2000_IN_UNIX_TIME = 946684800000L + } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/platform/time/JavaDates.kt b/uhabits-core/src/jvmMain/java/org/isoron/platform/time/JavaDates.kt index b922b88fe..486eaffb6 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/platform/time/JavaDates.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/platform/time/JavaDates.kt @@ -19,6 +19,7 @@ package org.isoron.platform.time +import kotlinx.datetime.Month import java.util.Calendar.DAY_OF_MONTH import java.util.Calendar.DAY_OF_WEEK import java.util.Calendar.HOUR_OF_DAY @@ -59,7 +60,7 @@ class JavaLocalDateFormatter(private val locale: Locale) : LocalDateFormatter { override fun shortWeekdayName(weekday: DayOfWeek): String { val cal = GregorianCalendar() cal.set(DAY_OF_WEEK, weekday.daysSinceSunday - 1) - return shortWeekdayName(LocalDate(cal.get(YEAR), cal.get(MONTH) + 1, cal.get(DAY_OF_MONTH))) + return shortWeekdayName(LocalDate(cal.get(YEAR), Month(cal.get(MONTH) + 1), cal.get(DAY_OF_MONTH))) } override fun shortWeekdayName(date: LocalDate): String { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt index baa281aeb..39e6d7eb1 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt @@ -114,13 +114,6 @@ data class Timestamp(var unixTime: Long) : Comparable { cal[year, javaMonth, day, 0, 0] = 0 return Timestamp(cal.timeInMillis) } - - /** - * Given two timestamps, returns whichever timestamp is the oldest one. - */ - fun oldest(first: Timestamp, second: Timestamp): Timestamp { - return if (first.unixTime < second.unixTime) first else second - } } init { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index f0da7a196..aa5d4b4fa 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.core.ui.views +import kotlinx.datetime.Month import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color import org.isoron.platform.gui.DataView @@ -63,7 +64,7 @@ class HistoryChart( private var height = 0.0 private var nColumns = 0 private var topLeftOffset = 0 - private var topLeftDate = LocalDate(2020, 1, 1) + private var topLeftDate = LocalDate(2020, Month.JANUARY, 1) private var lastPrintedMonth = "" private var lastPrintedYear = "" private var headerOverflow = 0.0 diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt index 8296528b7..9c170d599 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt @@ -24,11 +24,22 @@ import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.greaterThan import org.hamcrest.Matchers.lessThan +import org.isoron.platform.time.DatesTest.Companion.JAN_1_2000_IN_UNIX_TIME +import org.isoron.platform.time.LocalDate import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday import org.junit.Test +import java.time.Month +import kotlin.test.assertEquals class TimestampTest : BaseUnitTest() { + @Test + fun testToLocalDate() { + val timestamp = Timestamp(JAN_1_2000_IN_UNIX_TIME) + val expectedLocalDate = LocalDate(2000, Month.JANUARY ,1) + assertEquals(expectedLocalDate, timestamp.toLocalDate()) + } + @Test @Throws(Exception::class) fun testCompare() { diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt index ff608a49b..116b8a04d 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt @@ -20,6 +20,7 @@ package org.isoron.uhabits.core.ui.views import kotlinx.coroutines.runBlocking +import kotlinx.datetime.Month import org.isoron.platform.gui.assertRenders import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.platform.time.LocalDate @@ -28,7 +29,7 @@ import java.util.Locale class BarChartTest { val base = "views/BarChart" - val today = LocalDate(2015, 1, 25) + val today = LocalDate(2015, Month.JANUARY, 25) private val fmt = JavaLocalDateFormatter(Locale.US) val theme = LightTheme() val component = BarChart(theme, fmt) diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index a53135f9b..b309d4550 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -24,6 +24,7 @@ import com.nhaarman.mockitokotlin2.reset import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import kotlinx.coroutines.runBlocking +import kotlinx.datetime.Month import org.isoron.platform.gui.assertRenders import org.isoron.platform.time.DayOfWeek import org.isoron.platform.time.DayOfWeek.SUNDAY @@ -43,7 +44,7 @@ class HistoryChartTest { private val dateClickedListener: OnDateClickedListener = mock() val view = HistoryChart( - today = LocalDate(2015, 1, 25), + today = LocalDate(2015, Month.JANUARY, 25), paletteColor = PaletteColor(7), theme = LightTheme(), dateFormatter = JavaLocalDateFormatter(Locale.US), @@ -86,20 +87,20 @@ class HistoryChartTest { // Click top left date view.onClick(20.0, 46.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, Month.OCTOBER, 26)) reset(dateClickedListener) view.onClick(2.0, 28.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, Month.OCTOBER, 26)) reset(dateClickedListener) // Click date in the middle view.onClick(163.0, 113.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 12, 10)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, Month.DECEMBER, 10)) reset(dateClickedListener) // Click today view.onClick(336.0, 37.0) - verify(dateClickedListener).onDateClicked(LocalDate(2015, 1, 25)) + verify(dateClickedListener).onDateClicked(LocalDate(2015, Month.JANUARY, 25)) reset(dateClickedListener) // Click header