Time.kt (3806B)
1 /* 2 * This file is part of GNU Taler 3 * (C) 2020 Taler Systems S.A. 4 * 5 * GNU Taler is free software; you can redistribute it and/or modify it under the 6 * terms of the GNU General Public License as published by the Free Software 7 * Foundation; either version 3, or (at your option) any later version. 8 * 9 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY 10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 package net.taler.common 18 19 import kotlinx.serialization.SerialName 20 import kotlinx.serialization.Serializable 21 import kotlinx.serialization.builtins.serializer 22 import kotlinx.serialization.json.JsonElement 23 import kotlinx.serialization.json.JsonPrimitive 24 import kotlinx.serialization.json.JsonTransformingSerializer 25 import kotlinx.serialization.json.contentOrNull 26 import kotlinx.serialization.json.jsonPrimitive 27 import kotlinx.serialization.json.longOrNull 28 import kotlin.math.max 29 30 @Serializable 31 data class Timestamp( 32 @SerialName("t_s") 33 @Serializable(NeverSerializer::class) 34 private val s: Long, 35 ) : Comparable<Timestamp> { 36 37 companion object { 38 private const val NEVER: Long = -1 39 fun now(): Timestamp = fromMillis(System.currentTimeMillis()) 40 fun never(): Timestamp = Timestamp(NEVER) 41 fun fromMillis(ms: Long) = Timestamp(ms / 1000L) 42 } 43 44 val ms: Long = s * 1000L 45 46 operator fun minus(other: Timestamp): RelativeTime = when { 47 ms == NEVER -> RelativeTime.fromMillis(RelativeTime.FOREVER) 48 other.ms == NEVER -> throw Error("Invalid argument for timestamp comparison") 49 ms < other.ms -> RelativeTime.fromMillis(0) 50 else -> RelativeTime.fromMillis(ms - other.ms) 51 } 52 53 operator fun plus(other: RelativeTime): Timestamp = when { 54 ms == NEVER -> this 55 other.ms == RelativeTime.FOREVER -> never() 56 else -> fromMillis(ms + other.ms) 57 } 58 59 operator fun minus(other: RelativeTime): Timestamp = when { 60 ms == NEVER -> this 61 other.ms == RelativeTime.FOREVER -> fromMillis(0) 62 else -> fromMillis(max(0, ms - other.ms)) 63 } 64 65 override fun compareTo(other: Timestamp): Int { 66 return if (ms == NEVER) { 67 if (other.ms == NEVER) 0 68 else 1 69 } else { 70 if (other.ms == NEVER) -1 71 else ms.compareTo(other.ms) 72 } 73 } 74 75 } 76 77 @Serializable 78 data class RelativeTime( 79 /** 80 * Duration in microseconds or "forever" to represent an infinite duration. 81 * Numeric values are capped at 2^53 - 1 inclusive. 82 */ 83 @SerialName("d_us") 84 @Serializable(ForeverSerializer::class) 85 private val us: Long, 86 ) { 87 val ms: Long = us / 1000L 88 89 companion object { 90 internal const val FOREVER: Long = -1 91 fun forever(): RelativeTime = fromMillis(FOREVER) 92 fun fromMillis(ms: Long) = RelativeTime(ms / 100L) 93 } 94 } 95 96 internal abstract class MinusOneSerializer(private val keyword: String) : 97 JsonTransformingSerializer<Long>(Long.serializer()) { 98 99 override fun transformDeserialize(element: JsonElement): JsonElement { 100 return if (element.jsonPrimitive.contentOrNull == keyword) return JsonPrimitive(-1) 101 else super.transformDeserialize(element) 102 } 103 104 override fun transformSerialize(element: JsonElement): JsonElement { 105 return if (element.jsonPrimitive.longOrNull == -1L) return JsonPrimitive(keyword) 106 else element 107 } 108 } 109 110 internal object NeverSerializer : MinusOneSerializer("never") 111 internal object ForeverSerializer : MinusOneSerializer("forever")