mirror of
https://github.com/InsanusMokrassar/krontab.git
synced 2024-11-22 16:23:55 +00:00
commit
5a6084c573
2
.github/workflows/publishing_packages.yml
vendored
2
.github/workflows/publishing_packages.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
- name: prebuild
|
||||
run: ./gradlew clean build
|
||||
- name: Publish package
|
||||
run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication -x signMetadataPublication -x signAndroidDebugPublication -x signAndroidReleasePublication
|
||||
run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication -x signMetadataPublication -x signAndroidReleasePublication
|
||||
env:
|
||||
GITHUBPACKAGES_USER: ${{ github.actor }}
|
||||
GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.6.1
|
||||
|
||||
* Versions
|
||||
* `Klock`: `2.1.0` -> `2.1.2`
|
||||
* Rewriting of default mechanism of `KronScheduler`s
|
||||
|
||||
## 0.6.0
|
||||
|
||||
* Versions
|
||||
|
@ -13,7 +13,7 @@ kotlin_coroutines_version=1.5.0
|
||||
|
||||
dokka_version=1.4.32
|
||||
|
||||
klockVersion=2.1.0
|
||||
klockVersion=2.1.2
|
||||
|
||||
## Github reease
|
||||
|
||||
@ -33,6 +33,6 @@ androidx_work_version=2.5.0
|
||||
|
||||
## Common
|
||||
|
||||
version=0.6.0
|
||||
android_code_version=4
|
||||
version=0.6.1
|
||||
android_code_version=5
|
||||
|
||||
|
@ -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)
|
||||
|
@ -2,105 +2,63 @@ package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
import dev.inmo.krontab.utils.copy
|
||||
|
||||
/**
|
||||
* @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(
|
||||
years ?.let { NearDateTimeCalculatorYears(it) },
|
||||
daysOfWeek ?.let { NearDateTimeCalculatorWeekDays(it) },
|
||||
NearDateTimeCalculatorMillis(arrayOf(0)),
|
||||
seconds ?.let { NearDateTimeCalculatorSeconds(it) },
|
||||
minutes ?.let { NearDateTimeCalculatorMinutes(it) },
|
||||
hours ?.let { NearDateTimeCalculatorHours(it) },
|
||||
daysOfMonth ?.let { NearDateTimeCalculatorDays(it) },
|
||||
months ?.let { NearDateTimeCalculatorMonths(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
|
||||
}
|
||||
|
||||
internal fun createCronDateTimeList(
|
||||
internal fun createCronDateTime(
|
||||
seconds: Array<Byte>? = null,
|
||||
minutes: Array<Byte>? = null,
|
||||
hours: Array<Byte>? = null,
|
||||
@ -108,38 +66,8 @@ 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)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,7 +81,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 +94,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,183 @@
|
||||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import dev.inmo.krontab.utils.copy
|
||||
import kotlin.math.min
|
||||
|
||||
fun interface NearDateTimeCalculator {
|
||||
/**
|
||||
* @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>?
|
||||
}
|
||||
|
||||
internal class CommonNearDateTimeCalculator<T>(
|
||||
private val times: Array<T>,
|
||||
private val partGetter: (DateTime) -> T,
|
||||
private val partSetter: (DateTime, T) -> DateTime?
|
||||
) : NearDateTimeCalculator where T : Comparable<T>, T : Number {
|
||||
/**
|
||||
* @return pair of near [DateTime] for this checker and [Boolean] flag that all previous calculations must be
|
||||
* recalculated
|
||||
*/
|
||||
override fun calculateNearTime(
|
||||
relativelyTo: DateTime
|
||||
): Pair<DateTime, Boolean>? {
|
||||
val currentData = partGetter(relativelyTo)
|
||||
val greaterOrEquals = times.firstOrNull { it >= currentData }
|
||||
val newDateTime = when (greaterOrEquals) {
|
||||
null -> partSetter(relativelyTo, times.first()) ?: return null
|
||||
currentData -> relativelyTo
|
||||
else -> partSetter(relativelyTo, greaterOrEquals) ?: return null
|
||||
}
|
||||
return if (newDateTime == relativelyTo) {
|
||||
relativelyTo to false
|
||||
} else {
|
||||
newDateTime to true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun NearDateTimeCalculatorMillis(
|
||||
times: Array<Short>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
times,
|
||||
{ it.dayOfWeek.index0.toByte() },
|
||||
{ dateTime, newOne ->
|
||||
val currentDayOfWeek = dateTime.dayOfWeek.index0
|
||||
if (newOne.toInt() == currentDayOfWeek) return@CommonNearDateTimeCalculator dateTime
|
||||
(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>
|
||||
) = CommonNearDateTimeCalculator(
|
||||
times,
|
||||
{ it.yearInt },
|
||||
{ dateTime, newOne ->
|
||||
val currentYear = dateTime.yearInt
|
||||
if (newOne == currentYear) return@CommonNearDateTimeCalculator dateTime
|
||||
(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
|
||||
)
|
@ -15,9 +15,16 @@ import kotlinx.coroutines.flow.*
|
||||
*/
|
||||
@FlowPreview
|
||||
fun KronScheduler.asTzFlow(): Flow<DateTimeTz> = channelFlow {
|
||||
var previousTime = DateTime.nowLocal()
|
||||
while (isActive) {
|
||||
val now = DateTime.now().local
|
||||
val now = DateTime.nowLocal()
|
||||
val nextTime = next(now) ?: break
|
||||
if (previousTime == nextTime) {
|
||||
delay(1L) // skip 1ms
|
||||
continue
|
||||
} else {
|
||||
previousTime = nextTime
|
||||
}
|
||||
val sleepDelay = (nextTime - DateTime.now().local).millisecondsLong
|
||||
delay(sleepDelay)
|
||||
send(nextTime)
|
||||
@ -48,4 +55,4 @@ class SchedulerFlow(
|
||||
collector.emit(nextTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ class StringParseTest {
|
||||
val flow = kronScheduler.asFlow()
|
||||
|
||||
runTest {
|
||||
val ranges = rangesEnds.map { it.first .. it.second }.flatten().toMutableList()
|
||||
val expectedCollects = rangesEnds.sumOf { it.second - it.first + 1 }
|
||||
val ranges = rangesEnds.map { it.first .. it.second }.flatten().distinct().toMutableList()
|
||||
val expectedCollects = ranges.size
|
||||
var collected = 0
|
||||
|
||||
flow.takeWhile { ranges.isNotEmpty() }.collect {
|
||||
@ -80,7 +80,7 @@ class StringParseTest {
|
||||
}
|
||||
@Test
|
||||
fun testThatTimezoneCorrectlyDeserialized() {
|
||||
val now = DateTimeTz.nowLocal()
|
||||
val now = DateTime.now().copy(milliseconds = 0).local
|
||||
|
||||
runTest {
|
||||
for (i in 0 .. 1339) {
|
||||
|
@ -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