Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand code generation to include conversions between date types #108

Merged
merged 1 commit into from
Jul 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions core/src/commonMain/generated/io/islandtime/_Conversions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// This file is auto-generated by 'tools:code-generator'
//
@file:JvmMultifileClass
@file:JvmName("DateTimesKt")

package io.islandtime

import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

/**
* Returns this year-month with the precision reduced to the year.
*/
fun YearMonth.toYear(): Year = Year(year)

/**
* Returns this date with the precision reduced to the year.
*/
fun Date.toYear(): Year = Year(year)

/**
* Returns this date with the precision reduced to the month.
*/
fun Date.toYearMonth(): YearMonth = YearMonth(year, month)

/**
* Returns this date-time with the precision reduced to the year.
*/
fun DateTime.toYear(): Year = date.toYear()

/**
* Returns this date-time with the precision reduced to the month.
*/
fun DateTime.toYearMonth(): YearMonth = date.toYearMonth()

/**
* Returns this date-time with the precision reduced to the year.
*/
fun OffsetDateTime.toYear(): Year = dateTime.toYear()

/**
* Returns this date-time with the precision reduced to the month.
*/
fun OffsetDateTime.toYearMonth(): YearMonth = dateTime.toYearMonth()

/**
* Returns this date-time with the precision reduced to the year.
*/
fun ZonedDateTime.toYear(): Year = dateTime.toYear()

/**
* Returns this date-time with the precision reduced to the month.
*/
fun ZonedDateTime.toYearMonth(): YearMonth = dateTime.toYearMonth()
45 changes: 0 additions & 45 deletions core/src/commonMain/kotlin/io/islandtime/Conversions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,6 @@ import io.islandtime.base.TimePoint
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

/**
* Returns this date with the precision reduced to the year.
*/
fun YearMonth.toYear(): Year = Year(year)

/**
* Returns this date with the precision reduced to the year.
*/
fun Date.toYear(): Year = Year(year)

/**
* Returns this date-time with the precision reduced to the year.
*/
fun DateTime.toYear(): Year = date.toYear()

/**
* Returns this date-time with the precision reduced to the year.
*/
fun OffsetDateTime.toYear(): Year = date.toYear()

/**
* Returns this date-time with the precision reduced to the year.
*/
fun ZonedDateTime.toYear(): Year = date.toYear()

/**
* Returns this date with the precision reduced to the year-month.
*/
fun Date.toYearMonth(): YearMonth = YearMonth(year, month)

/**
* Returns this date-time with the precision reduced to the year-month.
*/
fun DateTime.toYearMonth(): YearMonth = date.toYearMonth()

/**
* Returns this date-time with the precision reduced to the year-month.
*/
fun OffsetDateTime.toYearMonth(): YearMonth = dateTime.toYearMonth()

/**
* Returns this date-time with the precision reduced to the year-month.
*/
fun ZonedDateTime.toYearMonth(): YearMonth = dateTime.toYearMonth()

/**
* Returns the combined time and UTC offset.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.islandtime.codegen

import com.squareup.kotlinpoet.ClassName
import io.islandtime.codegen.generators.ConstantsGenerator
import io.islandtime.codegen.generators.DateConversionsGenerator
import io.islandtime.codegen.generators.DatePropertiesGenerator
import io.islandtime.codegen.generators.TemporalUnitGenerator
import java.io.File
Expand All @@ -21,7 +22,8 @@ fun calendar(name: String) = ClassName(CALENDAR_PACKAGE_NAME, name)
private val generators = arrayOf(
TemporalUnitGenerator,
ConstantsGenerator,
DatePropertiesGenerator
DatePropertiesGenerator,
DateConversionsGenerator
)

fun main() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,63 @@ import com.squareup.kotlinpoet.TypeName
import io.islandtime.codegen.base

enum class DateTimeDescription {
Year {
override val typeName: TypeName get() = base("Year")
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.YEARS
override val simpleName: String get() = "year"
override val isDateBased: Boolean = true
},
YearMonth {
override val typeName: TypeName get() = base("YearMonth")
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.MONTHS
override val simpleName: String get() = "year-month"
override val isDateBased: Boolean = true
},
Date {
override val typeName: TypeName get() = base("Date")
override val datePropertyName: String get() = "this"
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.DAYS
override val simpleName: String get() = "date"
override val isDateBased: Boolean = true
},
DateTime {
override val typeName: TypeName get() = base("DateTime")
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.NANOSECONDS
override val datePropertyName: String get() = "date"
override val simpleName: String get() = "date-time"
override val isDateBased: Boolean = true
},
OffsetDateTime {
override val typeName: TypeName get() = base("OffsetDateTime")
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.NANOSECONDS
override val datePropertyName: String get() = "dateTime"
override val simpleName: String get() = "date-time"
override val isDateBased: Boolean = true
},
ZonedDateTime {
override val typeName: TypeName get() = base("ZonedDateTime")
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.NANOSECONDS
override val datePropertyName: String get() = "dateTime"
override val simpleName: String get() = "date-time"
override val isDateBased: Boolean = true
},
Instant {
override val typeName: TypeName get() = base("Instant")
override val datePropertyName: String get() = ""
override val smallestUnit: TemporalUnitDescription get() = TemporalUnitDescription.NANOSECONDS
override val simpleName: String get() = "instant"
};

abstract val typeName: TypeName
abstract val datePropertyName: String
abstract val smallestUnit: TemporalUnitDescription
abstract val simpleName: String

val isDateBased: Boolean get() = datePropertyName.isNotEmpty()
open val isDateBased: Boolean = false

open val datePropertyName: String get() = throw NotImplementedError()

open fun convertsDirectlyTo(other: DateTimeDescription): Boolean {
return isDateBased &&
other.isDateBased &&
other.smallestUnit > smallestUnit &&
other.smallestUnit > TemporalUnitDescription.DAYS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ enum class TemporalUnitDescription(
val intName: String get() = "Int$pluralName"
val longName: String get() = "Long$pluralName"
open val singularName: String get() = pluralName.dropLast(1)
val lowerCaseName: String get() = pluralName.toLowerCase(Locale.US)
val lowerSingularName: String get() = singularName.toLowerCase(Locale.US)
val lowerPluralName: String get() = pluralName.toLowerCase(Locale.US)
val valueName: String get() = "value"
val inUnitPropertyName: String get() = "in$pluralName"
val inUnitUncheckedPropertyName: String get() = "${inUnitPropertyName}Unchecked"
Expand Down Expand Up @@ -86,7 +87,7 @@ data class TemporalUnitConversion(

val constantName: String
get() {
val (smallerUnit, largerUnit) = smallerUnitToLargerUnit()
val (smallerUnit, largerUnit) = orderedFromSmallerToLargerUnit()
return "${smallerUnit.pluralName}_PER_${largerUnit.singularName}".toUpperCase(Locale.US)
}

Expand All @@ -98,7 +99,7 @@ data class TemporalUnitConversion(
}

val constantValue: Long by lazy {
val (smallerUnit, largerUnit) = smallerUnitToLargerUnit()
val (smallerUnit, largerUnit) = orderedFromSmallerToLargerUnit()

(smallerUnit.ordinal until largerUnit.ordinal)
.map { TemporalUnitDescription.values()[it].conversionFactor.toLong() }
Expand All @@ -117,7 +118,7 @@ data class TemporalUnitConversion(
}
}

private fun smallerUnitToLargerUnit() = if (fromUnit <= toUnit) {
private fun orderedFromSmallerToLargerUnit() = if (fromUnit <= toUnit) {
fromUnit to toUnit
} else {
toUnit to fromUnit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.islandtime.codegen.generators

import com.squareup.kotlinpoet.FileSpec
import io.islandtime.codegen.SingleFileGenerator
import io.islandtime.codegen.descriptions.DateTimeDescription
import io.islandtime.codegen.descriptions.DateTimeDescription.*
import io.islandtime.codegen.descriptions.TemporalUnitDescription
import io.islandtime.codegen.dsl.FileBuilder
import io.islandtime.codegen.dsl.FunctionBuilder
import io.islandtime.codegen.dsl.file

object DateConversionsGenerator : SingleFileGenerator() {
override fun generateSingle(): FileSpec = buildDateConversionsFile()
}

private fun buildDateConversionsFile() = file(
packageName = "io.islandtime",
fileName = "_Conversions",
jvmName = "DateTimesKt"
) {
DateTimeDescription.values().forEach { receiverClass ->
DateTimeDescription.values()
.filter { otherClass -> receiverClass.convertsDirectlyTo(otherClass) }
.forEach { otherClass -> buildConversionFunction(from = receiverClass, to = otherClass) }
}
}

private fun FileBuilder.buildConversionFunction(from: DateTimeDescription, to: DateTimeDescription) {
function(name = "to${to.name}") {
kdoc {
"Returns this ${from.simpleName} with the precision reduced to the ${to.smallestUnit.lowerSingularName}."
}

receiver(from.typeName)
returns(to.typeName)

if (from.smallestUnit < TemporalUnitDescription.DAYS) {
delegatesTo(from.datePropertyName)
} else {
construct(from, to)
}
}
}

private fun FunctionBuilder.construct(from: DateTimeDescription, to: DateTimeDescription) {
code {
when (to) {
Year -> {
require(from in arrayOf(Date, YearMonth)) { "Cannot construct '$to' from '$from'" }
"return Year(year)"
}
YearMonth -> {
require(from == Date) { "Cannot construct '$to' from '$from'" }
"return YearMonth(year, month)"
}
else -> throw IllegalArgumentException("Cannot construct '$to'")
}
}
}
Loading