Skip to content

Instantly share code, notes, and snippets.

@alashow
Created April 17, 2019 00:16
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alashow/c2b433c61fac4f78da372c60f7618109 to your computer and use it in GitHub Desktop.
Save alashow/c2b433c61fac4f78da372c60f7618109 to your computer and use it in GitHub Desktop.
Kotlin Calendar/Date utils
import java.util.Calendar
import java.util.Date
class CalendarRange(override val start: Calendar, override val endInclusive: Calendar, val field: Int = Calendar.DAY_OF_YEAR) :
ClosedRange<Calendar>, Iterable<Calendar> {
override fun iterator(): Iterator<Calendar> {
return CalendarIterator(start, endInclusive, field)
}
}
open class CalendarIterator(start: Calendar, private val endInclusive: Calendar, private val field: Int = Calendar.DAY_OF_YEAR) : Iterator<Calendar> {
private var current = start.let {
if (field !in Calendar.AM_PM..Calendar.MILLISECOND) {
it.timeless()
} else it
}
override fun hasNext(): Boolean {
return current <= endInclusive
}
override fun next(): Calendar {
val current = current
this.current = current.addPure(field, 1)
return current
}
}
class DateRange(override val start: Date, override val endInclusive: Date, val field: Int = Calendar.DAY_OF_YEAR) :
ClosedRange<Date>, Iterable<Date> {
override fun iterator(): Iterator<Date> = DateIterator(start, endInclusive, field)
}
class DateIterator(start: Date, private val endInclusive: Date, private val field: Int = Calendar.DAY_OF_YEAR) : Iterator<Date> {
private var current = start.let {
if (field !in Calendar.AM_PM..Calendar.MILLISECOND) {
it.timeless()
} else it
}
override fun hasNext(): Boolean {
return current <= endInclusive
}
override fun next(): Date {
val current = current
this.current = current.addPure(field, 1)
return current
}
}
infix operator fun Calendar.rangeTo(that: Calendar) = CalendarRange(this, that)
infix operator fun Date.rangeTo(that: Date) = DateRange(this, that)
import java.util.Calendar
import java.util.Date
fun Calendar.toDate(): Date = time
fun Date.toCalendar(): Calendar = Calendar.getInstance().also {
it.timeInMillis = this.time
}
fun Long.toCalendar() = Calendar.getInstance().also {
it.timeInMillis = this
}
fun Calendar.copy() = clone() as Calendar
/**
* @param month starting from 0, as [Calendar.MONTH].
*/
fun calendar(year: Int, month: Int, date: Int, hourOfDay: Int = 0, minute: Int = 0, seconds: Int = 0): Calendar {
val calendar = Calendar.getInstance()
calendar.set(year, month, date, hourOfDay, minute, seconds)
return calendar
}
fun Calendar.year() = get(Calendar.YEAR)
fun Calendar.month() = get(Calendar.MONTH)
fun Calendar.day() = get(Calendar.DAY_OF_MONTH)
fun Calendar.minute() = get(Calendar.MINUTE)
fun Calendar.second() = get(Calendar.SECOND)
fun Calendar.dayPadded() = "%01d".format(day())
fun Calendar.dayOfYear() = get(Calendar.DAY_OF_YEAR)
fun Calendar.toDateString() = "${year()}, ${month()}, ${day()}"
operator fun Calendar.component1() = year()
operator fun Calendar.component2() = month()
operator fun Calendar.component3() = day()
operator fun Calendar.component4() = minute()
operator fun Calendar.component5() = second()
infix fun Calendar.sameYear(other: Calendar) = year() == other.year()
infix fun Calendar.sameMonth(other: Calendar) = month() == other.month()
infix fun Calendar.sameDate(other: Calendar) = sameYear(other) && sameMonth(other) && (day() == other.day())
infix fun Date.sameYear(other: Calendar) = toCalendar().sameYear(other)
infix fun Date.sameYear(other: Date) = sameYear(other.toCalendar())
infix fun Date.sameMonth(other: Date) = toCalendar().sameMonth(other.toCalendar())
infix fun Date.sameDate(other: Date) = toCalendar().sameDate(other.toCalendar())
infix fun Calendar.diff(end: Calendar): Long {
val startTime = timeInMillis
val endTime = end.timeInMillis
return endTime - startTime
}
infix fun Calendar.diffInDays(end: Calendar): Long {
val diffTime = diff(end)
return diffTime / (1000 * 60 * 60 * 24)
}
fun Calendar.addPure(field: Int, value: Int): Calendar = this.copy().apply {
add(field, value)
}
fun Date.addPure(field: Int, value: Int): Date = toCalendar().addPure(field, value).time
infix fun Calendar.addDays(days: Int): Calendar = addPure(Calendar.DAY_OF_YEAR, days)
infix fun Calendar.addMonths(months: Int): Calendar = addPure(Calendar.MONTH, months)
infix fun Calendar.addYears(years: Int): Calendar = addPure(Calendar.YEAR, years)
infix fun Date.addDays(days: Int): Date = (toCalendar() addDays days).time
infix fun Date.addMonths(months: Int): Date = (toCalendar() addMonths months).time
infix fun Date.addYears(years: Int): Date = (toCalendar() addYears years).time
infix operator fun Calendar.minus(that: Calendar) = (timeInMillis - that.timeInMillis).toCalendar()
infix operator fun Calendar.plus(that: Calendar) = (timeInMillis + that.timeInMillis).toCalendar()
infix operator fun Date.minus(that: Date) = Date(time - that.time)
infix operator fun Date.plus(that: Date) = Date(time + that.time)
infix operator fun Calendar.compareTo(that: Date): Int = (timeInMillis - that.time).toInt()
infix operator fun Calendar.compareTo(that: Calendar): Int = (timeInMillis - that.timeInMillis).toInt()
infix operator fun Date.compareTo(that: Date): Int = (time - that.time).toInt()
infix operator fun Date.compareTo(that: Calendar): Int = (time - that.timeInMillis).toInt()
operator fun Calendar.inc() = this addDays 1
operator fun Calendar.dec() = this addDays -1
operator fun Date.inc() = this addDays 1
operator fun Date.dec() = this addDays -1
fun Calendar.isLeapYear(): Boolean {
var year = get(Calendar.YEAR)
if (year % 100 == 0)
year /= 100
return year % 4 == 0
}
fun Calendar.daysInAYear() = when (isLeapYear()) {
true -> 366
else -> 365
}
infix fun Calendar.yearsDiff(end: Calendar): Float {
val years = (year() - end.year()).toFloat()
val dayOfYearDiff = (dayOfYear() - end.dayOfYear())
return years - dayOfYearDiff.toFloat() / daysInAYear().toFloat()
}
fun Calendar.timeless(): Calendar = this.copy().apply {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
fun Date.timeless(): Date = toCalendar().timeless().time
fun List<Date>.timeless(): List<Date> = map { it.timeless() }
fun List<Calendar>.limit(min: Calendar? = null, max: Calendar? = null) = map {
when {
min != null && it < min -> min
max != null && it > max -> max
else -> it
}
}
fun List<Date>.limit(min: Date? = null, max: Date? = null) = map {
when {
min != null && it < min -> min
max != null && it > max -> max
else -> it
}
}
fun List<Date>.isValid(min: Date? = null, max: Date? = null) = map {
when {
min != null && it < min -> false
max != null && it > max -> false
else -> true
}
}.all { it }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment