Skip to content

Commit

Permalink
Optimize date conversion by using maps and skipping unnecessary loops.
Browse files Browse the repository at this point in the history
  • Loading branch information
shivathapaa committed Sep 12, 2024
1 parent b078821 commit af54a8a
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ private class NepaliDatePickerStateImpl(
* A mutable state of [CustomCalendar] that represents a selected date.
*/
private var _selectedDate = mutableStateOf(if (initialSelectedDate != null) {
val date = calendarModel.getNepaliMonth(simpleNepaliDate = initialSelectedDate)
val date = calendarModel.getNepaliCalendar(simpleNepaliDate = initialSelectedDate)
require(yearRange.contains(date.year)) {
"The provided initial date's year (${date.year}) is out of the years range of $yearRange."
}
Expand Down Expand Up @@ -878,7 +878,7 @@ private fun NepaliMonth(
// To tackle recompositions
val currentMonthDate by remember(cellIndex, dayNumber) {
derivedStateOf {
calendarModel.getNepaliMonth(
calendarModel.getNepaliCalendar(
SimpleDate(
year = monthCalendar.year,
month = monthCalendar.month,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import dev.shivathapaa.nepalidatepickerkmp.data.CustomCalendar
import dev.shivathapaa.nepalidatepickerkmp.data.NepaliMonthCalendar
import dev.shivathapaa.nepalidatepickerkmp.data.SimpleDate
import dev.shivathapaa.nepalidatepickerkmp.data.daysInMonthMap
import dev.shivathapaa.nepalidatepickerkmp.data.englishDateMap
import dev.shivathapaa.nepalidatepickerkmp.data.nepaliDateMap
import kotlinx.datetime.LocalDate
import kotlinx.datetime.daysUntil

Expand All @@ -32,9 +34,6 @@ internal object DateConverters {
private val minEnglishYear = NepaliDatePickerDefaults.EnglishYearRange.first
private val maxEnglishYear = NepaliDatePickerDefaults.EnglishYearRange.last

private val startingEnglishCalendar = NepaliDatePickerDefaults.startingEnglishCalendar
private val startingNepaliCalendar = NepaliDatePickerDefaults.startingNepaliCalendar

fun getTotalDaysInNepaliMonth(nepaliYYYY: Int, nepaliMM: Int): Int {
return daysInMonthMap.getValue(nepaliYYYY)[nepaliMM]
}
Expand All @@ -50,13 +49,23 @@ internal object DateConverters {
}

// Initialize the starting English and Nepali dates
val (startingEnglishDate, startingNepaliCalendar, startingDayOfWeek) = initializeStartingDates()
val (startingEnglishDate, startingNepaliCalendar) = initializeStartingDates(
englishYYYY,
false
)

val newEnglishDate = LocalDate(englishYYYY, englishMM, englishDD)
val englishLocalDate = LocalDate(
year = startingEnglishDate.year,
monthNumber = startingEnglishDate.month,
dayOfMonth = startingEnglishDate.dayOfMonth
)

val newEnglishDate =
LocalDate(year = englishYYYY, monthNumber = englishMM, dayOfMonth = englishDD)

// Calculate the total number of days between the base date and the target date
val totalDaysDifference = calculateEnglishDaysDifference(
startingEnglishDate, newEnglishDate
englishLocalDate, newEnglishDate
)

// Initialize the Nepali date with the starting values
Expand All @@ -65,15 +74,15 @@ internal object DateConverters {
startingNepaliCalendar.month,
startingNepaliCalendar.dayOfMonth
)
var dayOfWeek = startingDayOfWeek
var dayOfWeek = startingNepaliCalendar.dayOfWeek

// Counters for day of year, week of year, and week of month
var dayOfYear = 1
var weekOfYear = 1
var weekOfMonth = 1
var dayOfYear = startingNepaliCalendar.dayOfYear
var weekOfYear = startingNepaliCalendar.weekOfYear
var weekOfMonth = startingNepaliCalendar.weekOfMonth

var firstDayOfMonth: Int = dayOfWeek
var lastDayOfMonth: Int = -1
var firstDayOfMonth: Int = startingNepaliCalendar.firstDayOfMonth
var lastDayOfMonth: Int = startingNepaliCalendar.lastDayOfMonth

var totalDaysInMonth = daysInMonthMap.getValue(nepaliYYYY)[nepaliMM]

Expand Down Expand Up @@ -141,7 +150,10 @@ internal object DateConverters {
}

// Initialize the starting English and Nepali dates
val (startingEnglishDate, startingNepaliCalendar, startingDayOfWeek) = initializeStartingDates()
val (startingEnglishDate, startingNepaliCalendar) = initializeStartingDates(
nepaliYYYY,
true
)

// Calculate the total number of Nepali days from the starting date to the target date
val totalNepDaysCount =
Expand All @@ -154,17 +166,17 @@ internal object DateConverters {
// Initialize the English date with the starting values
var (englishYYYY, englishMM, englishDD) = Triple(
startingEnglishDate.year,
startingEnglishDate.monthNumber,
startingEnglishDate.month,
startingEnglishDate.dayOfMonth
)

var dayOfWeek = startingDayOfWeek
var dayOfYear = 1
var weekOfYear = 1
var weekOfMonth = 1
var dayOfWeek = startingEnglishDate.dayOfWeek
var dayOfYear = startingEnglishDate.dayOfYear
var weekOfYear = startingEnglishDate.weekOfYear
var weekOfMonth = startingEnglishDate.weekOfMonth

var firstDayOfMonth: Int = dayOfWeek
var lastDayOfMonth: Int = -1
var firstDayOfMonth: Int = startingEnglishDate.firstDayOfMonth
var lastDayOfMonth: Int = startingEnglishDate.lastDayOfMonth

var totalDaysInMonth =
if (isEnglishLeapYear(englishYYYY)) daysInMonthOfLeapYear[englishMM] else daysInMonth[englishMM]
Expand Down Expand Up @@ -221,16 +233,18 @@ internal object DateConverters {
)
}

private fun initializeStartingDates(): Triple<LocalDate, CustomCalendar, Int> {
val startingEnglishDate = LocalDate(
startingEnglishCalendar.year,
startingEnglishCalendar.month,
startingEnglishCalendar.dayOfMonth
)
val startingNepaliCalendar = startingNepaliCalendar
val startingDayOfWeek = 1
private fun initializeStartingDates(targetYear: Int, isNepaliDate: Boolean)
: Pair<CustomCalendar, CustomCalendar> {
val referenceDate =
if (isNepaliDate) nepaliDateMap[targetYear - 1]
else englishDateMap[targetYear - 1]

val startingEnglishDate =
referenceDate?.englishDate ?: NepaliDatePickerDefaults.startingEnglishCalendar
val startingNepaliCalendar =
referenceDate?.nepaliDate ?: NepaliDatePickerDefaults.startingNepaliCalendar

return Triple(startingEnglishDate, startingNepaliCalendar, startingDayOfWeek)
return Pair(startingEnglishDate, startingNepaliCalendar)
}

private fun calculateEnglishDaysDifference(
Expand Down Expand Up @@ -263,7 +277,6 @@ internal object DateConverters {
return totalNepDaysCount
}

// Two overload functions for month details
fun getNepaliMonth(
nepaliYear: Int, nepaliMonth: Int, addedMonthsCount: Int
): NepaliMonthCalendar {
Expand All @@ -274,7 +287,7 @@ internal object DateConverters {
return calculateNepaliMonthDetails(newYear, newMonth)
}

fun getNepaliMonth(simpleNepaliDate: SimpleDate): CustomCalendar {
fun getNepaliCalendar(simpleNepaliDate: SimpleDate): CustomCalendar {
return getCustomCalendarUsingDayMonthYear(
dayOfMonth = simpleNepaliDate.dayOfMonth,
month = simpleNepaliDate.month,
Expand All @@ -291,19 +304,34 @@ internal object DateConverters {
* and throws exception if the year is not found in [daysInMonthMap].
*/
fun nepaliDaysInBetween(startDate: SimpleDate, endDate: SimpleDate): Int {
val referenceYear: Int

if (startDate.year > endDate.year) {
return -nepaliDaysInBetween(endDate, startDate)
} else {
referenceYear = startDate.year
}

if (!isNepaliCalendarInConversionRange(startDate.year, startDate.month, startDate.dayOfMonth)
if (!isNepaliCalendarInConversionRange(
startDate.year,
startDate.month,
startDate.dayOfMonth
)
|| !isNepaliCalendarInConversionRange(endDate.year, endDate.month, endDate.dayOfMonth)
) {
throw IllegalArgumentException("Out of Range: Nepali start year ${startDate.year} or end year " +
"${startDate.year} is out of range to compare. Check range value from NepaliDatePickerDefaults.")
throw IllegalArgumentException(
"Out of Range: Nepali start year ${startDate.year} or end year " +
"${startDate.year} is out of range to compare. Check range value from NepaliDatePickerDefaults."
)
}

val startOffset = calculateDayOffset(minNepaliYear, startDate.year, startDate.month) + startDate.dayOfMonth
val endOffset = calculateDayOffset(minNepaliYear, endDate.year, endDate.month) + endDate.dayOfMonth
val startOffset = calculateDayOffset(
referenceYear,
startDate.year,
startDate.month
) + startDate.dayOfMonth
val endOffset =
calculateDayOffset(referenceYear, endDate.year, endDate.month) + endDate.dayOfMonth

return endOffset - startOffset
}
Expand Down Expand Up @@ -381,10 +409,12 @@ internal object DateConverters {
val totalDaysInMonth = daysInMonthMap[nepaliYear]?.get(nepaliMonth)
?: throw IllegalArgumentException("Invalid year $nepaliYear or month provided $nepaliMonth.")

val startingNepaliCalendar = startingNepaliCalendar
val startingNepaliCalendar = nepaliDateMap[nepaliYear - 1]?.nepaliDate
?: NepaliDatePickerDefaults.startingNepaliCalendar

// Calculate the offset in days from the starting date to the target date
val dayOffset = calculateDayOffset(startingNepaliCalendar.year, nepaliYear, nepaliMonth)
val dayOffset =
calculateDayOffset(startingNepaliCalendar.year, nepaliYear, nepaliMonth)

// Calculate the first day of the month by applying the offset to the base day of the week
val firstDayOfMonth = (startingNepaliCalendar.firstDayOfMonth + dayOffset) % 7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ internal class NepaliCalendarModel(val locale: NepaliDateLocale = NepaliDateLoca
return DateConverters.calculateNepaliMonthDetails(nepaliYear, nepaliMonth)
}

fun getNepaliMonth(simpleNepaliDate: SimpleDate): CustomCalendar {
return DateConverters.getNepaliMonth(simpleNepaliDate = simpleNepaliDate)
fun getNepaliCalendar(simpleNepaliDate: SimpleDate): CustomCalendar {
return DateConverters.getNepaliCalendar(simpleNepaliDate = simpleNepaliDate)
}

// Function to add months to a CustomCalendar
Expand Down
Loading

0 comments on commit af54a8a

Please sign in to comment.