Less sugar

This commit is contained in:
Sad Ellie 2023-02-03 14:10:27 +04:00
parent 32fafb9a66
commit 52d7db579c
8 changed files with 178 additions and 49 deletions

View File

@ -79,6 +79,7 @@ android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
isCoreLibraryDesugaringEnabled = true
}
packagingOptions {
@ -101,6 +102,7 @@ android {
dependencies {
implementation(libs.androidx.core)
coreLibraryDesugaring(libs.android.desugarJdkLibs)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.lifecycle.runtime.compose)

View File

@ -21,7 +21,10 @@ package com.sadellie.unitto
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.plugins.ExtensionAware
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
internal fun Project.configureKotlinAndroid(
@ -47,6 +50,7 @@ internal fun Project.configureKotlinAndroid(
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
isCoreLibraryDesugaringEnabled = true
}
buildFeatures {
@ -75,6 +79,12 @@ internal fun Project.configureKotlinAndroid(
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
add("coreLibraryDesugaring", libs.findLibrary("android.desugarJdkLibs").get())
}
}
fun CommonExtension<*, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) {

View File

@ -24,3 +24,7 @@ plugins {
android {
namespace = "com.sadellie.unitto.data.epoch"
}
dependencies {
testImplementation(libs.junit)
}

View File

@ -18,60 +18,33 @@
package com.sadellie.unitto.data.epoch
import java.math.BigDecimal
import java.util.*
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
object EpochDateConverter {
private val pattern by lazy {
DateTimeFormatter.ofPattern("HHmmssddMMyyyy")
}
fun convertDateToUnix(date: String): String {
return try {
// Here we add some zeros, so that input is 14 symbols long
val inputWithPadding = date.padEnd(14, '0')
// Now we break input that is 14 symbols into pieces
val hour = inputWithPadding.substring(0, 2)
val minute = inputWithPadding.substring(2, 4)
val second = inputWithPadding.substring(4, 6)
val day = inputWithPadding.substring(6, 8)
val month = inputWithPadding.substring(8, 10)
val year = inputWithPadding.substring(10, 14)
val cal = Calendar.getInstance()
cal.set(
year.toIntOrNull() ?: 1970,
(month.toIntOrNull() ?: 1) - 1,
day.toIntOrNull() ?: 0,
hour.toIntOrNull() ?: 0,
minute.toIntOrNull() ?: 0,
second.toIntOrNull() ?: 0,
)
return (cal.timeInMillis / 1000).toString()
LocalDateTime
.parse(date.padEnd(14, '0'), pattern)
.toEpochSecond(ZoneOffset.UTC)
} catch (e: DateTimeParseException) {
0
}.toString()
}
fun convertUnixToDate(unix: String): String {
var date = ""
val cal2 = Calendar.getInstance()
cal2.clear()
cal2.isLenient = true
val unixLong = unix.toLong().takeIf { it <= 253402300559L }
?: throw IllegalArgumentException("Max unix is 253402300559")
// This lets us bypass calendars limits (it uses Int, we want BigDecimal)
try {
val unixBg = BigDecimal(unix.ifEmpty { "0" })
val division = unixBg.divideAndRemainder(BigDecimal(Int.MAX_VALUE))
val intTimes = division.component1()
val rem = division.component2()
repeat(intTimes.intValueExact()) {
cal2.add(Calendar.SECOND, Int.MAX_VALUE)
}
cal2.add(Calendar.SECOND, rem.intValueExact())
} catch (e: NumberFormatException) {
return ""
}
date += cal2.get(Calendar.HOUR_OF_DAY).toString().padStart(2, '0')
date += cal2.get(Calendar.MINUTE).toString().padStart(2, '0')
date += cal2.get(Calendar.SECOND).toString().padStart(2, '0')
date += cal2.get(Calendar.DAY_OF_MONTH).toString().padStart(2, '0')
date += (cal2.get(Calendar.MONTH) + 1).toString().padStart(2, '0')
// Year is 4 symbols long
date += cal2.get(Calendar.YEAR).toString().padStart(4, '0')
return date
return LocalDateTime
.ofEpochSecond(unixLong, 0, ZoneOffset.UTC)
.format(pattern)
}
}

View File

@ -0,0 +1,60 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.epoch
import org.junit.Assert.assertEquals
import org.junit.Test
class DateToEpochTest {
@Test
fun `00h0m00s 00 00 0000`() {
convertDateToUnixTest("00:00:00 00.00.0000", "0")
}
@Test
fun `00h00m00s 01 01 0001`() {
convertDateToUnixTest("00:00:00 01.01.0001", "-62135596800")
}
@Test
fun `00h00m00s 01 01 1970`() {
convertDateToUnixTest("00:00:00 01.01.1970", "0")
}
@Test
fun `23h55m59s 31 12 9999`() {
convertDateToUnixTest("23:55:59 31.12.9999", "253402300559")
}
@Test
fun `99h99m99s 99 99 9999`() {
convertDateToUnixTest("99:99:99 99.99.9999", "0")
}
private fun convertDateToUnixTest(inputDate: String, expectedUnix: String) {
// Date input comes "fancy"
val cleanInputDate = inputDate.filter{ it.isDigit() }
assertEquals(
"Couldn't convert $inputDate ($cleanInputDate) into unix",
expectedUnix,
EpochDateConverter.convertDateToUnix(cleanInputDate)
)
}
}

View File

@ -0,0 +1,72 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.data.epoch
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test
class EpochToDateTest {
@Test
fun `0`() {
convertUnixToDate("0", "00:00:00 01.01.1970")
}
@Test
fun `00000000000000 max input length`() {
convertUnixToDate("00000000000000", "00:00:00 01.01.1970")
}
@Test
fun `253402300559 max possible date`() {
convertUnixToDate("253402300559", "23:55:59 31.12.9999")
}
@Test
fun `2534023005599999 input longe than allowed`() {
convertUnixToDate("2534023005599999", "23:55:59 31.12.9999", IllegalArgumentException())
}
@Test
fun `99999999999999 max possible unix with max length`() {
convertUnixToDate("99999999999999", "23:55:59 31.12.9999", IllegalArgumentException())
}
private fun convertUnixToDate(inputUnix: String, expectedDate: String, throwable: Throwable? = null) {
// Date input comes "fancy"
val cleanExpectedDate = expectedDate.filter{ it.isDigit() }
// Will throw
if (throwable != null) {
assertThrows(
"Failed to throw ${throwable.javaClass} when converting $inputUnix into $expectedDate ($cleanExpectedDate)",
throwable.javaClass
) { EpochDateConverter.convertUnixToDate(inputUnix) }
return
}
// Should actually convert
assertEquals(
"Couldn't convert $inputUnix into $expectedDate ($cleanExpectedDate)",
cleanExpectedDate,
EpochDateConverter.convertUnixToDate(inputUnix)
)
}
}

View File

@ -52,9 +52,15 @@ class EpochViewModel @Inject constructor() : ViewModel() {
dateToUnix = fromDateToUnix
)
} else {
val date = try {
EpochDateConverter.convertUnixToDate(input)
} catch (e: IllegalArgumentException) {
""
}
EpochUIState(
unixField = input,
dateField = EpochDateConverter.convertUnixToDate(input),
dateField = date,
dateToUnix = fromDateToUnix
)
}

View File

@ -4,6 +4,7 @@ appName = "Glaucous"
androidxCore = "1.9.0"
androidxTest = "1.5.0"
androidxTestExt = "1.1.4"
androidDesugarJdkLibs = "2.0.0"
junit = "4.13.2"
androidxTestRunner = "1.5.1"
androidxTestRules = "1.5.0"
@ -61,6 +62,7 @@ com-squareup-retrofit2 = { group = "com.squareup.retrofit2", name = "converter-m
com-github-sadellie-themmo = { group = "com.github.sadellie", name = "themmo", version.ref = "comGithubSadellieThemmo" }
org-burnoutcrew-composereorderable = { group = "org.burnoutcrew.composereorderable", name = "reorderable", version.ref = "orgBurnoutcrewComposereorderable" }
com-github-sadellie-exprk = { group = "com.github.sadellie", name = "ExprK", version.ref = "comGithubSadellieExprk" }
android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" }
# classpath
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }