mirror of
https://github.com/InsanusMokrassar/krontab.git
synced 2024-11-22 16:23:55 +00:00
rewrite mechanism of calculating of near time
This commit is contained in:
parent
22ef00fe8f
commit
28f84d4e3a
@ -3,7 +3,9 @@
|
||||
## 0.6.1
|
||||
|
||||
* Versions
|
||||
* `Klock`: `2.1.0` -> `2.1.2`
|
||||
* `Klock`: `2.1.0` -> `2.1.2
|
||||
|
||||
`
|
||||
|
||||
## 0.6.0
|
||||
|
||||
|
@ -16,13 +16,13 @@ fun Iterator<KronScheduler>.merge(): CollectionKronScheduler {
|
||||
val collectionScheduler = CollectionKronScheduler()
|
||||
forEach {
|
||||
when (it) {
|
||||
is CronDateTimeScheduler -> cronDateTimes.addAll(it.cronDateTimes)
|
||||
is CronDateTimeScheduler -> cronDateTimes.add(it.cronDateTime)
|
||||
is CronDateTimeSchedulerTz -> timezonedCronDateTimes.add(it)
|
||||
else -> collectionScheduler.include(it)
|
||||
}
|
||||
}
|
||||
if (cronDateTimes.isNotEmpty()) {
|
||||
collectionScheduler.include(CronDateTimeScheduler(cronDateTimes))
|
||||
collectionScheduler.include(CronDateTimeScheduler(cronDateTimes.merge()))
|
||||
}
|
||||
if (timezonedCronDateTimes.isNotEmpty()) {
|
||||
collectionScheduler.includeAll(mergeCronDateTimeSchedulers(timezonedCronDateTimes))
|
||||
|
@ -13,7 +13,7 @@ internal fun getAnyNext(relatively: DateTime) = anyCronDateTime.toNearDateTime(r
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now]
|
||||
*/
|
||||
val AnyTimeScheduler: KronScheduler by lazy {
|
||||
CronDateTimeScheduler(listOf(anyCronDateTime))
|
||||
CronDateTimeScheduler(anyCronDateTime)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,4 +56,4 @@ val EveryMonthScheduler: KronScheduler by lazy {
|
||||
*/
|
||||
val EveryYearScheduler: KronScheduler by lazy {
|
||||
buildSchedule { years { 0 every 1 } }
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ fun createSimpleScheduler(
|
||||
scheduler
|
||||
} else {
|
||||
CronDateTimeSchedulerTz(
|
||||
(scheduler as CronDateTimeScheduler).cronDateTimes,
|
||||
(scheduler as CronDateTimeScheduler).cronDateTime,
|
||||
TimezoneOffset(defaultOffset.minutes)
|
||||
)
|
||||
}
|
||||
|
@ -38,16 +38,16 @@ data class CollectionKronScheduler internal constructor(
|
||||
)
|
||||
}
|
||||
is CronDateTimeSchedulerTz -> {
|
||||
val newCronDateTimes = kronScheduler.cronDateTimes.toMutableList()
|
||||
val cronDateTimes = schedulers.removeAll {
|
||||
val newCronDateTimes = mutableListOf(kronScheduler.cronDateTime)
|
||||
schedulers.removeAll {
|
||||
if (it is CronDateTimeSchedulerTz && it.offset == kronScheduler.offset) {
|
||||
newCronDateTimes.addAll(it.cronDateTimes)
|
||||
newCronDateTimes.add(it.cronDateTime)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
schedulers.add(CronDateTimeSchedulerTz(newCronDateTimes.toList(), kronScheduler.offset))
|
||||
schedulers.add(CronDateTimeSchedulerTz(newCronDateTimes.merge(), kronScheduler.offset))
|
||||
}
|
||||
is CollectionKronScheduler -> kronScheduler.schedulers.forEach {
|
||||
include(it)
|
||||
|
@ -4,103 +4,125 @@ import com.soywiz.klock.*
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
|
||||
/**
|
||||
* @param dayOfweek 0-6
|
||||
* @param year any int
|
||||
* @param month 0-11
|
||||
* @param dayOfMonth 0-31
|
||||
* @param daysOfWeek 0-6
|
||||
* @param years any int
|
||||
* @param months 0-11
|
||||
* @param daysOfMonth 0-31
|
||||
* @param hours 0-23
|
||||
* @param minutes 0-59
|
||||
* @param seconds 0-59
|
||||
*/
|
||||
internal data class CronDateTime(
|
||||
val dayOfweek: Byte? = null,
|
||||
val year: Int? = null,
|
||||
val month: Byte? = null,
|
||||
val dayOfMonth: Byte? = null,
|
||||
val hours: Byte? = null,
|
||||
val minutes: Byte? = null,
|
||||
val seconds: Byte? = null
|
||||
val daysOfWeek: Array<Byte>? = null,
|
||||
val years: Array<Int>? = null,
|
||||
val months: Array<Byte>? = null,
|
||||
val daysOfMonth: Array<Byte>? = null,
|
||||
val hours: Array<Byte>? = null,
|
||||
val minutes: Array<Byte>? = null,
|
||||
val seconds: Array<Byte>? = null
|
||||
) {
|
||||
init {
|
||||
check(dayOfweek ?.let { it in dayOfWeekRange } ?: true)
|
||||
check(year ?.let { it in yearRange } ?: true)
|
||||
check(month ?.let { it in monthRange } ?: true)
|
||||
check(dayOfMonth ?.let { it in dayOfMonthRange } ?: true)
|
||||
check(hours?.let { it in hoursRange } ?: true)
|
||||
check(minutes?.let { it in minutesRange } ?: true)
|
||||
check(seconds?.let { it in secondsRange } ?: true)
|
||||
check(daysOfWeek ?.all { it in dayOfWeekRange } ?: true)
|
||||
check(years?.all { it in yearRange } ?: true)
|
||||
check(months?.all { it in monthRange } ?: true)
|
||||
check(daysOfMonth ?.all { it in dayOfMonthRange } ?: true)
|
||||
check(hours?.all { it in hoursRange } ?: true)
|
||||
check(minutes?.all { it in minutesRange } ?: true)
|
||||
check(seconds?.all { it in secondsRange } ?: true)
|
||||
}
|
||||
|
||||
internal val klockDayOfMonth = dayOfMonth ?.plus(1)
|
||||
internal val dayOfWeekInt: Int? = dayOfweek ?.toInt()
|
||||
}
|
||||
internal val calculators = listOf(
|
||||
NearDateTimeCalculatorMillis(arrayOf(0)),
|
||||
seconds ?.let { NearDateTimeCalculatorSeconds(it) },
|
||||
minutes ?.let { NearDateTimeCalculatorMinutes(it) },
|
||||
hours ?.let { NearDateTimeCalculatorHours(it) },
|
||||
daysOfMonth ?.let { NearDateTimeCalculatorDays(it) },
|
||||
months ?.let { NearDateTimeCalculatorMonths(it) },
|
||||
years ?.let { NearDateTimeCalculatorYears(it) },
|
||||
daysOfWeek ?.let { NearDateTimeCalculatorWeekDays(it) },
|
||||
)
|
||||
|
||||
/**
|
||||
* THIS METHOD WILL <b>NOT</b> TAKE CARE ABOUT [offset] PARAMETER. It was decided due to the fact that we unable to get
|
||||
* real timezone offset from simple [DateTime]
|
||||
*
|
||||
* @return The near [DateTime] which happens after [relativelyTo] or will be equal to [relativelyTo]
|
||||
*/
|
||||
internal fun CronDateTime.toNearDateTime(relativelyTo: DateTime = DateTime.now()): DateTime? {
|
||||
var current = relativelyTo
|
||||
|
||||
val weekDay = dayOfWeekInt
|
||||
if (weekDay != null && current.dayOfWeek.index0 != weekDay) {
|
||||
do {
|
||||
var diff = weekDay - current.dayOfWeek.index0
|
||||
if (diff < 0) {
|
||||
diff += 7 /* days in week */
|
||||
internal fun toNearDateTime(relativelyTo: DateTime = DateTime.now()): DateTime? {
|
||||
var current = relativelyTo
|
||||
whileLoop@while (true) {
|
||||
for (calculator in calculators) {
|
||||
val (calculated, requireRecalculation) = (calculator ?: continue).calculateNearTime(current) ?: return null
|
||||
current = calculated
|
||||
if (requireRecalculation) {
|
||||
continue@whileLoop
|
||||
}
|
||||
}
|
||||
current = (current + diff.days).startOfDay
|
||||
|
||||
val next = toNearDateTime(current)
|
||||
if (next == null || next.dayOfWeek.index0 == weekDay) {
|
||||
return next
|
||||
}
|
||||
} while (true)
|
||||
}
|
||||
|
||||
seconds?.let {
|
||||
val left = it - current.seconds
|
||||
current += DateTimeSpan(minutes = if (left <= 0) 1 else 0, seconds = left)
|
||||
}
|
||||
|
||||
minutes?.let {
|
||||
val left = it - current.minutes
|
||||
current += DateTimeSpan(hours = if (left < 0) 1 else 0, minutes = left)
|
||||
}
|
||||
|
||||
hours?.let {
|
||||
val left = it - current.hours
|
||||
current += DateTimeSpan(days = if (left < 0) 1 else 0, hours = left)
|
||||
}
|
||||
|
||||
klockDayOfMonth ?.let {
|
||||
val left = (it - current.dayOfMonth).let { diff ->
|
||||
if (diff > 0 && current.endOfMonth.run { it > dayOfMonth && current.dayOfMonth == dayOfMonth }) {
|
||||
0
|
||||
} else {
|
||||
diff
|
||||
}
|
||||
}
|
||||
current += DateTimeSpan(months = if (left < 0) 1 else 0, days = left)
|
||||
}
|
||||
|
||||
month ?.let {
|
||||
val left = it - current.month0
|
||||
current += DateTimeSpan(years = if (left < 0) 1 else 0, months = left)
|
||||
}
|
||||
|
||||
year ?.let {
|
||||
if (current.yearInt != it) {
|
||||
return null
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
//
|
||||
///**
|
||||
// * THIS METHOD WILL <b>NOT</b> TAKE CARE ABOUT [offset] PARAMETER. It was decided due to the fact that we unable to get
|
||||
// * real timezone offset from simple [DateTime]
|
||||
// *
|
||||
// * @return The near [DateTime] which happens after [relativelyTo] or will be equal to [relativelyTo]
|
||||
// */
|
||||
//internal fun CronDateTime.toNearDateTime(relativelyTo: DateTime = DateTime.now()): DateTime? {
|
||||
// var current = relativelyTo
|
||||
//
|
||||
// val weekDay = dayOfWeekInt
|
||||
// if (weekDay != null && current.dayOfWeek.index0 != weekDay) {
|
||||
// do {
|
||||
// var diff = weekDay - current.dayOfWeek.index0
|
||||
// if (diff < 0) {
|
||||
// diff += 7 /* days in week */
|
||||
// }
|
||||
// current = (current + diff.days).startOfDay
|
||||
//
|
||||
// val next = toNearDateTime(current)
|
||||
// if (next == null || next.dayOfWeek.index0 == weekDay) {
|
||||
// return next
|
||||
// }
|
||||
// } while (true)
|
||||
// }
|
||||
//
|
||||
// seconds?.let {
|
||||
// val left = it - current.seconds
|
||||
// current += DateTimeSpan(minutes = if (left <= 0) 1 else 0, seconds = left)
|
||||
// }
|
||||
//
|
||||
// minutes?.let {
|
||||
// val left = it - current.minutes
|
||||
// current += DateTimeSpan(hours = if (left < 0) 1 else 0, minutes = left)
|
||||
// }
|
||||
//
|
||||
// hours?.let {
|
||||
// val left = it - current.hours
|
||||
// current += DateTimeSpan(days = if (left < 0) 1 else 0, hours = left)
|
||||
// }
|
||||
//
|
||||
// klockDayOfMonth ?.let {
|
||||
// val left = (it - current.dayOfMonth).let { diff ->
|
||||
// if (diff > 0 && current.endOfMonth.run { it > dayOfMonth && current.dayOfMonth == dayOfMonth }) {
|
||||
// 0
|
||||
// } else {
|
||||
// diff
|
||||
// }
|
||||
// }
|
||||
// current += DateTimeSpan(months = if (left < 0) 1 else 0, days = left)
|
||||
// }
|
||||
//
|
||||
// months?.let {
|
||||
// val left = it - current.month0
|
||||
// current += DateTimeSpan(years = if (left < 0) 1 else 0, months = left)
|
||||
// }
|
||||
//
|
||||
// years?.let {
|
||||
// if (current.yearInt != it) {
|
||||
// return null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return current
|
||||
//}
|
||||
|
||||
internal fun createCronDateTimeList(
|
||||
internal fun createCronDateTime(
|
||||
seconds: Array<Byte>? = null,
|
||||
minutes: Array<Byte>? = null,
|
||||
hours: Array<Byte>? = null,
|
||||
@ -108,38 +130,39 @@ internal fun createCronDateTimeList(
|
||||
month: Array<Byte>? = null,
|
||||
years: Array<Int>? = null,
|
||||
weekDays: Array<Byte>? = null
|
||||
): List<CronDateTime> {
|
||||
val resultCronDateTimes = mutableListOf(CronDateTime())
|
||||
|
||||
seconds ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(seconds = currentTime)
|
||||
}
|
||||
|
||||
minutes ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(minutes = currentTime)
|
||||
}
|
||||
|
||||
hours ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(hours = currentTime)
|
||||
}
|
||||
|
||||
dayOfMonth ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(dayOfMonth = currentTime)
|
||||
}
|
||||
|
||||
month ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(month = currentTime)
|
||||
}
|
||||
|
||||
years ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Int ->
|
||||
previousCronDateTime.copy(year = currentTime)
|
||||
}
|
||||
|
||||
weekDays ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
previousCronDateTime.copy(dayOfweek = currentTime)
|
||||
}
|
||||
|
||||
return resultCronDateTimes.toList()
|
||||
): CronDateTime {
|
||||
return CronDateTime(weekDays, years, month, dayOfMonth, hours, minutes, seconds)
|
||||
// val resultCronDateTimes = mutableListOf(CronDateTime())
|
||||
//
|
||||
// seconds ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(seconds = currentTime)
|
||||
// }
|
||||
//
|
||||
// minutes ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(minutes = currentTime)
|
||||
// }
|
||||
//
|
||||
// hours ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(hours = currentTime)
|
||||
// }
|
||||
//
|
||||
// dayOfMonth ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(daysOfMonth = currentTime)
|
||||
// }
|
||||
//
|
||||
// month ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(months = currentTime)
|
||||
// }
|
||||
//
|
||||
// years ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Int ->
|
||||
// previousCronDateTime.copy(years = currentTime)
|
||||
// }
|
||||
//
|
||||
// weekDays ?.fillWith(resultCronDateTimes) { previousCronDateTime: CronDateTime, currentTime: Byte ->
|
||||
// previousCronDateTime.copy(daysOfWeek = currentTime)
|
||||
// }
|
||||
//
|
||||
// return resultCronDateTimes.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,7 +176,7 @@ internal fun createKronScheduler(
|
||||
month: Array<Byte>? = null,
|
||||
years: Array<Int>? = null,
|
||||
weekDays: Array<Byte>? = null
|
||||
): KronScheduler = CronDateTimeScheduler(createCronDateTimeList(seconds, minutes, hours, dayOfMonth, month, years, weekDays))
|
||||
): KronScheduler = CronDateTimeScheduler(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays))
|
||||
/**
|
||||
* @return [KronScheduler] (in fact [CronDateTimeScheduler]) based on incoming data
|
||||
*/
|
||||
@ -166,4 +189,14 @@ internal fun createKronSchedulerWithOffset(
|
||||
years: Array<Int>? = null,
|
||||
weekDays: Array<Byte>? = null,
|
||||
offset: TimezoneOffset
|
||||
): KronScheduler = CronDateTimeSchedulerTz(createCronDateTimeList(seconds, minutes, hours, dayOfMonth, month, years, weekDays), offset)
|
||||
): KronScheduler = CronDateTimeSchedulerTz(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays), offset)
|
||||
|
||||
internal fun List<CronDateTime>.merge() = CronDateTime(
|
||||
flatMap { it.daysOfWeek ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.years ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.months ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.daysOfMonth ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.hours ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.minutes ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
flatMap { it.seconds ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ import dev.inmo.krontab.collection.plus
|
||||
* @see dev.inmo.krontab.builder.SchedulerBuilder
|
||||
*/
|
||||
internal data class CronDateTimeScheduler internal constructor(
|
||||
internal val cronDateTimes: List<CronDateTime>
|
||||
internal val cronDateTime: CronDateTime
|
||||
) : KronScheduler {
|
||||
/**
|
||||
* @return Near date using [cronDateTimes] list and getting the [Iterable.minByOrNull] one
|
||||
@ -27,12 +27,14 @@ internal data class CronDateTimeScheduler internal constructor(
|
||||
* @see toNearDateTime
|
||||
*/
|
||||
override suspend fun next(relatively: DateTime): DateTime? {
|
||||
return cronDateTimes.mapNotNull { it.toNearDateTime(relatively) }.minOrNull()
|
||||
return cronDateTime.toNearDateTime(relatively)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun mergeCronDateTimeSchedulers(schedulers: List<CronDateTimeScheduler>) = CronDateTimeScheduler(
|
||||
schedulers.flatMap { it.cronDateTimes }
|
||||
internal fun mergeCronDateTimeSchedulers(
|
||||
schedulers: List<CronDateTimeScheduler>
|
||||
): CronDateTimeScheduler = CronDateTimeScheduler(
|
||||
schedulers.map { it.cronDateTime }.merge()
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -11,14 +11,12 @@ import dev.inmo.krontab.KronSchedulerTz
|
||||
* @see CronDateTime
|
||||
*/
|
||||
internal data class CronDateTimeSchedulerTz internal constructor(
|
||||
internal val cronDateTimes: List<CronDateTime>,
|
||||
internal val cronDateTime: CronDateTime,
|
||||
internal val offset: TimezoneOffset
|
||||
) : KronSchedulerTz {
|
||||
override suspend fun next(relatively: DateTimeTz): DateTimeTz? {
|
||||
val dateTimeWithActualOffset = relatively.toOffset(offset).local
|
||||
return cronDateTimes.mapNotNull {
|
||||
it.toNearDateTime(dateTimeWithActualOffset)
|
||||
}.minOrNull() ?.toOffsetUnadjusted(offset) ?.toOffset(relatively.offset)
|
||||
return cronDateTime.toNearDateTime(dateTimeWithActualOffset) ?.toOffsetUnadjusted(offset) ?.toOffset(relatively.offset)
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,5 +25,8 @@ internal fun mergeCronDateTimeSchedulers(
|
||||
) = schedulers.groupBy {
|
||||
it.offset
|
||||
}.map { (offset, schedulers) ->
|
||||
CronDateTimeSchedulerTz(schedulers.flatMap { it.cronDateTimes }, offset)
|
||||
CronDateTimeSchedulerTz(
|
||||
schedulers.map { it.cronDateTime }.merge(),
|
||||
offset
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,171 @@
|
||||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import dev.inmo.krontab.utils.copy
|
||||
import kotlin.math.min
|
||||
|
||||
internal class NearDateTimeCalculator<T>(
|
||||
private val times: Array<T>,
|
||||
private val partGetter: (DateTime) -> T,
|
||||
private val partSetter: (DateTime, T) -> DateTime?
|
||||
) where T : Comparable<T>, T : Number {
|
||||
/**
|
||||
* @return pair of near [DateTime] for this checker and [Boolean] flag that all previous calculations must be
|
||||
* recalculated
|
||||
*/
|
||||
fun calculateNearTime(
|
||||
relativelyTo: DateTime
|
||||
): Pair<DateTime, Boolean>? {
|
||||
val currentData = partGetter(relativelyTo)
|
||||
val greaterOrEquals = times.firstOrNull { it >= currentData }
|
||||
val newDateTime = if (greaterOrEquals == null) {
|
||||
partSetter(relativelyTo, times.first()) ?: return null
|
||||
} else {
|
||||
partSetter(relativelyTo, greaterOrEquals) ?: return null
|
||||
}
|
||||
return if (newDateTime == relativelyTo) {
|
||||
relativelyTo to false
|
||||
} else {
|
||||
newDateTime to true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun NearDateTimeCalculatorMillis(
|
||||
times: Array<Short>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.milliseconds.toShort() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.milliseconds) {
|
||||
dateTime.plus(1.seconds)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(milliseconds = newOne.toInt())
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorSeconds(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.seconds.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.seconds) {
|
||||
dateTime.plus(1.minutes)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(second = newOne.toInt(), milliseconds = 0)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorMinutes(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.minutes.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.minutes) {
|
||||
dateTime.plus(1.hours)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(minute = newOne.toInt(), second = 0, milliseconds = 0)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorHours(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.hours.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.hours) {
|
||||
dateTime.plus(1.days)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(hour = newOne.toInt(), minute = 0, second = 0, milliseconds = 0)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorDays(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.dayOfMonth.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.dayOfMonth) {
|
||||
dateTime.plus(1.months)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(
|
||||
dayOfMonth = min(dateTime.month.days(dateTime.year), newOne.toInt() + 1), // index1
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0,
|
||||
milliseconds = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorMonths(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.dayOfMonth.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
(if (newOne < dateTime.month0) {
|
||||
dateTime.plus(1.years)
|
||||
} else {
|
||||
dateTime
|
||||
}).copy(
|
||||
month = newOne.toInt() + 1, // index1
|
||||
dayOfMonth = 1, // index1
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0,
|
||||
milliseconds = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorWeekDays(
|
||||
times: Array<Byte>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.dayOfWeek.index0.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
val currentDayOfWeek = dateTime.dayOfWeek.index0
|
||||
(if (newOne < currentDayOfWeek) {
|
||||
dateTime.plus(7.days - (currentDayOfWeek - newOne).days)
|
||||
} else {
|
||||
dateTime.plus(newOne.toInt().days - currentDayOfWeek.days)
|
||||
}).copy(
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0,
|
||||
milliseconds = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
internal fun NearDateTimeCalculatorYears(
|
||||
times: Array<Int>
|
||||
) = NearDateTimeCalculator(
|
||||
times,
|
||||
{ it.yearInt },
|
||||
{ dateTime, newOne ->
|
||||
val currentYear = dateTime.yearInt
|
||||
(if (newOne < currentYear) {
|
||||
null
|
||||
} else {
|
||||
dateTime.plus(newOne.years - currentYear.years)
|
||||
}) ?.copy(
|
||||
month = 1, // index1
|
||||
dayOfMonth = 1, // index1
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0,
|
||||
milliseconds = 0
|
||||
)
|
||||
}
|
||||
)
|
@ -8,7 +8,7 @@ private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataCon
|
||||
val things = from.split(",")
|
||||
|
||||
val results = things.flatMap {
|
||||
val currentToken = it.toLowerCase().replace(
|
||||
val currentToken = it.lowercase().replace(
|
||||
"f", dataRange.first.toString()
|
||||
).replace(
|
||||
"l", dataRange.last.toString()
|
||||
|
22
src/commonMain/kotlin/dev/inmo/krontab/utils/DateTimeCopy.kt
Normal file
22
src/commonMain/kotlin/dev/inmo/krontab/utils/DateTimeCopy.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import kotlin.math.min
|
||||
|
||||
fun DateTime.copy(
|
||||
year: Int = yearInt,
|
||||
month: Int = month1,
|
||||
dayOfMonth: Int = this.dayOfMonth,
|
||||
hour: Int = hours,
|
||||
minute: Int = minutes,
|
||||
second: Int = seconds,
|
||||
milliseconds: Int = this.milliseconds
|
||||
) = DateTime(
|
||||
year,
|
||||
month,
|
||||
min(Month(month).days(yearInt), dayOfMonth),
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
milliseconds
|
||||
)
|
@ -10,7 +10,8 @@ class TimeZoneTest {
|
||||
@Test
|
||||
fun testDifferentTimeZonesReturnsDifferentTimes() {
|
||||
val scheduler = buildSchedule { seconds { every(1) } }
|
||||
val baseDate = DateTime.now().startOfWeek
|
||||
val additionalMilliseconds = 100.milliseconds
|
||||
val baseDate = DateTime.now().startOfWeek.copy(milliseconds = additionalMilliseconds.millisecondsInt)
|
||||
runTest {
|
||||
for (i in 0 until 7) {
|
||||
val now = baseDate + i.days
|
||||
@ -18,10 +19,10 @@ class TimeZoneTest {
|
||||
val nowTz = now.toOffset(j.hours)
|
||||
val next = scheduler.next(nowTz)!!
|
||||
assertEquals(
|
||||
(nowTz + 1.seconds).utc.unixMillisLong, next.utc.unixMillisLong
|
||||
(nowTz + 1.seconds - additionalMilliseconds).utc.unixMillisLong, next.utc.unixMillisLong
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user