darwinMain.io.islandtime.format.DateTimeTextProvider.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-metadata Show documentation
Show all versions of core-metadata Show documentation
A multiplatform library for working with dates and times
The newest version!
package io.islandtime.format
import io.islandtime.DateTimeException
import io.islandtime.base.DateTimeField
import io.islandtime.internal.confine
import io.islandtime.locale.Locale
import platform.Foundation.NSCalendar
import platform.Foundation.NSCalendarIdentifierISO8601
import kotlin.native.concurrent.Worker
@SharedImmutable
private val worker = Worker.start(errorReporting = false)
actual object PlatformDateTimeTextProvider : DateTimeTextProvider {
private val narrowEraTextSymbols = listOf("B", "A")
private val parsableText = worker.confine { hashMapOf() }
private val descendingTextComparator =
compareByDescending> { it.first.length }.thenBy { it.second }
private data class ParsableTextKey(
val field: DateTimeField,
val styles: Set,
val locale: Locale
)
override fun parsableTextFor(field: DateTimeField, styles: Set, locale: Locale): ParsableTextList {
if (styles.isEmpty() || !supports(field)) {
return emptyList()
}
val key = ParsableTextKey(field, styles, locale)
return parsableText.use {
it.getOrPut(key) {
val valueMap = hashMapOf>()
styles.forEach { style ->
allTextFor(field, style, locale)?.forEachIndexed { index, symbol ->
valueMap.getOrPut(symbol) { mutableSetOf() } += valueForArrayIndex(field, index)
}
}
valueMap.mapNotNull {
if (it.value.size == 1) {
it.key to it.value.first()
} else {
null
}
}.sortedWith(descendingTextComparator)
}
}
}
override fun dayOfWeekTextFor(value: Long, style: TextStyle, locale: Locale): String? {
if (value !in 1L..7L) {
throw DateTimeException("'$value' is outside the supported day of week field range")
}
return allDayOfWeekTextFor(style, locale)?.run {
val index = if (value == 7L) 0 else value.toInt()
get(index)
}
}
override fun monthTextFor(value: Long, style: TextStyle, locale: Locale): String? {
if (value !in 1L..12L) {
throw DateTimeException("'$value' is outside the supported month of year field range")
}
return allMonthTextFor(style, locale)?.get(value.toInt() - 1)
}
override fun amPmTextFor(value: Long, locale: Locale): String? {
return withCalendarIn(locale) {
when (value) {
0L -> AMSymbol
1L -> PMSymbol
else -> throw DateTimeException("'$value' is outside the supported AM/PM range")
}
}
}
override fun eraTextFor(value: Long, style: TextStyle, locale: Locale): String? {
if (value !in 0L..1L) {
throw DateTimeException("'$value' is outside the supported era field range")
}
return allEraTextFor(style, locale)?.get(value.toInt())
}
private fun supports(field: DateTimeField): Boolean {
return when (field) {
DateTimeField.MONTH_OF_YEAR,
DateTimeField.DAY_OF_WEEK,
DateTimeField.AM_PM_OF_DAY,
DateTimeField.ERA -> true
else -> false
}
}
private fun allTextFor(field: DateTimeField, style: TextStyle, locale: Locale): List? {
return when (field) {
DateTimeField.MONTH_OF_YEAR -> allMonthTextFor(style, locale)
DateTimeField.DAY_OF_WEEK -> allDayOfWeekTextFor(style, locale)
DateTimeField.AM_PM_OF_DAY -> allAmPmTextFor(locale)
DateTimeField.ERA -> allEraTextFor(style, locale)
else -> throw IllegalStateException("Unexpected field")
}
}
private fun valueForArrayIndex(field: DateTimeField, index: Int): Long {
return when (field) {
DateTimeField.MONTH_OF_YEAR -> index + 1L
DateTimeField.DAY_OF_WEEK -> if (index == 0) 7L else index.toLong()
else -> index.toLong()
}
}
@Suppress("UNCHECKED_CAST")
private fun allDayOfWeekTextFor(style: TextStyle, locale: Locale): List? {
return withCalendarIn(locale) {
when (style) {
TextStyle.FULL -> weekdaySymbols
TextStyle.FULL_STANDALONE -> standaloneWeekdaySymbols
TextStyle.SHORT -> shortWeekdaySymbols
TextStyle.SHORT_STANDALONE -> shortStandaloneWeekdaySymbols
TextStyle.NARROW -> veryShortWeekdaySymbols
TextStyle.NARROW_STANDALONE -> veryShortStandaloneWeekdaySymbols
} as List
}
}
@Suppress("UNCHECKED_CAST")
private fun allMonthTextFor(style: TextStyle, locale: Locale): List? {
return withCalendarIn(locale) {
when (style) {
TextStyle.FULL -> monthSymbols
TextStyle.FULL_STANDALONE -> standaloneMonthSymbols
TextStyle.SHORT -> shortMonthSymbols
TextStyle.SHORT_STANDALONE -> shortStandaloneMonthSymbols
TextStyle.NARROW -> veryShortMonthSymbols
TextStyle.NARROW_STANDALONE -> veryShortStandaloneMonthSymbols
} as List
}
}
private fun allAmPmTextFor(locale: Locale): List? {
return withCalendarIn(locale) {
listOf(AMSymbol, PMSymbol)
}
}
@Suppress("UNCHECKED_CAST")
private fun allEraTextFor(style: TextStyle, locale: Locale): List? {
return when (style) {
TextStyle.NARROW, TextStyle.NARROW_STANDALONE -> narrowEraTextSymbols
else -> withCalendarIn(locale) {
when (style) {
TextStyle.FULL, TextStyle.FULL_STANDALONE -> longEraSymbols
else -> eraSymbols
} as List
}
}
}
private inline fun withCalendarIn(locale: Locale, block: NSCalendar.() -> T): T? {
return NSCalendar.calendarWithIdentifier(NSCalendarIdentifierISO8601)?.also {
it.locale = locale
}?.block()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy