diff --git a/benchmarks/api/benchmarks.api b/benchmarks/api/benchmarks.api new file mode 100644 index 000000000..e69de29bb diff --git a/build.gradle.kts b/build.gradle.kts index 0c16b804b..47dcd5581 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ plugins { id("kotlinx.team.infra") version "0.4.0-dev-81" kotlin("multiplatform") apply false id("org.jetbrains.kotlinx.kover") version "0.8.0-Beta2" + id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.16.3" } infra { @@ -57,3 +58,10 @@ dependencies { kover(project(":kotlinx-datetime")) kover(project(":kotlinx-datetime-serialization")) } + +apiValidation { + @OptIn(kotlinx.validation.ExperimentalBCVApi::class) + klib { + enabled = true + } +} diff --git a/core/api/kotlinx-datetime.api b/core/api/kotlinx-datetime.api new file mode 100644 index 000000000..da9f03164 --- /dev/null +++ b/core/api/kotlinx-datetime.api @@ -0,0 +1,932 @@ +public abstract interface class kotlinx/datetime/Clock { + public static final field Companion Lkotlinx/datetime/Clock$Companion; + public abstract fun now ()Lkotlinx/datetime/Instant; +} + +public final class kotlinx/datetime/Clock$Companion { +} + +public final class kotlinx/datetime/Clock$System : kotlinx/datetime/Clock { + public static final field INSTANCE Lkotlinx/datetime/Clock$System; + public fun now ()Lkotlinx/datetime/Instant; +} + +public final class kotlinx/datetime/ClockKt { + public static final fun asClock (Lkotlin/time/TimeSource;Lkotlinx/time/Instant;)Lkotlinx/time/Clock; + public static final fun asTimeSource (Lkotlinx/datetime/Clock;)Lkotlin/time/TimeSource$WithComparableMarks; + public static final fun asTimeSource (Lkotlinx/time/Clock;)Lkotlin/time/TimeSource$WithComparableMarks; + public static final fun todayAt (Lkotlinx/datetime/Clock;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDate; + public static final fun todayAt (Lkotlinx/time/Clock;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDate; + public static final fun todayIn (Lkotlinx/datetime/Clock;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDate; + public static final fun todayIn (Lkotlinx/time/Clock;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDate; +} + +public final class kotlinx/datetime/ConvertersKt { + public static final fun toJavaInstant (Lkotlinx/datetime/Instant;)Ljava/time/Instant; + public static final fun toJavaLocalDate (Lkotlinx/datetime/LocalDate;)Ljava/time/LocalDate; + public static final fun toJavaLocalDateTime (Lkotlinx/datetime/LocalDateTime;)Ljava/time/LocalDateTime; + public static final fun toJavaLocalTime (Lkotlinx/datetime/LocalTime;)Ljava/time/LocalTime; + public static final fun toJavaPeriod (Lkotlinx/datetime/DatePeriod;)Ljava/time/Period; + public static final fun toJavaZoneId (Lkotlinx/datetime/TimeZone;)Ljava/time/ZoneId; + public static final fun toJavaZoneOffset (Lkotlinx/datetime/FixedOffsetTimeZone;)Ljava/time/ZoneOffset; + public static final fun toJavaZoneOffset (Lkotlinx/datetime/UtcOffset;)Ljava/time/ZoneOffset; + public static final fun toKotlinDatePeriod (Ljava/time/Period;)Lkotlinx/datetime/DatePeriod; + public static final fun toKotlinFixedOffsetTimeZone (Ljava/time/ZoneOffset;)Lkotlinx/datetime/FixedOffsetTimeZone; + public static final fun toKotlinInstant (Ljava/time/Instant;)Lkotlinx/datetime/Instant; + public static final fun toKotlinLocalDate (Ljava/time/LocalDate;)Lkotlinx/datetime/LocalDate; + public static final fun toKotlinLocalDateTime (Ljava/time/LocalDateTime;)Lkotlinx/datetime/LocalDateTime; + public static final fun toKotlinLocalTime (Ljava/time/LocalTime;)Lkotlinx/datetime/LocalTime; + public static final fun toKotlinTimeZone (Ljava/time/ZoneId;)Lkotlinx/datetime/TimeZone; + public static final fun toKotlinUtcOffset (Ljava/time/ZoneOffset;)Lkotlinx/datetime/UtcOffset; + public static final fun toKotlinZoneOffset (Ljava/time/ZoneOffset;)Lkotlinx/datetime/FixedOffsetTimeZone; +} + +public final class kotlinx/datetime/DatePeriod : kotlinx/datetime/DateTimePeriod { + public static final field Companion Lkotlinx/datetime/DatePeriod$Companion; + public fun (III)V + public synthetic fun (IIIILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun getDays ()I + public fun getHours ()I + public fun getMinutes ()I + public fun getNanoseconds ()I + public fun getSeconds ()I +} + +public final class kotlinx/datetime/DatePeriod$Companion { + public final fun parse (Ljava/lang/String;)Lkotlinx/datetime/DatePeriod; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DateTimeArithmeticException : java/lang/RuntimeException { + public fun ()V + public fun (Ljava/lang/String;)V + public fun (Ljava/lang/String;Ljava/lang/Throwable;)V + public fun (Ljava/lang/Throwable;)V +} + +public abstract class kotlinx/datetime/DateTimePeriod { + public static final field Companion Lkotlinx/datetime/DateTimePeriod$Companion; + public fun equals (Ljava/lang/Object;)Z + public abstract fun getDays ()I + public fun getHours ()I + public fun getMinutes ()I + public final fun getMonths ()I + public fun getNanoseconds ()I + public fun getSeconds ()I + public final fun getYears ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/DateTimePeriod$Companion { + public final fun parse (Ljava/lang/String;)Lkotlinx/datetime/DateTimePeriod; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DateTimePeriodKt { + public static final fun DateTimePeriod (IIIIIIJ)Lkotlinx/datetime/DateTimePeriod; + public static synthetic fun DateTimePeriod$default (IIIIIIJILjava/lang/Object;)Lkotlinx/datetime/DateTimePeriod; + public static final fun plus (Lkotlinx/datetime/DatePeriod;Lkotlinx/datetime/DatePeriod;)Lkotlinx/datetime/DatePeriod; + public static final fun plus (Lkotlinx/datetime/DateTimePeriod;Lkotlinx/datetime/DateTimePeriod;)Lkotlinx/datetime/DateTimePeriod; + public static final fun toDatePeriod (Ljava/lang/String;)Lkotlinx/datetime/DatePeriod; + public static final fun toDateTimePeriod (Ljava/lang/String;)Lkotlinx/datetime/DateTimePeriod; + public static final fun toDateTimePeriod-LRDsOJo (J)Lkotlinx/datetime/DateTimePeriod; +} + +public abstract class kotlinx/datetime/DateTimeUnit { + public static final field Companion Lkotlinx/datetime/DateTimeUnit$Companion; + protected final fun formatToString (ILjava/lang/String;)Ljava/lang/String; + protected final fun formatToString (JLjava/lang/String;)Ljava/lang/String; + public abstract fun times (I)Lkotlinx/datetime/DateTimeUnit; +} + +public final class kotlinx/datetime/DateTimeUnit$Companion { + public final fun getCENTURY ()Lkotlinx/datetime/DateTimeUnit$MonthBased; + public final fun getDAY ()Lkotlinx/datetime/DateTimeUnit$DayBased; + public final fun getHOUR ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getMICROSECOND ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getMILLISECOND ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getMINUTE ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getMONTH ()Lkotlinx/datetime/DateTimeUnit$MonthBased; + public final fun getNANOSECOND ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getQUARTER ()Lkotlinx/datetime/DateTimeUnit$MonthBased; + public final fun getSECOND ()Lkotlinx/datetime/DateTimeUnit$TimeBased; + public final fun getWEEK ()Lkotlinx/datetime/DateTimeUnit$DayBased; + public final fun getYEAR ()Lkotlinx/datetime/DateTimeUnit$MonthBased; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public abstract class kotlinx/datetime/DateTimeUnit$DateBased : kotlinx/datetime/DateTimeUnit { + public static final field Companion Lkotlinx/datetime/DateTimeUnit$DateBased$Companion; +} + +public final class kotlinx/datetime/DateTimeUnit$DateBased$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DateTimeUnit$DayBased : kotlinx/datetime/DateTimeUnit$DateBased { + public static final field Companion Lkotlinx/datetime/DateTimeUnit$DayBased$Companion; + public fun (I)V + public fun equals (Ljava/lang/Object;)Z + public final fun getDays ()I + public fun hashCode ()I + public fun times (I)Lkotlinx/datetime/DateTimeUnit$DayBased; + public synthetic fun times (I)Lkotlinx/datetime/DateTimeUnit; + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/DateTimeUnit$DayBased$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DateTimeUnit$MonthBased : kotlinx/datetime/DateTimeUnit$DateBased { + public static final field Companion Lkotlinx/datetime/DateTimeUnit$MonthBased$Companion; + public fun (I)V + public fun equals (Ljava/lang/Object;)Z + public final fun getMonths ()I + public fun hashCode ()I + public fun times (I)Lkotlinx/datetime/DateTimeUnit$MonthBased; + public synthetic fun times (I)Lkotlinx/datetime/DateTimeUnit; + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/DateTimeUnit$MonthBased$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DateTimeUnit$TimeBased : kotlinx/datetime/DateTimeUnit { + public static final field Companion Lkotlinx/datetime/DateTimeUnit$TimeBased$Companion; + public fun (J)V + public fun equals (Ljava/lang/Object;)Z + public final fun getDuration-UwyO8pc ()J + public final fun getNanoseconds ()J + public fun hashCode ()I + public fun times (I)Lkotlinx/datetime/DateTimeUnit$TimeBased; + public synthetic fun times (I)Lkotlinx/datetime/DateTimeUnit; + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/DateTimeUnit$TimeBased$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/DayOfWeekKt { + public static final fun DayOfWeek (I)Ljava/time/DayOfWeek; + public static final fun getIsoDayNumber (Ljava/time/DayOfWeek;)I +} + +public final class kotlinx/datetime/DeprecationMarker { +} + +public final class kotlinx/datetime/FixedOffsetTimeZone : kotlinx/datetime/TimeZone { + public static final field Companion Lkotlinx/datetime/FixedOffsetTimeZone$Companion; + public fun (Lkotlinx/datetime/UtcOffset;)V + public final fun getOffset ()Lkotlinx/datetime/UtcOffset; + public final fun getTotalSeconds ()I +} + +public final class kotlinx/datetime/FixedOffsetTimeZone$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/IllegalTimeZoneException : java/lang/IllegalArgumentException { + public fun ()V + public fun (Ljava/lang/String;)V + public fun (Ljava/lang/String;Ljava/lang/Throwable;)V + public fun (Ljava/lang/Throwable;)V +} + +public final class kotlinx/datetime/Instant : java/lang/Comparable { + public static final field Companion Lkotlinx/datetime/Instant$Companion; + public synthetic fun compareTo (Ljava/lang/Object;)I + public fun compareTo (Lkotlinx/datetime/Instant;)I + public fun equals (Ljava/lang/Object;)Z + public final fun getEpochSeconds ()J + public final fun getNanosecondsOfSecond ()I + public fun hashCode ()I + public final fun minus-5sfh64U (Lkotlinx/datetime/Instant;)J + public final fun minus-LRDsOJo (J)Lkotlinx/datetime/Instant; + public final fun plus-LRDsOJo (J)Lkotlinx/datetime/Instant; + public final fun toEpochMilliseconds ()J + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/Instant$Companion { + public final fun fromEpochMilliseconds (J)Lkotlinx/datetime/Instant; + public final fun fromEpochSeconds (JI)Lkotlinx/datetime/Instant; + public final fun fromEpochSeconds (JJ)Lkotlinx/datetime/Instant; + public static synthetic fun fromEpochSeconds$default (Lkotlinx/datetime/Instant$Companion;JJILjava/lang/Object;)Lkotlinx/datetime/Instant; + public final fun getDISTANT_FUTURE ()Lkotlinx/datetime/Instant; + public final fun getDISTANT_PAST ()Lkotlinx/datetime/Instant; + public final fun now ()Lkotlinx/datetime/Instant; + public final fun parse (Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/Instant; + public final synthetic fun parse (Ljava/lang/String;)Lkotlinx/datetime/Instant; + public static synthetic fun parse$default (Lkotlinx/datetime/Instant$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;ILjava/lang/Object;)Lkotlinx/datetime/Instant; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/InstantJvmKt { + public static final fun minus (Lkotlinx/datetime/Instant;ILkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/time/Instant;ILkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun periodUntil (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/DateTimePeriod; + public static final fun periodUntil (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/DateTimePeriod; + public static final fun plus (Lkotlinx/datetime/Instant;ILkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;JLkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;JLkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimePeriod;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/time/Instant;ILkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/time/Instant;JLkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/time/Instant;JLkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimePeriod;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun until (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)J + public static final fun until (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)J +} + +public final class kotlinx/datetime/InstantKt { + public static final fun daysUntil (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)I + public static final fun daysUntil (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)I + public static final fun format (Lkotlinx/datetime/Instant;Lkotlinx/datetime/format/DateTimeFormat;Lkotlinx/datetime/UtcOffset;)Ljava/lang/String; + public static final fun format (Lkotlinx/time/Instant;Lkotlinx/datetime/format/DateTimeFormat;Lkotlinx/datetime/UtcOffset;)Ljava/lang/String; + public static synthetic fun format$default (Lkotlinx/datetime/Instant;Lkotlinx/datetime/format/DateTimeFormat;Lkotlinx/datetime/UtcOffset;ILjava/lang/Object;)Ljava/lang/String; + public static synthetic fun format$default (Lkotlinx/time/Instant;Lkotlinx/datetime/format/DateTimeFormat;Lkotlinx/datetime/UtcOffset;ILjava/lang/Object;)Ljava/lang/String; + public static final fun isDistantFuture (Lkotlinx/datetime/Instant;)Z + public static final fun isDistantPast (Lkotlinx/datetime/Instant;)Z + public static final fun minus (Lkotlinx/datetime/Instant;ILkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;JLkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;JLkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimePeriod;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)J + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)J + public static final fun minus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/DateTimePeriod; + public static final fun minus (Lkotlinx/time/Instant;ILkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;JLkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;JLkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimePeriod;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)Lkotlinx/time/Instant; + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)J + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit;Lkotlinx/datetime/TimeZone;)J + public static final fun minus (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/DateTimePeriod; + public static final fun monthsUntil (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)I + public static final fun monthsUntil (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)I + public static final fun parse (Lkotlinx/time/Instant$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;ILkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/datetime/Instant; + public static final fun plus (Lkotlinx/time/Instant;ILkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun plus (Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)Lkotlinx/time/Instant; + public static final fun toDeprecatedInstant (Lkotlinx/time/Instant;)Lkotlinx/datetime/Instant; + public static final fun toInstant (Ljava/lang/String;)Lkotlinx/datetime/Instant; + public static final fun toNewInstant (Lkotlinx/datetime/Instant;)Lkotlinx/time/Instant; + public static final fun until (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)J + public static final fun until (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/DateTimeUnit$TimeBased;)J + public static final fun yearsUntil (Lkotlinx/datetime/Instant;Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)I + public static final fun yearsUntil (Lkotlinx/time/Instant;Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)I +} + +public final class kotlinx/datetime/LocalDate : java/lang/Comparable { + public static final field Companion Lkotlinx/datetime/LocalDate$Companion; + public fun (III)V + public fun (ILjava/time/Month;I)V + public synthetic fun compareTo (Ljava/lang/Object;)I + public fun compareTo (Lkotlinx/datetime/LocalDate;)I + public fun equals (Ljava/lang/Object;)Z + public final fun getDayOfMonth ()I + public final fun getDayOfWeek ()Ljava/time/DayOfWeek; + public final fun getDayOfYear ()I + public final fun getMonth ()Ljava/time/Month; + public final fun getMonthNumber ()I + public final fun getYear ()I + public fun hashCode ()I + public final fun toEpochDays ()I + public final fun toEpochDays ()J + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/LocalDate$Companion { + public final fun Format (Lkotlin/jvm/functions/Function1;)Lkotlinx/datetime/format/DateTimeFormat; + public final fun fromEpochDays (I)Lkotlinx/datetime/LocalDate; + public final fun fromEpochDays (J)Lkotlinx/datetime/LocalDate; + public final fun parse (Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/LocalDate; + public final synthetic fun parse (Ljava/lang/String;)Lkotlinx/datetime/LocalDate; + public static synthetic fun parse$default (Lkotlinx/datetime/LocalDate$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;ILjava/lang/Object;)Lkotlinx/datetime/LocalDate; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/LocalDate$Formats { + public static final field INSTANCE Lkotlinx/datetime/LocalDate$Formats; + public final fun getISO ()Lkotlinx/datetime/format/DateTimeFormat; + public final fun getISO_BASIC ()Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/LocalDateJvmKt { + public static final fun daysUntil (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;)I + public static final fun minus (Lkotlinx/datetime/LocalDate;ILkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun monthsUntil (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;)I + public static final fun periodUntil (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;)Lkotlinx/datetime/DatePeriod; + public static final fun plus (Lkotlinx/datetime/LocalDate;ILkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun plus (Lkotlinx/datetime/LocalDate;JLkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun plus (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DatePeriod;)Lkotlinx/datetime/LocalDate; + public static final fun plus (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun until (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DateTimeUnit$DateBased;)I + public static final fun until (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DateTimeUnit$DateBased;)J + public static final fun yearsUntil (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;)I +} + +public final class kotlinx/datetime/LocalDateKt { + public static final fun atTime (Lkotlinx/datetime/LocalDate;IIII)Lkotlinx/datetime/LocalDateTime; + public static final fun atTime (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalTime;)Lkotlinx/datetime/LocalDateTime; + public static synthetic fun atTime$default (Lkotlinx/datetime/LocalDate;IIIIILjava/lang/Object;)Lkotlinx/datetime/LocalDateTime; + public static final fun format (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/format/DateTimeFormat;)Ljava/lang/String; + public static final fun minus (Lkotlinx/datetime/LocalDate;ILkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun minus (Lkotlinx/datetime/LocalDate;JLkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun minus (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DatePeriod;)Lkotlinx/datetime/LocalDate; + public static final fun minus (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun minus (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalDate;)Lkotlinx/datetime/DatePeriod; + public static final fun plus (Lkotlinx/datetime/LocalDate;ILkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/datetime/LocalDate; + public static final fun toLocalDate (Ljava/lang/String;)Lkotlinx/datetime/LocalDate; +} + +public final class kotlinx/datetime/LocalDateTime : java/lang/Comparable { + public static final field Companion Lkotlinx/datetime/LocalDateTime$Companion; + public fun (IIIIIII)V + public synthetic fun (IIIIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (ILjava/time/Month;IIIII)V + public synthetic fun (ILjava/time/Month;IIIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/LocalTime;)V + public synthetic fun compareTo (Ljava/lang/Object;)I + public fun compareTo (Lkotlinx/datetime/LocalDateTime;)I + public fun equals (Ljava/lang/Object;)Z + public final fun getDate ()Lkotlinx/datetime/LocalDate; + public final fun getDayOfMonth ()I + public final fun getDayOfWeek ()Ljava/time/DayOfWeek; + public final fun getDayOfYear ()I + public final fun getHour ()I + public final fun getMinute ()I + public final fun getMonth ()Ljava/time/Month; + public final fun getMonthNumber ()I + public final fun getNanosecond ()I + public final fun getSecond ()I + public final fun getTime ()Lkotlinx/datetime/LocalTime; + public final fun getYear ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/LocalDateTime$Companion { + public final fun Format (Lkotlin/jvm/functions/Function1;)Lkotlinx/datetime/format/DateTimeFormat; + public final fun parse (Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/LocalDateTime; + public final synthetic fun parse (Ljava/lang/String;)Lkotlinx/datetime/LocalDateTime; + public static synthetic fun parse$default (Lkotlinx/datetime/LocalDateTime$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;ILjava/lang/Object;)Lkotlinx/datetime/LocalDateTime; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/LocalDateTime$Formats { + public static final field INSTANCE Lkotlinx/datetime/LocalDateTime$Formats; + public final fun getISO ()Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/LocalDateTimeKt { + public static final fun format (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/format/DateTimeFormat;)Ljava/lang/String; + public static final fun toLocalDateTime (Ljava/lang/String;)Lkotlinx/datetime/LocalDateTime; +} + +public final class kotlinx/datetime/LocalTime : java/lang/Comparable { + public static final field Companion Lkotlinx/datetime/LocalTime$Companion; + public fun (IIII)V + public synthetic fun (IIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun compareTo (Ljava/lang/Object;)I + public fun compareTo (Lkotlinx/datetime/LocalTime;)I + public fun equals (Ljava/lang/Object;)Z + public final fun getHour ()I + public final fun getMinute ()I + public final fun getNanosecond ()I + public final fun getSecond ()I + public fun hashCode ()I + public final fun toMillisecondOfDay ()I + public final fun toNanosecondOfDay ()J + public final fun toSecondOfDay ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/LocalTime$Companion { + public final fun Format (Lkotlin/jvm/functions/Function1;)Lkotlinx/datetime/format/DateTimeFormat; + public final fun fromMillisecondOfDay (I)Lkotlinx/datetime/LocalTime; + public final fun fromNanosecondOfDay (J)Lkotlinx/datetime/LocalTime; + public final fun fromSecondOfDay (I)Lkotlinx/datetime/LocalTime; + public final fun parse (Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/LocalTime; + public final synthetic fun parse (Ljava/lang/String;)Lkotlinx/datetime/LocalTime; + public static synthetic fun parse$default (Lkotlinx/datetime/LocalTime$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;ILjava/lang/Object;)Lkotlinx/datetime/LocalTime; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/LocalTime$Formats { + public static final field INSTANCE Lkotlinx/datetime/LocalTime$Formats; + public final fun getISO ()Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/LocalTimeKt { + public static final fun atDate (Lkotlinx/datetime/LocalTime;III)Lkotlinx/datetime/LocalDateTime; + public static final fun atDate (Lkotlinx/datetime/LocalTime;ILjava/time/Month;I)Lkotlinx/datetime/LocalDateTime; + public static final fun atDate (Lkotlinx/datetime/LocalTime;Lkotlinx/datetime/LocalDate;)Lkotlinx/datetime/LocalDateTime; + public static synthetic fun atDate$default (Lkotlinx/datetime/LocalTime;IIIILjava/lang/Object;)Lkotlinx/datetime/LocalDateTime; + public static synthetic fun atDate$default (Lkotlinx/datetime/LocalTime;ILjava/time/Month;IILjava/lang/Object;)Lkotlinx/datetime/LocalDateTime; + public static final fun format (Lkotlinx/datetime/LocalTime;Lkotlinx/datetime/format/DateTimeFormat;)Ljava/lang/String; + public static final fun toLocalTime (Ljava/lang/String;)Lkotlinx/datetime/LocalTime; +} + +public final class kotlinx/datetime/MonthKt { + public static final fun Month (I)Ljava/time/Month; + public static final fun getNumber (Ljava/time/Month;)I +} + +public class kotlinx/datetime/TimeZone { + public static final field Companion Lkotlinx/datetime/TimeZone$Companion; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toInstant (Lkotlinx/datetime/LocalDateTime;)Lkotlinx/datetime/Instant; + public final fun toInstant (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/DeprecationMarker;)Lkotlinx/time/Instant; + public static synthetic fun toInstant$default (Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/DeprecationMarker;ILjava/lang/Object;)Lkotlinx/time/Instant; + public final fun toLocalDateTime (Lkotlinx/datetime/Instant;)Lkotlinx/datetime/LocalDateTime; + public final fun toLocalDateTime (Lkotlinx/time/Instant;)Lkotlinx/datetime/LocalDateTime; + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/TimeZone$Companion { + public final fun currentSystemDefault ()Lkotlinx/datetime/TimeZone; + public final fun getAvailableZoneIds ()Ljava/util/Set; + public final fun getUTC ()Lkotlinx/datetime/FixedOffsetTimeZone; + public final fun of (Ljava/lang/String;)Lkotlinx/datetime/TimeZone; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/TimeZoneKt { + public static final fun atStartOfDayIn (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun atStartOfDayIn (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/DeprecationMarker;)Lkotlinx/time/Instant; + public static synthetic fun atStartOfDayIn$default (Lkotlinx/datetime/LocalDate;Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/DeprecationMarker;ILjava/lang/Object;)Lkotlinx/time/Instant; + public static final fun offsetAt (Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/Instant;)Lkotlinx/datetime/UtcOffset; + public static final fun offsetAt (Lkotlinx/datetime/TimeZone;Lkotlinx/time/Instant;)Lkotlinx/datetime/UtcOffset; + public static final fun offsetIn (Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/UtcOffset; + public static final fun offsetIn (Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/UtcOffset; + public static final fun toInstant (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/Instant; + public static final fun toInstant (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/DeprecationMarker;)Lkotlinx/time/Instant; + public static final fun toInstant (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/UtcOffset;)Lkotlinx/datetime/Instant; + public static final fun toInstant (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/UtcOffset;Lkotlinx/datetime/DeprecationMarker;)Lkotlinx/time/Instant; + public static synthetic fun toInstant$default (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/TimeZone;Lkotlinx/datetime/DeprecationMarker;ILjava/lang/Object;)Lkotlinx/time/Instant; + public static synthetic fun toInstant$default (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/UtcOffset;Lkotlinx/datetime/DeprecationMarker;ILjava/lang/Object;)Lkotlinx/time/Instant; + public static final fun toLocalDateTime (Lkotlinx/datetime/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDateTime; + public static final fun toLocalDateTime (Lkotlinx/datetime/Instant;Lkotlinx/datetime/UtcOffset;)Lkotlinx/datetime/LocalDateTime; + public static final fun toLocalDateTime (Lkotlinx/time/Instant;Lkotlinx/datetime/TimeZone;)Lkotlinx/datetime/LocalDateTime; +} + +public final class kotlinx/datetime/UtcOffset { + public static final field Companion Lkotlinx/datetime/UtcOffset$Companion; + public fun (Ljava/time/ZoneOffset;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getTotalSeconds ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/UtcOffset$Companion { + public final fun Format (Lkotlin/jvm/functions/Function1;)Lkotlinx/datetime/format/DateTimeFormat; + public final fun getZERO ()Lkotlinx/datetime/UtcOffset; + public final fun parse (Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/UtcOffset; + public final synthetic fun parse (Ljava/lang/String;)Lkotlinx/datetime/UtcOffset; + public static synthetic fun parse$default (Lkotlinx/datetime/UtcOffset$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;ILjava/lang/Object;)Lkotlinx/datetime/UtcOffset; + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class kotlinx/datetime/UtcOffset$Formats { + public static final field INSTANCE Lkotlinx/datetime/UtcOffset$Formats; + public final fun getFOUR_DIGITS ()Lkotlinx/datetime/format/DateTimeFormat; + public final fun getISO ()Lkotlinx/datetime/format/DateTimeFormat; + public final fun getISO_BASIC ()Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/UtcOffsetJvmKt { + public static final fun UtcOffset (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Lkotlinx/datetime/UtcOffset; + public static synthetic fun UtcOffset$default (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;ILjava/lang/Object;)Lkotlinx/datetime/UtcOffset; +} + +public final class kotlinx/datetime/UtcOffsetKt { + public static final fun UtcOffset ()Lkotlinx/datetime/UtcOffset; + public static final fun asTimeZone (Lkotlinx/datetime/UtcOffset;)Lkotlinx/datetime/FixedOffsetTimeZone; + public static final fun format (Lkotlinx/datetime/UtcOffset;Lkotlinx/datetime/format/DateTimeFormat;)Ljava/lang/String; +} + +public final class kotlinx/datetime/format/AmPmMarker : java/lang/Enum { + public static final field AM Lkotlinx/datetime/format/AmPmMarker; + public static final field PM Lkotlinx/datetime/format/AmPmMarker; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Lkotlinx/datetime/format/AmPmMarker; + public static fun values ()[Lkotlinx/datetime/format/AmPmMarker; +} + +public final class kotlinx/datetime/format/DateTimeComponents { + public static final field Companion Lkotlinx/datetime/format/DateTimeComponents$Companion; + public fun ()V + public final fun getAmPm ()Lkotlinx/datetime/format/AmPmMarker; + public final fun getDayOfMonth ()Ljava/lang/Integer; + public final fun getDayOfWeek ()Ljava/time/DayOfWeek; + public final fun getDayOfYear ()Ljava/lang/Integer; + public final fun getHour ()Ljava/lang/Integer; + public final fun getHourOfAmPm ()Ljava/lang/Integer; + public final fun getMinute ()Ljava/lang/Integer; + public final fun getMonth ()Ljava/time/Month; + public final fun getMonthNumber ()Ljava/lang/Integer; + public final fun getNanosecond ()Ljava/lang/Integer; + public final fun getOffsetHours ()Ljava/lang/Integer; + public final fun getOffsetIsNegative ()Ljava/lang/Boolean; + public final fun getOffsetMinutesOfHour ()Ljava/lang/Integer; + public final fun getOffsetSecondsOfMinute ()Ljava/lang/Integer; + public final fun getSecond ()Ljava/lang/Integer; + public final fun getTimeZoneId ()Ljava/lang/String; + public final fun getYear ()Ljava/lang/Integer; + public final fun setAmPm (Lkotlinx/datetime/format/AmPmMarker;)V + public final fun setDate (Lkotlinx/datetime/LocalDate;)V + public final fun setDateTime (Lkotlinx/datetime/LocalDateTime;)V + public final fun setDateTimeOffset (Lkotlinx/datetime/Instant;Lkotlinx/datetime/UtcOffset;)V + public final fun setDateTimeOffset (Lkotlinx/datetime/LocalDateTime;Lkotlinx/datetime/UtcOffset;)V + public final fun setDateTimeOffset (Lkotlinx/time/Instant;Lkotlinx/datetime/UtcOffset;)V + public final fun setDayOfMonth (Ljava/lang/Integer;)V + public final fun setDayOfWeek (Ljava/time/DayOfWeek;)V + public final fun setDayOfYear (Ljava/lang/Integer;)V + public final fun setHour (Ljava/lang/Integer;)V + public final fun setHourOfAmPm (Ljava/lang/Integer;)V + public final fun setMinute (Ljava/lang/Integer;)V + public final fun setMonth (Ljava/time/Month;)V + public final fun setMonthNumber (Ljava/lang/Integer;)V + public final fun setNanosecond (Ljava/lang/Integer;)V + public final fun setOffset (Lkotlinx/datetime/UtcOffset;)V + public final fun setOffsetHours (Ljava/lang/Integer;)V + public final fun setOffsetIsNegative (Ljava/lang/Boolean;)V + public final fun setOffsetMinutesOfHour (Ljava/lang/Integer;)V + public final fun setOffsetSecondsOfMinute (Ljava/lang/Integer;)V + public final fun setSecond (Ljava/lang/Integer;)V + public final fun setTime (Lkotlinx/datetime/LocalTime;)V + public final fun setTimeZoneId (Ljava/lang/String;)V + public final fun setYear (Ljava/lang/Integer;)V + public final fun toInstantUsingOffset ()Lkotlinx/datetime/Instant; + public final fun toInstantUsingOffset (Lkotlinx/datetime/DeprecationMarker;)Lkotlinx/time/Instant; + public static synthetic fun toInstantUsingOffset$default (Lkotlinx/datetime/format/DateTimeComponents;Lkotlinx/datetime/DeprecationMarker;ILjava/lang/Object;)Lkotlinx/time/Instant; + public final fun toLocalDate ()Lkotlinx/datetime/LocalDate; + public final fun toLocalDateTime ()Lkotlinx/datetime/LocalDateTime; + public final fun toLocalTime ()Lkotlinx/datetime/LocalTime; + public final fun toUtcOffset ()Lkotlinx/datetime/UtcOffset; +} + +public final class kotlinx/datetime/format/DateTimeComponents$Companion { + public final fun Format (Lkotlin/jvm/functions/Function1;)Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/format/DateTimeComponents$Formats { + public static final field INSTANCE Lkotlinx/datetime/format/DateTimeComponents$Formats; + public final fun getISO_DATE_TIME_OFFSET ()Lkotlinx/datetime/format/DateTimeFormat; + public final fun getRFC_1123 ()Lkotlinx/datetime/format/DateTimeFormat; +} + +public final class kotlinx/datetime/format/DateTimeComponentsKt { + public static final fun format (Lkotlinx/datetime/format/DateTimeFormat;Lkotlin/jvm/functions/Function1;)Ljava/lang/String; + public static final fun parse (Lkotlinx/datetime/format/DateTimeComponents$Companion;Ljava/lang/CharSequence;Lkotlinx/datetime/format/DateTimeFormat;)Lkotlinx/datetime/format/DateTimeComponents; +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormat { + public static final field Companion Lkotlinx/datetime/format/DateTimeFormat$Companion; + public abstract fun format (Ljava/lang/Object;)Ljava/lang/String; + public abstract fun formatTo (Ljava/lang/Appendable;Ljava/lang/Object;)Ljava/lang/Appendable; + public abstract fun parse (Ljava/lang/CharSequence;)Ljava/lang/Object; + public abstract fun parseOrNull (Ljava/lang/CharSequence;)Ljava/lang/Object; +} + +public final class kotlinx/datetime/format/DateTimeFormat$Companion { + public final fun formatAsKotlinBuilderDsl (Lkotlinx/datetime/format/DateTimeFormat;)Ljava/lang/String; +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder { + public abstract fun chars (Ljava/lang/String;)V +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder$WithDate : kotlinx/datetime/format/DateTimeFormatBuilder { + public abstract fun date (Lkotlinx/datetime/format/DateTimeFormat;)V + public abstract fun dayOfMonth (Lkotlinx/datetime/format/Padding;)V + public abstract fun dayOfWeek (Lkotlinx/datetime/format/DayOfWeekNames;)V + public abstract fun dayOfYear (Lkotlinx/datetime/format/Padding;)V + public abstract fun monthName (Lkotlinx/datetime/format/MonthNames;)V + public abstract fun monthNumber (Lkotlinx/datetime/format/Padding;)V + public abstract fun year (Lkotlinx/datetime/format/Padding;)V + public abstract fun yearTwoDigits (I)V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilder$WithDate$DefaultImpls { + public static synthetic fun dayOfMonth$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDate;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun dayOfYear$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDate;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun monthNumber$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDate;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun year$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDate;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder$WithDateTime : kotlinx/datetime/format/DateTimeFormatBuilder$WithDate, kotlinx/datetime/format/DateTimeFormatBuilder$WithTime { + public abstract fun dateTime (Lkotlinx/datetime/format/DateTimeFormat;)V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilder$WithDateTime$DefaultImpls { + public static fun secondFraction (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDateTime;I)V +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder$WithDateTimeComponents : kotlinx/datetime/format/DateTimeFormatBuilder$WithDateTime, kotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset { + public abstract fun dateTimeComponents (Lkotlinx/datetime/format/DateTimeFormat;)V + public abstract fun timeZoneId ()V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilder$WithDateTimeComponents$DefaultImpls { + public static fun secondFraction (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithDateTimeComponents;I)V +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder$WithTime : kotlinx/datetime/format/DateTimeFormatBuilder { + public abstract fun amPmHour (Lkotlinx/datetime/format/Padding;)V + public abstract fun amPmMarker (Ljava/lang/String;Ljava/lang/String;)V + public abstract fun hour (Lkotlinx/datetime/format/Padding;)V + public abstract fun minute (Lkotlinx/datetime/format/Padding;)V + public abstract fun second (Lkotlinx/datetime/format/Padding;)V + public abstract fun secondFraction (I)V + public abstract fun secondFraction (II)V + public abstract fun time (Lkotlinx/datetime/format/DateTimeFormat;)V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilder$WithTime$DefaultImpls { + public static synthetic fun amPmHour$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun hour$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun minute$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun second$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static fun secondFraction (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;I)V + public static synthetic fun secondFraction$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithTime;IIILjava/lang/Object;)V +} + +public abstract interface class kotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset : kotlinx/datetime/format/DateTimeFormatBuilder { + public abstract fun offset (Lkotlinx/datetime/format/DateTimeFormat;)V + public abstract fun offsetHours (Lkotlinx/datetime/format/Padding;)V + public abstract fun offsetMinutesOfHour (Lkotlinx/datetime/format/Padding;)V + public abstract fun offsetSecondsOfMinute (Lkotlinx/datetime/format/Padding;)V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset$DefaultImpls { + public static synthetic fun offsetHours$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun offsetMinutesOfHour$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V + public static synthetic fun offsetSecondsOfMinute$default (Lkotlinx/datetime/format/DateTimeFormatBuilder$WithUtcOffset;Lkotlinx/datetime/format/Padding;ILjava/lang/Object;)V +} + +public final class kotlinx/datetime/format/DateTimeFormatBuilderKt { + public static final fun alternativeParsing (Lkotlinx/datetime/format/DateTimeFormatBuilder;[Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V + public static final fun char (Lkotlinx/datetime/format/DateTimeFormatBuilder;C)V + public static final fun optional (Lkotlinx/datetime/format/DateTimeFormatBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun optional$default (Lkotlinx/datetime/format/DateTimeFormatBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V +} + +public final class kotlinx/datetime/format/DayOfWeekNames { + public static final field Companion Lkotlinx/datetime/format/DayOfWeekNames$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public fun (Ljava/util/List;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getNames ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/format/DayOfWeekNames$Companion { + public final fun getENGLISH_ABBREVIATED ()Lkotlinx/datetime/format/DayOfWeekNames; + public final fun getENGLISH_FULL ()Lkotlinx/datetime/format/DayOfWeekNames; +} + +public abstract interface annotation class kotlinx/datetime/format/FormatStringsInDatetimeFormats : java/lang/annotation/Annotation { +} + +public final class kotlinx/datetime/format/MonthNames { + public static final field Companion Lkotlinx/datetime/format/MonthNames$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public fun (Ljava/util/List;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getNames ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/datetime/format/MonthNames$Companion { + public final fun getENGLISH_ABBREVIATED ()Lkotlinx/datetime/format/MonthNames; + public final fun getENGLISH_FULL ()Lkotlinx/datetime/format/MonthNames; +} + +public final class kotlinx/datetime/format/Padding : java/lang/Enum { + public static final field NONE Lkotlinx/datetime/format/Padding; + public static final field SPACE Lkotlinx/datetime/format/Padding; + public static final field ZERO Lkotlinx/datetime/format/Padding; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Lkotlinx/datetime/format/Padding; + public static fun values ()[Lkotlinx/datetime/format/Padding; +} + +public final class kotlinx/datetime/format/UnicodeKt { + public static final fun byUnicodePattern (Lkotlinx/datetime/format/DateTimeFormatBuilder;Ljava/lang/String;)V +} + +public final class kotlinx/datetime/serializers/DateBasedDateTimeUnitSerializer : kotlinx/serialization/internal/AbstractPolymorphicSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DateBasedDateTimeUnitSerializer; + public fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/CompositeDecoder;Ljava/lang/String;)Lkotlinx/serialization/DeserializationStrategy; + public synthetic fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)Lkotlinx/serialization/SerializationStrategy; + public fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimeUnit$DateBased;)Lkotlinx/serialization/SerializationStrategy; + public fun getBaseClass ()Lkotlin/reflect/KClass; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; +} + +public final class kotlinx/datetime/serializers/DatePeriodComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DatePeriodComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DatePeriod; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DatePeriod;)V +} + +public final class kotlinx/datetime/serializers/DatePeriodIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DatePeriodIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DatePeriod; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DatePeriod;)V +} + +public final class kotlinx/datetime/serializers/DateTimePeriodComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DateTimePeriodComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DateTimePeriod; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimePeriod;)V +} + +public final class kotlinx/datetime/serializers/DateTimePeriodIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DateTimePeriodIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DateTimePeriod; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimePeriod;)V +} + +public final class kotlinx/datetime/serializers/DateTimeUnitSerializer : kotlinx/serialization/internal/AbstractPolymorphicSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DateTimeUnitSerializer; + public fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/CompositeDecoder;Ljava/lang/String;)Lkotlinx/serialization/DeserializationStrategy; + public synthetic fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)Lkotlinx/serialization/SerializationStrategy; + public fun findPolymorphicSerializerOrNull (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimeUnit;)Lkotlinx/serialization/SerializationStrategy; + public fun getBaseClass ()Lkotlin/reflect/KClass; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; +} + +public final class kotlinx/datetime/serializers/DayBasedDateTimeUnitSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DayBasedDateTimeUnitSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DateTimeUnit$DayBased; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimeUnit$DayBased;)V +} + +public final class kotlinx/datetime/serializers/DayOfWeekSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/DayOfWeekSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/DayOfWeek; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/DayOfWeek;)V +} + +public final class kotlinx/datetime/serializers/FixedOffsetTimeZoneSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/FixedOffsetTimeZoneSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/FixedOffsetTimeZone; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/FixedOffsetTimeZone;)V +} + +public final class kotlinx/datetime/serializers/InstantComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/InstantComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/Instant; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/Instant;)V +} + +public final class kotlinx/datetime/serializers/InstantIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/InstantIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/Instant; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/Instant;)V +} + +public final class kotlinx/datetime/serializers/LocalDateComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalDateComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalDate; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalDate;)V +} + +public final class kotlinx/datetime/serializers/LocalDateIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalDateIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalDate; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalDate;)V +} + +public final class kotlinx/datetime/serializers/LocalDateTimeComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalDateTimeComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalDateTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalDateTime;)V +} + +public final class kotlinx/datetime/serializers/LocalDateTimeIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalDateTimeIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalDateTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalDateTime;)V +} + +public final class kotlinx/datetime/serializers/LocalTimeComponentSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalTimeComponentSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalTime;)V +} + +public final class kotlinx/datetime/serializers/LocalTimeIso8601Serializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/LocalTimeIso8601Serializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/LocalTime; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/LocalTime;)V +} + +public final class kotlinx/datetime/serializers/MonthBasedDateTimeUnitSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/MonthBasedDateTimeUnitSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DateTimeUnit$MonthBased; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimeUnit$MonthBased;)V +} + +public final class kotlinx/datetime/serializers/MonthSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/MonthSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/time/Month; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/time/Month;)V +} + +public final class kotlinx/datetime/serializers/TimeBasedDateTimeUnitSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/TimeBasedDateTimeUnitSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/DateTimeUnit$TimeBased; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/DateTimeUnit$TimeBased;)V +} + +public final class kotlinx/datetime/serializers/TimeZoneSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/TimeZoneSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/TimeZone; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/TimeZone;)V +} + +public final class kotlinx/datetime/serializers/UtcOffsetSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Lkotlinx/datetime/serializers/UtcOffsetSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lkotlinx/datetime/UtcOffset; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlinx/datetime/UtcOffset;)V +} + diff --git a/core/api/kotlinx-datetime.klib.api b/core/api/kotlinx-datetime.klib.api new file mode 100644 index 000000000..678ff9b5f --- /dev/null +++ b/core/api/kotlinx-datetime.klib.api @@ -0,0 +1,985 @@ +// Klib ABI Dump +// Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, js, linuxArm32Hfp, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, wasmWasi, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64] +// Alias: apple => [iosArm64, iosSimulatorArm64, iosX64, macosArm64, macosX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +open annotation class kotlinx.datetime.format/FormatStringsInDatetimeFormats : kotlin/Annotation { // kotlinx.datetime.format/FormatStringsInDatetimeFormats|null[0] + constructor () // kotlinx.datetime.format/FormatStringsInDatetimeFormats.|(){}[0] +} + +final enum class kotlinx.datetime.format/AmPmMarker : kotlin/Enum { // kotlinx.datetime.format/AmPmMarker|null[0] + enum entry AM // kotlinx.datetime.format/AmPmMarker.AM|null[0] + enum entry PM // kotlinx.datetime.format/AmPmMarker.PM|null[0] + + final val entries // kotlinx.datetime.format/AmPmMarker.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // kotlinx.datetime.format/AmPmMarker.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): kotlinx.datetime.format/AmPmMarker // kotlinx.datetime.format/AmPmMarker.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // kotlinx.datetime.format/AmPmMarker.values|values#static(){}[0] +} + +final enum class kotlinx.datetime.format/Padding : kotlin/Enum { // kotlinx.datetime.format/Padding|null[0] + enum entry NONE // kotlinx.datetime.format/Padding.NONE|null[0] + enum entry SPACE // kotlinx.datetime.format/Padding.SPACE|null[0] + enum entry ZERO // kotlinx.datetime.format/Padding.ZERO|null[0] + + final val entries // kotlinx.datetime.format/Padding.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // kotlinx.datetime.format/Padding.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): kotlinx.datetime.format/Padding // kotlinx.datetime.format/Padding.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // kotlinx.datetime.format/Padding.values|values#static(){}[0] +} + +final enum class kotlinx.datetime/DayOfWeek : kotlin/Enum { // kotlinx.datetime/DayOfWeek|null[0] + enum entry FRIDAY // kotlinx.datetime/DayOfWeek.FRIDAY|null[0] + enum entry MONDAY // kotlinx.datetime/DayOfWeek.MONDAY|null[0] + enum entry SATURDAY // kotlinx.datetime/DayOfWeek.SATURDAY|null[0] + enum entry SUNDAY // kotlinx.datetime/DayOfWeek.SUNDAY|null[0] + enum entry THURSDAY // kotlinx.datetime/DayOfWeek.THURSDAY|null[0] + enum entry TUESDAY // kotlinx.datetime/DayOfWeek.TUESDAY|null[0] + enum entry WEDNESDAY // kotlinx.datetime/DayOfWeek.WEDNESDAY|null[0] + + final val entries // kotlinx.datetime/DayOfWeek.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // kotlinx.datetime/DayOfWeek.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): kotlinx.datetime/DayOfWeek // kotlinx.datetime/DayOfWeek.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // kotlinx.datetime/DayOfWeek.values|values#static(){}[0] +} + +final enum class kotlinx.datetime/Month : kotlin/Enum { // kotlinx.datetime/Month|null[0] + enum entry APRIL // kotlinx.datetime/Month.APRIL|null[0] + enum entry AUGUST // kotlinx.datetime/Month.AUGUST|null[0] + enum entry DECEMBER // kotlinx.datetime/Month.DECEMBER|null[0] + enum entry FEBRUARY // kotlinx.datetime/Month.FEBRUARY|null[0] + enum entry JANUARY // kotlinx.datetime/Month.JANUARY|null[0] + enum entry JULY // kotlinx.datetime/Month.JULY|null[0] + enum entry JUNE // kotlinx.datetime/Month.JUNE|null[0] + enum entry MARCH // kotlinx.datetime/Month.MARCH|null[0] + enum entry MAY // kotlinx.datetime/Month.MAY|null[0] + enum entry NOVEMBER // kotlinx.datetime/Month.NOVEMBER|null[0] + enum entry OCTOBER // kotlinx.datetime/Month.OCTOBER|null[0] + enum entry SEPTEMBER // kotlinx.datetime/Month.SEPTEMBER|null[0] + + final val entries // kotlinx.datetime/Month.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // kotlinx.datetime/Month.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): kotlinx.datetime/Month // kotlinx.datetime/Month.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // kotlinx.datetime/Month.values|values#static(){}[0] +} + +abstract interface kotlinx.datetime/Clock { // kotlinx.datetime/Clock|null[0] + abstract fun now(): kotlinx.datetime/Instant // kotlinx.datetime/Clock.now|now(){}[0] + + final object Companion // kotlinx.datetime/Clock.Companion|null[0] + + final object System : kotlinx.datetime/Clock { // kotlinx.datetime/Clock.System|null[0] + final fun now(): kotlinx.datetime/Instant // kotlinx.datetime/Clock.System.now|now(){}[0] + } +} + +sealed interface <#A: kotlin/Any?> kotlinx.datetime.format/DateTimeFormat { // kotlinx.datetime.format/DateTimeFormat|null[0] + abstract fun <#A1: kotlin.text/Appendable> formatTo(#A1, #A): #A1 // kotlinx.datetime.format/DateTimeFormat.formatTo|formatTo(0:0;1:0){0§}[0] + abstract fun format(#A): kotlin/String // kotlinx.datetime.format/DateTimeFormat.format|format(1:0){}[0] + abstract fun parse(kotlin/CharSequence): #A // kotlinx.datetime.format/DateTimeFormat.parse|parse(kotlin.CharSequence){}[0] + abstract fun parseOrNull(kotlin/CharSequence): #A? // kotlinx.datetime.format/DateTimeFormat.parseOrNull|parseOrNull(kotlin.CharSequence){}[0] + + final object Companion { // kotlinx.datetime.format/DateTimeFormat.Companion|null[0] + final fun formatAsKotlinBuilderDsl(kotlinx.datetime.format/DateTimeFormat<*>): kotlin/String // kotlinx.datetime.format/DateTimeFormat.Companion.formatAsKotlinBuilderDsl|formatAsKotlinBuilderDsl(kotlinx.datetime.format.DateTimeFormat<*>){}[0] + } +} + +sealed interface kotlinx.datetime.format/DateTimeFormatBuilder { // kotlinx.datetime.format/DateTimeFormatBuilder|null[0] + abstract fun chars(kotlin/String) // kotlinx.datetime.format/DateTimeFormatBuilder.chars|chars(kotlin.String){}[0] + + sealed interface WithDate : kotlinx.datetime.format/DateTimeFormatBuilder { // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate|null[0] + abstract fun date(kotlinx.datetime.format/DateTimeFormat) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.date|date(kotlinx.datetime.format.DateTimeFormat){}[0] + abstract fun dayOfMonth(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.dayOfMonth|dayOfMonth(kotlinx.datetime.format.Padding){}[0] + abstract fun dayOfWeek(kotlinx.datetime.format/DayOfWeekNames) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.dayOfWeek|dayOfWeek(kotlinx.datetime.format.DayOfWeekNames){}[0] + abstract fun dayOfYear(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.dayOfYear|dayOfYear(kotlinx.datetime.format.Padding){}[0] + abstract fun monthName(kotlinx.datetime.format/MonthNames) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.monthName|monthName(kotlinx.datetime.format.MonthNames){}[0] + abstract fun monthNumber(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.monthNumber|monthNumber(kotlinx.datetime.format.Padding){}[0] + abstract fun year(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.year|year(kotlinx.datetime.format.Padding){}[0] + abstract fun yearTwoDigits(kotlin/Int) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDate.yearTwoDigits|yearTwoDigits(kotlin.Int){}[0] + } + + sealed interface WithDateTime : kotlinx.datetime.format/DateTimeFormatBuilder.WithDate, kotlinx.datetime.format/DateTimeFormatBuilder.WithTime { // kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTime|null[0] + abstract fun dateTime(kotlinx.datetime.format/DateTimeFormat) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTime.dateTime|dateTime(kotlinx.datetime.format.DateTimeFormat){}[0] + } + + sealed interface WithDateTimeComponents : kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTime, kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset { // kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTimeComponents|null[0] + abstract fun dateTimeComponents(kotlinx.datetime.format/DateTimeFormat) // kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTimeComponents.dateTimeComponents|dateTimeComponents(kotlinx.datetime.format.DateTimeFormat){}[0] + abstract fun timeZoneId() // kotlinx.datetime.format/DateTimeFormatBuilder.WithDateTimeComponents.timeZoneId|timeZoneId(){}[0] + } + + sealed interface WithTime : kotlinx.datetime.format/DateTimeFormatBuilder { // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime|null[0] + abstract fun amPmHour(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.amPmHour|amPmHour(kotlinx.datetime.format.Padding){}[0] + abstract fun amPmMarker(kotlin/String, kotlin/String) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.amPmMarker|amPmMarker(kotlin.String;kotlin.String){}[0] + abstract fun hour(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.hour|hour(kotlinx.datetime.format.Padding){}[0] + abstract fun minute(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.minute|minute(kotlinx.datetime.format.Padding){}[0] + abstract fun second(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.second|second(kotlinx.datetime.format.Padding){}[0] + abstract fun secondFraction(kotlin/Int =..., kotlin/Int =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.secondFraction|secondFraction(kotlin.Int;kotlin.Int){}[0] + abstract fun time(kotlinx.datetime.format/DateTimeFormat) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.time|time(kotlinx.datetime.format.DateTimeFormat){}[0] + open fun secondFraction(kotlin/Int) // kotlinx.datetime.format/DateTimeFormatBuilder.WithTime.secondFraction|secondFraction(kotlin.Int){}[0] + } + + sealed interface WithUtcOffset : kotlinx.datetime.format/DateTimeFormatBuilder { // kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset|null[0] + abstract fun offset(kotlinx.datetime.format/DateTimeFormat) // kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset.offset|offset(kotlinx.datetime.format.DateTimeFormat){}[0] + abstract fun offsetHours(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset.offsetHours|offsetHours(kotlinx.datetime.format.Padding){}[0] + abstract fun offsetMinutesOfHour(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset.offsetMinutesOfHour|offsetMinutesOfHour(kotlinx.datetime.format.Padding){}[0] + abstract fun offsetSecondsOfMinute(kotlinx.datetime.format/Padding =...) // kotlinx.datetime.format/DateTimeFormatBuilder.WithUtcOffset.offsetSecondsOfMinute|offsetSecondsOfMinute(kotlinx.datetime.format.Padding){}[0] + } +} + +final class kotlinx.datetime.format/DateTimeComponents { // kotlinx.datetime.format/DateTimeComponents|null[0] + final var amPm // kotlinx.datetime.format/DateTimeComponents.amPm|{}amPm[0] + final fun (): kotlinx.datetime.format/AmPmMarker? // kotlinx.datetime.format/DateTimeComponents.amPm.|(){}[0] + final fun (kotlinx.datetime.format/AmPmMarker?) // kotlinx.datetime.format/DateTimeComponents.amPm.|(kotlinx.datetime.format.AmPmMarker?){}[0] + final var dayOfMonth // kotlinx.datetime.format/DateTimeComponents.dayOfMonth|{}dayOfMonth[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.dayOfMonth.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.dayOfMonth.|(kotlin.Int?){}[0] + final var dayOfWeek // kotlinx.datetime.format/DateTimeComponents.dayOfWeek|{}dayOfWeek[0] + final fun (): kotlinx.datetime/DayOfWeek? // kotlinx.datetime.format/DateTimeComponents.dayOfWeek.|(){}[0] + final fun (kotlinx.datetime/DayOfWeek?) // kotlinx.datetime.format/DateTimeComponents.dayOfWeek.|(kotlinx.datetime.DayOfWeek?){}[0] + final var dayOfYear // kotlinx.datetime.format/DateTimeComponents.dayOfYear|{}dayOfYear[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.dayOfYear.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.dayOfYear.|(kotlin.Int?){}[0] + final var hour // kotlinx.datetime.format/DateTimeComponents.hour|{}hour[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.hour.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.hour.|(kotlin.Int?){}[0] + final var hourOfAmPm // kotlinx.datetime.format/DateTimeComponents.hourOfAmPm|{}hourOfAmPm[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.hourOfAmPm.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.hourOfAmPm.|(kotlin.Int?){}[0] + final var minute // kotlinx.datetime.format/DateTimeComponents.minute|{}minute[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.minute.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.minute.|(kotlin.Int?){}[0] + final var month // kotlinx.datetime.format/DateTimeComponents.month|{}month[0] + final fun (): kotlinx.datetime/Month? // kotlinx.datetime.format/DateTimeComponents.month.|(){}[0] + final fun (kotlinx.datetime/Month?) // kotlinx.datetime.format/DateTimeComponents.month.|(kotlinx.datetime.Month?){}[0] + final var monthNumber // kotlinx.datetime.format/DateTimeComponents.monthNumber|{}monthNumber[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.monthNumber.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.monthNumber.|(kotlin.Int?){}[0] + final var nanosecond // kotlinx.datetime.format/DateTimeComponents.nanosecond|{}nanosecond[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.nanosecond.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.nanosecond.|(kotlin.Int?){}[0] + final var offsetHours // kotlinx.datetime.format/DateTimeComponents.offsetHours|{}offsetHours[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.offsetHours.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.offsetHours.|(kotlin.Int?){}[0] + final var offsetIsNegative // kotlinx.datetime.format/DateTimeComponents.offsetIsNegative|{}offsetIsNegative[0] + final fun (): kotlin/Boolean? // kotlinx.datetime.format/DateTimeComponents.offsetIsNegative.|(){}[0] + final fun (kotlin/Boolean?) // kotlinx.datetime.format/DateTimeComponents.offsetIsNegative.|(kotlin.Boolean?){}[0] + final var offsetMinutesOfHour // kotlinx.datetime.format/DateTimeComponents.offsetMinutesOfHour|{}offsetMinutesOfHour[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.offsetMinutesOfHour.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.offsetMinutesOfHour.|(kotlin.Int?){}[0] + final var offsetSecondsOfMinute // kotlinx.datetime.format/DateTimeComponents.offsetSecondsOfMinute|{}offsetSecondsOfMinute[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.offsetSecondsOfMinute.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.offsetSecondsOfMinute.|(kotlin.Int?){}[0] + final var second // kotlinx.datetime.format/DateTimeComponents.second|{}second[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.second.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.second.|(kotlin.Int?){}[0] + final var timeZoneId // kotlinx.datetime.format/DateTimeComponents.timeZoneId|{}timeZoneId[0] + final fun (): kotlin/String? // kotlinx.datetime.format/DateTimeComponents.timeZoneId.|(){}[0] + final fun (kotlin/String?) // kotlinx.datetime.format/DateTimeComponents.timeZoneId.|(kotlin.String?){}[0] + final var year // kotlinx.datetime.format/DateTimeComponents.year|(kotlin.Int?){}[0] + final fun (): kotlin/Int? // kotlinx.datetime.format/DateTimeComponents.year.|(){}[0] + final fun (kotlin/Int?) // kotlinx.datetime.format/DateTimeComponents.year.|(kotlin.Int?){}[0] + + final fun setDate(kotlinx.datetime/LocalDate) // kotlinx.datetime.format/DateTimeComponents.setDate|setDate(kotlinx.datetime.LocalDate){}[0] + final fun setDateTime(kotlinx.datetime/LocalDateTime) // kotlinx.datetime.format/DateTimeComponents.setDateTime|setDateTime(kotlinx.datetime.LocalDateTime){}[0] + final fun setDateTimeOffset(kotlinx.datetime/Instant, kotlinx.datetime/UtcOffset) // kotlinx.datetime.format/DateTimeComponents.setDateTimeOffset|setDateTimeOffset(kotlinx.datetime.Instant;kotlinx.datetime.UtcOffset){}[0] + final fun setDateTimeOffset(kotlinx.datetime/LocalDateTime, kotlinx.datetime/UtcOffset) // kotlinx.datetime.format/DateTimeComponents.setDateTimeOffset|setDateTimeOffset(kotlinx.datetime.LocalDateTime;kotlinx.datetime.UtcOffset){}[0] + final fun setDateTimeOffset(kotlinx.time/Instant, kotlinx.datetime/UtcOffset) // kotlinx.datetime.format/DateTimeComponents.setDateTimeOffset|setDateTimeOffset(kotlinx.time.Instant;kotlinx.datetime.UtcOffset){}[0] + final fun setOffset(kotlinx.datetime/UtcOffset) // kotlinx.datetime.format/DateTimeComponents.setOffset|setOffset(kotlinx.datetime.UtcOffset){}[0] + final fun setTime(kotlinx.datetime/LocalTime) // kotlinx.datetime.format/DateTimeComponents.setTime|setTime(kotlinx.datetime.LocalTime){}[0] + final fun toInstantUsingOffset(): kotlinx.datetime/Instant // kotlinx.datetime.format/DateTimeComponents.toInstantUsingOffset|toInstantUsingOffset(){}[0] + final fun toInstantUsingOffset(kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime.format/DateTimeComponents.toInstantUsingOffset|toInstantUsingOffset(kotlinx.datetime.DeprecationMarker){}[0] + final fun toLocalDate(): kotlinx.datetime/LocalDate // kotlinx.datetime.format/DateTimeComponents.toLocalDate|toLocalDate(){}[0] + final fun toLocalDateTime(): kotlinx.datetime/LocalDateTime // kotlinx.datetime.format/DateTimeComponents.toLocalDateTime|toLocalDateTime(){}[0] + final fun toLocalTime(): kotlinx.datetime/LocalTime // kotlinx.datetime.format/DateTimeComponents.toLocalTime|toLocalTime(){}[0] + final fun toUtcOffset(): kotlinx.datetime/UtcOffset // kotlinx.datetime.format/DateTimeComponents.toUtcOffset|toUtcOffset(){}[0] + + final object Companion { // kotlinx.datetime.format/DateTimeComponents.Companion|null[0] + final fun Format(kotlin/Function1): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime.format/DateTimeComponents.Companion.Format|Format(kotlin.Function1){}[0] + } + + final object Formats { // kotlinx.datetime.format/DateTimeComponents.Formats|null[0] + final val ISO_DATE_TIME_OFFSET // kotlinx.datetime.format/DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET|{}ISO_DATE_TIME_OFFSET[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime.format/DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET.|(){}[0] + final val RFC_1123 // kotlinx.datetime.format/DateTimeComponents.Formats.RFC_1123|{}RFC_1123[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime.format/DateTimeComponents.Formats.RFC_1123.|(){}[0] + } +} + +final class kotlinx.datetime.format/DayOfWeekNames { // kotlinx.datetime.format/DayOfWeekNames|null[0] + constructor (kotlin.collections/List) // kotlinx.datetime.format/DayOfWeekNames.|(kotlin.collections.List){}[0] + constructor (kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String) // kotlinx.datetime.format/DayOfWeekNames.|(kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String){}[0] + + final val names // kotlinx.datetime.format/DayOfWeekNames.names|{}names[0] + final fun (): kotlin.collections/List // kotlinx.datetime.format/DayOfWeekNames.names.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime.format/DayOfWeekNames.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime.format/DayOfWeekNames.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime.format/DayOfWeekNames.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime.format/DayOfWeekNames.Companion|null[0] + final val ENGLISH_ABBREVIATED // kotlinx.datetime.format/DayOfWeekNames.Companion.ENGLISH_ABBREVIATED|{}ENGLISH_ABBREVIATED[0] + final fun (): kotlinx.datetime.format/DayOfWeekNames // kotlinx.datetime.format/DayOfWeekNames.Companion.ENGLISH_ABBREVIATED.|(){}[0] + final val ENGLISH_FULL // kotlinx.datetime.format/DayOfWeekNames.Companion.ENGLISH_FULL|{}ENGLISH_FULL[0] + final fun (): kotlinx.datetime.format/DayOfWeekNames // kotlinx.datetime.format/DayOfWeekNames.Companion.ENGLISH_FULL.|(){}[0] + } +} + +final class kotlinx.datetime.format/MonthNames { // kotlinx.datetime.format/MonthNames|null[0] + constructor (kotlin.collections/List) // kotlinx.datetime.format/MonthNames.|(kotlin.collections.List){}[0] + constructor (kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String, kotlin/String) // kotlinx.datetime.format/MonthNames.|(kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String;kotlin.String){}[0] + + final val names // kotlinx.datetime.format/MonthNames.names|{}names[0] + final fun (): kotlin.collections/List // kotlinx.datetime.format/MonthNames.names.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime.format/MonthNames.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime.format/MonthNames.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime.format/MonthNames.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime.format/MonthNames.Companion|null[0] + final val ENGLISH_ABBREVIATED // kotlinx.datetime.format/MonthNames.Companion.ENGLISH_ABBREVIATED|{}ENGLISH_ABBREVIATED[0] + final fun (): kotlinx.datetime.format/MonthNames // kotlinx.datetime.format/MonthNames.Companion.ENGLISH_ABBREVIATED.|(){}[0] + final val ENGLISH_FULL // kotlinx.datetime.format/MonthNames.Companion.ENGLISH_FULL|{}ENGLISH_FULL[0] + final fun (): kotlinx.datetime.format/MonthNames // kotlinx.datetime.format/MonthNames.Companion.ENGLISH_FULL.|(){}[0] + } +} + +final class kotlinx.datetime/DatePeriod : kotlinx.datetime/DateTimePeriod { // kotlinx.datetime/DatePeriod|null[0] + constructor (kotlin/Int =..., kotlin/Int =..., kotlin/Int =...) // kotlinx.datetime/DatePeriod.|(kotlin.Int;kotlin.Int;kotlin.Int){}[0] + + final val days // kotlinx.datetime/DatePeriod.days|{}days[0] + final fun (): kotlin/Int // kotlinx.datetime/DatePeriod.days.|(){}[0] + final val hours // kotlinx.datetime/DatePeriod.hours|{}hours[0] + final fun (): kotlin/Int // kotlinx.datetime/DatePeriod.hours.|(){}[0] + final val minutes // kotlinx.datetime/DatePeriod.minutes|{}minutes[0] + final fun (): kotlin/Int // kotlinx.datetime/DatePeriod.minutes.|(){}[0] + final val nanoseconds // kotlinx.datetime/DatePeriod.nanoseconds|{}nanoseconds[0] + final fun (): kotlin/Int // kotlinx.datetime/DatePeriod.nanoseconds.|(){}[0] + final val seconds // kotlinx.datetime/DatePeriod.seconds|{}seconds[0] + final fun (): kotlin/Int // kotlinx.datetime/DatePeriod.seconds.|(){}[0] + + final object Companion { // kotlinx.datetime/DatePeriod.Companion|null[0] + final fun parse(kotlin/String): kotlinx.datetime/DatePeriod // kotlinx.datetime/DatePeriod.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DatePeriod.Companion.serializer|serializer(){}[0] + } +} + +final class kotlinx.datetime/DateTimeArithmeticException : kotlin/RuntimeException { // kotlinx.datetime/DateTimeArithmeticException|null[0] + constructor () // kotlinx.datetime/DateTimeArithmeticException.|(){}[0] + constructor (kotlin/String) // kotlinx.datetime/DateTimeArithmeticException.|(kotlin.String){}[0] + constructor (kotlin/String, kotlin/Throwable) // kotlinx.datetime/DateTimeArithmeticException.|(kotlin.String;kotlin.Throwable){}[0] + constructor (kotlin/Throwable) // kotlinx.datetime/DateTimeArithmeticException.|(kotlin.Throwable){}[0] +} + +final class kotlinx.datetime/DeprecationMarker // kotlinx.datetime/DeprecationMarker|null[0] + +final class kotlinx.datetime/FixedOffsetTimeZone : kotlinx.datetime/TimeZone { // kotlinx.datetime/FixedOffsetTimeZone|null[0] + constructor (kotlinx.datetime/UtcOffset) // kotlinx.datetime/FixedOffsetTimeZone.|(kotlinx.datetime.UtcOffset){}[0] + + final val id // kotlinx.datetime/FixedOffsetTimeZone.id|{}id[0] + final fun (): kotlin/String // kotlinx.datetime/FixedOffsetTimeZone.id.|(){}[0] + final val offset // kotlinx.datetime/FixedOffsetTimeZone.offset|{}offset[0] + final fun (): kotlinx.datetime/UtcOffset // kotlinx.datetime/FixedOffsetTimeZone.offset.|(){}[0] + final val totalSeconds // kotlinx.datetime/FixedOffsetTimeZone.totalSeconds|{}totalSeconds[0] + final fun (): kotlin/Int // kotlinx.datetime/FixedOffsetTimeZone.totalSeconds.|(){}[0] + + final object Companion { // kotlinx.datetime/FixedOffsetTimeZone.Companion|null[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/FixedOffsetTimeZone.Companion.serializer|serializer(){}[0] + } +} + +final class kotlinx.datetime/IllegalTimeZoneException : kotlin/IllegalArgumentException { // kotlinx.datetime/IllegalTimeZoneException|null[0] + constructor () // kotlinx.datetime/IllegalTimeZoneException.|(){}[0] + constructor (kotlin/String) // kotlinx.datetime/IllegalTimeZoneException.|(kotlin.String){}[0] + constructor (kotlin/String, kotlin/Throwable) // kotlinx.datetime/IllegalTimeZoneException.|(kotlin.String;kotlin.Throwable){}[0] + constructor (kotlin/Throwable) // kotlinx.datetime/IllegalTimeZoneException.|(kotlin.Throwable){}[0] +} + +final class kotlinx.datetime/Instant : kotlin/Comparable { // kotlinx.datetime/Instant|null[0] + final val epochSeconds // kotlinx.datetime/Instant.epochSeconds|{}epochSeconds[0] + final fun (): kotlin/Long // kotlinx.datetime/Instant.epochSeconds.|(){}[0] + final val nanosecondsOfSecond // kotlinx.datetime/Instant.nanosecondsOfSecond|{}nanosecondsOfSecond[0] + final fun (): kotlin/Int // kotlinx.datetime/Instant.nanosecondsOfSecond.|(){}[0] + + final fun compareTo(kotlinx.datetime/Instant): kotlin/Int // kotlinx.datetime/Instant.compareTo|compareTo(kotlinx.datetime.Instant){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/Instant.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/Instant.hashCode|hashCode(){}[0] + final fun minus(kotlin.time/Duration): kotlinx.datetime/Instant // kotlinx.datetime/Instant.minus|minus(kotlin.time.Duration){}[0] + final fun minus(kotlinx.datetime/Instant): kotlin.time/Duration // kotlinx.datetime/Instant.minus|minus(kotlinx.datetime.Instant){}[0] + final fun plus(kotlin.time/Duration): kotlinx.datetime/Instant // kotlinx.datetime/Instant.plus|plus(kotlin.time.Duration){}[0] + final fun toEpochMilliseconds(): kotlin/Long // kotlinx.datetime/Instant.toEpochMilliseconds|toEpochMilliseconds(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/Instant.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/Instant.Companion|null[0] + final val DISTANT_FUTURE // kotlinx.datetime/Instant.Companion.DISTANT_FUTURE|{}DISTANT_FUTURE[0] + final fun (): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.DISTANT_FUTURE.|(){}[0] + final val DISTANT_PAST // kotlinx.datetime/Instant.Companion.DISTANT_PAST|{}DISTANT_PAST[0] + final fun (): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.DISTANT_PAST.|(){}[0] + + final fun fromEpochMilliseconds(kotlin/Long): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.fromEpochMilliseconds|fromEpochMilliseconds(kotlin.Long){}[0] + final fun fromEpochSeconds(kotlin/Long, kotlin/Int): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.fromEpochSeconds|fromEpochSeconds(kotlin.Long;kotlin.Int){}[0] + final fun fromEpochSeconds(kotlin/Long, kotlin/Long =...): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.fromEpochSeconds|fromEpochSeconds(kotlin.Long;kotlin.Long){}[0] + final fun now(): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.now|now(){}[0] + final fun parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat =...): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.parse|parse(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] + final fun parse(kotlin/String): kotlinx.datetime/Instant // kotlinx.datetime/Instant.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/Instant.Companion.serializer|serializer(){}[0] + } +} + +final class kotlinx.datetime/LocalDate : kotlin/Comparable { // kotlinx.datetime/LocalDate|null[0] + constructor (kotlin/Int, kotlin/Int, kotlin/Int) // kotlinx.datetime/LocalDate.|(kotlin.Int;kotlin.Int;kotlin.Int){}[0] + constructor (kotlin/Int, kotlinx.datetime/Month, kotlin/Int) // kotlinx.datetime/LocalDate.|(kotlin.Int;kotlinx.datetime.Month;kotlin.Int){}[0] + + final val dayOfMonth // kotlinx.datetime/LocalDate.dayOfMonth|{}dayOfMonth[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDate.dayOfMonth.|(){}[0] + final val dayOfWeek // kotlinx.datetime/LocalDate.dayOfWeek|{}dayOfWeek[0] + final fun (): kotlinx.datetime/DayOfWeek // kotlinx.datetime/LocalDate.dayOfWeek.|(){}[0] + final val dayOfYear // kotlinx.datetime/LocalDate.dayOfYear|{}dayOfYear[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDate.dayOfYear.|(){}[0] + final val month // kotlinx.datetime/LocalDate.month|(){}[0] + final fun (): kotlinx.datetime/Month // kotlinx.datetime/LocalDate.month.|(){}[0] + final val monthNumber // kotlinx.datetime/LocalDate.monthNumber|{}monthNumber[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDate.monthNumber.|(){}[0] + final val year // kotlinx.datetime/LocalDate.year|{}year[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDate.year.|(){}[0] + + final fun compareTo(kotlinx.datetime/LocalDate): kotlin/Int // kotlinx.datetime/LocalDate.compareTo|compareTo(kotlinx.datetime.LocalDate){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/LocalDate.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/LocalDate.hashCode|hashCode(){}[0] + final fun toEpochDays(): kotlin/Long // kotlinx.datetime/LocalDate.toEpochDays|toEpochDays(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/LocalDate.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/LocalDate.Companion|null[0] + final fun Format(kotlin/Function1): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalDate.Companion.Format|Format(kotlin.Function1){}[0] + final fun fromEpochDays(kotlin/Int): kotlinx.datetime/LocalDate // kotlinx.datetime/LocalDate.Companion.fromEpochDays|fromEpochDays(kotlin.Int){}[0] + final fun fromEpochDays(kotlin/Long): kotlinx.datetime/LocalDate // kotlinx.datetime/LocalDate.Companion.fromEpochDays|fromEpochDays(kotlin.Long){}[0] + final fun parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat =...): kotlinx.datetime/LocalDate // kotlinx.datetime/LocalDate.Companion.parse|parse(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] + final fun parse(kotlin/String): kotlinx.datetime/LocalDate // kotlinx.datetime/LocalDate.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/LocalDate.Companion.serializer|serializer(){}[0] + } + + final object Formats { // kotlinx.datetime/LocalDate.Formats|null[0] + final val ISO // kotlinx.datetime/LocalDate.Formats.ISO|{}ISO[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalDate.Formats.ISO.|(){}[0] + final val ISO_BASIC // kotlinx.datetime/LocalDate.Formats.ISO_BASIC|{}ISO_BASIC[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalDate.Formats.ISO_BASIC.|(){}[0] + } +} + +final class kotlinx.datetime/LocalDateTime : kotlin/Comparable { // kotlinx.datetime/LocalDateTime|null[0] + constructor (kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Int =..., kotlin/Int =...) // kotlinx.datetime/LocalDateTime.|(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int){}[0] + constructor (kotlin/Int, kotlinx.datetime/Month, kotlin/Int, kotlin/Int, kotlin/Int, kotlin/Int =..., kotlin/Int =...) // kotlinx.datetime/LocalDateTime.|(kotlin.Int;kotlinx.datetime.Month;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int){}[0] + constructor (kotlinx.datetime/LocalDate, kotlinx.datetime/LocalTime) // kotlinx.datetime/LocalDateTime.|(kotlinx.datetime.LocalDate;kotlinx.datetime.LocalTime){}[0] + + final val date // kotlinx.datetime/LocalDateTime.date|{}date[0] + final fun (): kotlinx.datetime/LocalDate // kotlinx.datetime/LocalDateTime.date.|(){}[0] + final val dayOfMonth // kotlinx.datetime/LocalDateTime.dayOfMonth|{}dayOfMonth[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.dayOfMonth.|(){}[0] + final val dayOfWeek // kotlinx.datetime/LocalDateTime.dayOfWeek|{}dayOfWeek[0] + final fun (): kotlinx.datetime/DayOfWeek // kotlinx.datetime/LocalDateTime.dayOfWeek.|(){}[0] + final val dayOfYear // kotlinx.datetime/LocalDateTime.dayOfYear|{}dayOfYear[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.dayOfYear.|(){}[0] + final val hour // kotlinx.datetime/LocalDateTime.hour|{}hour[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.hour.|(){}[0] + final val minute // kotlinx.datetime/LocalDateTime.minute|{}minute[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.minute.|(){}[0] + final val month // kotlinx.datetime/LocalDateTime.month|{}month[0] + final fun (): kotlinx.datetime/Month // kotlinx.datetime/LocalDateTime.month.|(){}[0] + final val monthNumber // kotlinx.datetime/LocalDateTime.monthNumber|{}monthNumber[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.monthNumber.|(){}[0] + final val nanosecond // kotlinx.datetime/LocalDateTime.nanosecond|{}nanosecond[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.nanosecond.|(){}[0] + final val second // kotlinx.datetime/LocalDateTime.second|{}second[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.second.|(){}[0] + final val time // kotlinx.datetime/LocalDateTime.time|{}time[0] + final fun (): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalDateTime.time.|(){}[0] + final val year // kotlinx.datetime/LocalDateTime.year|{}year[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalDateTime.year.|(){}[0] + + final fun compareTo(kotlinx.datetime/LocalDateTime): kotlin/Int // kotlinx.datetime/LocalDateTime.compareTo|compareTo(kotlinx.datetime.LocalDateTime){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/LocalDateTime.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/LocalDateTime.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/LocalDateTime.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/LocalDateTime.Companion|null[0] + final fun Format(kotlin/Function1): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalDateTime.Companion.Format|Format(kotlin.Function1){}[0] + final fun parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat =...): kotlinx.datetime/LocalDateTime // kotlinx.datetime/LocalDateTime.Companion.parse|parse(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] + final fun parse(kotlin/String): kotlinx.datetime/LocalDateTime // kotlinx.datetime/LocalDateTime.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/LocalDateTime.Companion.serializer|serializer(){}[0] + } + + final object Formats { // kotlinx.datetime/LocalDateTime.Formats|null[0] + final val ISO // kotlinx.datetime/LocalDateTime.Formats.ISO|{}ISO[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalDateTime.Formats.ISO.|(){}[0] + } +} + +final class kotlinx.datetime/LocalTime : kotlin/Comparable { // kotlinx.datetime/LocalTime|null[0] + constructor (kotlin/Int, kotlin/Int, kotlin/Int =..., kotlin/Int =...) // kotlinx.datetime/LocalTime.|(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int){}[0] + + final val hour // kotlinx.datetime/LocalTime.hour|{}hour[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalTime.hour.|(){}[0] + final val minute // kotlinx.datetime/LocalTime.minute|{}minute[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalTime.minute.|(){}[0] + final val nanosecond // kotlinx.datetime/LocalTime.nanosecond|{}nanosecond[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalTime.nanosecond.|(){}[0] + final val second // kotlinx.datetime/LocalTime.second|{}second[0] + final fun (): kotlin/Int // kotlinx.datetime/LocalTime.second.|(){}[0] + + final fun compareTo(kotlinx.datetime/LocalTime): kotlin/Int // kotlinx.datetime/LocalTime.compareTo|compareTo(kotlinx.datetime.LocalTime){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/LocalTime.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/LocalTime.hashCode|hashCode(){}[0] + final fun toMillisecondOfDay(): kotlin/Int // kotlinx.datetime/LocalTime.toMillisecondOfDay|toMillisecondOfDay(){}[0] + final fun toNanosecondOfDay(): kotlin/Long // kotlinx.datetime/LocalTime.toNanosecondOfDay|toNanosecondOfDay(){}[0] + final fun toSecondOfDay(): kotlin/Int // kotlinx.datetime/LocalTime.toSecondOfDay|toSecondOfDay(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/LocalTime.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/LocalTime.Companion|null[0] + final fun Format(kotlin/Function1): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalTime.Companion.Format|Format(kotlin.Function1){}[0] + final fun fromMillisecondOfDay(kotlin/Int): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalTime.Companion.fromMillisecondOfDay|fromMillisecondOfDay(kotlin.Int){}[0] + final fun fromNanosecondOfDay(kotlin/Long): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalTime.Companion.fromNanosecondOfDay|fromNanosecondOfDay(kotlin.Long){}[0] + final fun fromSecondOfDay(kotlin/Int): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalTime.Companion.fromSecondOfDay|fromSecondOfDay(kotlin.Int){}[0] + final fun parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat =...): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalTime.Companion.parse|parse(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] + final fun parse(kotlin/String): kotlinx.datetime/LocalTime // kotlinx.datetime/LocalTime.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/LocalTime.Companion.serializer|serializer(){}[0] + } + + final object Formats { // kotlinx.datetime/LocalTime.Formats|null[0] + final val ISO // kotlinx.datetime/LocalTime.Formats.ISO|{}ISO[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/LocalTime.Formats.ISO.|(){}[0] + } +} + +final class kotlinx.datetime/UtcOffset { // kotlinx.datetime/UtcOffset|null[0] + final val totalSeconds // kotlinx.datetime/UtcOffset.totalSeconds|{}totalSeconds[0] + final fun (): kotlin/Int // kotlinx.datetime/UtcOffset.totalSeconds.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/UtcOffset.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/UtcOffset.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/UtcOffset.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/UtcOffset.Companion|null[0] + final val ZERO // kotlinx.datetime/UtcOffset.Companion.ZERO|{}ZERO[0] + final fun (): kotlinx.datetime/UtcOffset // kotlinx.datetime/UtcOffset.Companion.ZERO.|(){}[0] + + final fun Format(kotlin/Function1): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/UtcOffset.Companion.Format|Format(kotlin.Function1){}[0] + final fun parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat =...): kotlinx.datetime/UtcOffset // kotlinx.datetime/UtcOffset.Companion.parse|parse(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] + final fun parse(kotlin/String): kotlinx.datetime/UtcOffset // kotlinx.datetime/UtcOffset.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/UtcOffset.Companion.serializer|serializer(){}[0] + } + + final object Formats { // kotlinx.datetime/UtcOffset.Formats|null[0] + final val FOUR_DIGITS // kotlinx.datetime/UtcOffset.Formats.FOUR_DIGITS|{}FOUR_DIGITS[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/UtcOffset.Formats.FOUR_DIGITS.|(){}[0] + final val ISO // kotlinx.datetime/UtcOffset.Formats.ISO|(){}[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/UtcOffset.Formats.ISO.|(){}[0] + final val ISO_BASIC // kotlinx.datetime/UtcOffset.Formats.ISO_BASIC|{}ISO_BASIC[0] + final fun (): kotlinx.datetime.format/DateTimeFormat // kotlinx.datetime/UtcOffset.Formats.ISO_BASIC.|(){}[0] + } +} + +open class kotlinx.datetime/TimeZone { // kotlinx.datetime/TimeZone|null[0] + open val id // kotlinx.datetime/TimeZone.id|{}id[0] + open fun (): kotlin/String // kotlinx.datetime/TimeZone.id.|(){}[0] + + final fun (kotlinx.datetime/Instant).toLocalDateTime(): kotlinx.datetime/LocalDateTime // kotlinx.datetime/TimeZone.toLocalDateTime|toLocalDateTime@kotlinx.datetime.Instant(){}[0] + final fun (kotlinx.datetime/LocalDateTime).toInstant(): kotlinx.datetime/Instant // kotlinx.datetime/TimeZone.toInstant|toInstant@kotlinx.datetime.LocalDateTime(){}[0] + final fun (kotlinx.datetime/LocalDateTime).toInstant(kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime/TimeZone.toInstant|toInstant@kotlinx.datetime.LocalDateTime(kotlinx.datetime.DeprecationMarker){}[0] + final fun (kotlinx.time/Instant).toLocalDateTime(): kotlinx.datetime/LocalDateTime // kotlinx.datetime/TimeZone.toLocalDateTime|toLocalDateTime@kotlinx.time.Instant(){}[0] + open fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/TimeZone.equals|equals(kotlin.Any?){}[0] + open fun hashCode(): kotlin/Int // kotlinx.datetime/TimeZone.hashCode|hashCode(){}[0] + open fun toString(): kotlin/String // kotlinx.datetime/TimeZone.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/TimeZone.Companion|null[0] + final val UTC // kotlinx.datetime/TimeZone.Companion.UTC|{}UTC[0] + final fun (): kotlinx.datetime/FixedOffsetTimeZone // kotlinx.datetime/TimeZone.Companion.UTC.|(){}[0] + final val availableZoneIds // kotlinx.datetime/TimeZone.Companion.availableZoneIds|{}availableZoneIds[0] + final fun (): kotlin.collections/Set // kotlinx.datetime/TimeZone.Companion.availableZoneIds.|(){}[0] + + final fun currentSystemDefault(): kotlinx.datetime/TimeZone // kotlinx.datetime/TimeZone.Companion.currentSystemDefault|currentSystemDefault(){}[0] + final fun of(kotlin/String): kotlinx.datetime/TimeZone // kotlinx.datetime/TimeZone.Companion.of|of(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/TimeZone.Companion.serializer|serializer(){}[0] + } +} + +sealed class kotlinx.datetime/DateTimePeriod { // kotlinx.datetime/DateTimePeriod|null[0] + constructor () // kotlinx.datetime/DateTimePeriod.|(){}[0] + + abstract val days // kotlinx.datetime/DateTimePeriod.days|{}days[0] + abstract fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.days.|(){}[0] + final val months // kotlinx.datetime/DateTimePeriod.months|{}months[0] + final fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.months.|(){}[0] + final val years // kotlinx.datetime/DateTimePeriod.years|{}years[0] + final fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.years.|(){}[0] + open val hours // kotlinx.datetime/DateTimePeriod.hours|{}hours[0] + open fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.hours.|(){}[0] + open val minutes // kotlinx.datetime/DateTimePeriod.minutes|{}minutes[0] + open fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.minutes.|(){}[0] + open val nanoseconds // kotlinx.datetime/DateTimePeriod.nanoseconds|{}nanoseconds[0] + open fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.nanoseconds.|(){}[0] + open val seconds // kotlinx.datetime/DateTimePeriod.seconds|{}seconds[0] + open fun (): kotlin/Int // kotlinx.datetime/DateTimePeriod.seconds.|(){}[0] + + open fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/DateTimePeriod.equals|equals(kotlin.Any?){}[0] + open fun hashCode(): kotlin/Int // kotlinx.datetime/DateTimePeriod.hashCode|hashCode(){}[0] + open fun toString(): kotlin/String // kotlinx.datetime/DateTimePeriod.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/DateTimePeriod.Companion|null[0] + final fun parse(kotlin/String): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/DateTimePeriod.Companion.parse|parse(kotlin.String){}[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimePeriod.Companion.serializer|serializer(){}[0] + } +} + +sealed class kotlinx.datetime/DateTimeUnit { // kotlinx.datetime/DateTimeUnit|null[0] + constructor () // kotlinx.datetime/DateTimeUnit.|(){}[0] + + abstract fun times(kotlin/Int): kotlinx.datetime/DateTimeUnit // kotlinx.datetime/DateTimeUnit.times|times(kotlin.Int){}[0] + final fun formatToString(kotlin/Int, kotlin/String): kotlin/String // kotlinx.datetime/DateTimeUnit.formatToString|formatToString(kotlin.Int;kotlin.String){}[0] + final fun formatToString(kotlin/Long, kotlin/String): kotlin/String // kotlinx.datetime/DateTimeUnit.formatToString|formatToString(kotlin.Long;kotlin.String){}[0] + + final class DayBased : kotlinx.datetime/DateTimeUnit.DateBased { // kotlinx.datetime/DateTimeUnit.DayBased|null[0] + constructor (kotlin/Int) // kotlinx.datetime/DateTimeUnit.DayBased.|(kotlin.Int){}[0] + + final val days // kotlinx.datetime/DateTimeUnit.DayBased.days|{}days[0] + final fun (): kotlin/Int // kotlinx.datetime/DateTimeUnit.DayBased.days.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/DateTimeUnit.DayBased.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/DateTimeUnit.DayBased.hashCode|hashCode(){}[0] + final fun times(kotlin/Int): kotlinx.datetime/DateTimeUnit.DayBased // kotlinx.datetime/DateTimeUnit.DayBased.times|times(kotlin.Int){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/DateTimeUnit.DayBased.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/DateTimeUnit.DayBased.Companion|null[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimeUnit.DayBased.Companion.serializer|serializer(){}[0] + } + } + + final class MonthBased : kotlinx.datetime/DateTimeUnit.DateBased { // kotlinx.datetime/DateTimeUnit.MonthBased|null[0] + constructor (kotlin/Int) // kotlinx.datetime/DateTimeUnit.MonthBased.|(kotlin.Int){}[0] + + final val months // kotlinx.datetime/DateTimeUnit.MonthBased.months|{}months[0] + final fun (): kotlin/Int // kotlinx.datetime/DateTimeUnit.MonthBased.months.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/DateTimeUnit.MonthBased.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/DateTimeUnit.MonthBased.hashCode|hashCode(){}[0] + final fun times(kotlin/Int): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime/DateTimeUnit.MonthBased.times|times(kotlin.Int){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/DateTimeUnit.MonthBased.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/DateTimeUnit.MonthBased.Companion|null[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimeUnit.MonthBased.Companion.serializer|serializer(){}[0] + } + } + + final class TimeBased : kotlinx.datetime/DateTimeUnit { // kotlinx.datetime/DateTimeUnit.TimeBased|null[0] + constructor (kotlin/Long) // kotlinx.datetime/DateTimeUnit.TimeBased.|(kotlin.Long){}[0] + + final val duration // kotlinx.datetime/DateTimeUnit.TimeBased.duration|{}duration[0] + final fun (): kotlin.time/Duration // kotlinx.datetime/DateTimeUnit.TimeBased.duration.|(){}[0] + final val nanoseconds // kotlinx.datetime/DateTimeUnit.TimeBased.nanoseconds|{}nanoseconds[0] + final fun (): kotlin/Long // kotlinx.datetime/DateTimeUnit.TimeBased.nanoseconds.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.datetime/DateTimeUnit.TimeBased.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.datetime/DateTimeUnit.TimeBased.hashCode|hashCode(){}[0] + final fun times(kotlin/Int): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.TimeBased.times|times(kotlin.Int){}[0] + final fun toString(): kotlin/String // kotlinx.datetime/DateTimeUnit.TimeBased.toString|toString(){}[0] + + final object Companion { // kotlinx.datetime/DateTimeUnit.TimeBased.Companion|null[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimeUnit.TimeBased.Companion.serializer|serializer(){}[0] + } + } + + sealed class DateBased : kotlinx.datetime/DateTimeUnit { // kotlinx.datetime/DateTimeUnit.DateBased|null[0] + constructor () // kotlinx.datetime/DateTimeUnit.DateBased.|(){}[0] + + final object Companion { // kotlinx.datetime/DateTimeUnit.DateBased.Companion|null[0] + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimeUnit.DateBased.Companion.serializer|serializer(){}[0] + } + } + + final object Companion { // kotlinx.datetime/DateTimeUnit.Companion|null[0] + final val CENTURY // kotlinx.datetime/DateTimeUnit.Companion.CENTURY|{}CENTURY[0] + final fun (): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime/DateTimeUnit.Companion.CENTURY.|(){}[0] + final val DAY // kotlinx.datetime/DateTimeUnit.Companion.DAY|{}DAY[0] + final fun (): kotlinx.datetime/DateTimeUnit.DayBased // kotlinx.datetime/DateTimeUnit.Companion.DAY.|(){}[0] + final val HOUR // kotlinx.datetime/DateTimeUnit.Companion.HOUR|{}HOUR[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.HOUR.|(){}[0] + final val MICROSECOND // kotlinx.datetime/DateTimeUnit.Companion.MICROSECOND|{}MICROSECOND[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.MICROSECOND.|(){}[0] + final val MILLISECOND // kotlinx.datetime/DateTimeUnit.Companion.MILLISECOND|{}MILLISECOND[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.MILLISECOND.|(){}[0] + final val MINUTE // kotlinx.datetime/DateTimeUnit.Companion.MINUTE|{}MINUTE[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.MINUTE.|(){}[0] + final val MONTH // kotlinx.datetime/DateTimeUnit.Companion.MONTH|{}MONTH[0] + final fun (): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime/DateTimeUnit.Companion.MONTH.|(){}[0] + final val NANOSECOND // kotlinx.datetime/DateTimeUnit.Companion.NANOSECOND|{}NANOSECOND[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.NANOSECOND.|(){}[0] + final val QUARTER // kotlinx.datetime/DateTimeUnit.Companion.QUARTER|{}QUARTER[0] + final fun (): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime/DateTimeUnit.Companion.QUARTER.|(){}[0] + final val SECOND // kotlinx.datetime/DateTimeUnit.Companion.SECOND|{}SECOND[0] + final fun (): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime/DateTimeUnit.Companion.SECOND.|(){}[0] + final val WEEK // kotlinx.datetime/DateTimeUnit.Companion.WEEK|{}WEEK[0] + final fun (): kotlinx.datetime/DateTimeUnit.DayBased // kotlinx.datetime/DateTimeUnit.Companion.WEEK.|(){}[0] + final val YEAR // kotlinx.datetime/DateTimeUnit.Companion.YEAR|{}YEAR[0] + final fun (): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime/DateTimeUnit.Companion.YEAR.|(){}[0] + + final fun serializer(): kotlinx.serialization/KSerializer // kotlinx.datetime/DateTimeUnit.Companion.serializer|serializer(){}[0] + } +} + +final object kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer : kotlinx.serialization.internal/AbstractPolymorphicSerializer { // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer|null[0] + final val baseClass // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.baseClass|{}baseClass[0] + final fun (): kotlin.reflect/KClass // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.baseClass.|(){}[0] + final val descriptor // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.descriptor.|(){}[0] + + final fun findPolymorphicSerializerOrNull(kotlinx.serialization.encoding/CompositeDecoder, kotlin/String?): kotlinx.serialization/DeserializationStrategy? // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.findPolymorphicSerializerOrNull|findPolymorphicSerializerOrNull(kotlinx.serialization.encoding.CompositeDecoder;kotlin.String?){}[0] + final fun findPolymorphicSerializerOrNull(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.serialization/SerializationStrategy? // kotlinx.datetime.serializers/DateBasedDateTimeUnitSerializer.findPolymorphicSerializerOrNull|findPolymorphicSerializerOrNull(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +} + +final object kotlinx.datetime.serializers/DatePeriodComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DatePeriodComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DatePeriodComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DatePeriodComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DatePeriod // kotlinx.datetime.serializers/DatePeriodComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DatePeriod) // kotlinx.datetime.serializers/DatePeriodComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DatePeriod){}[0] +} + +final object kotlinx.datetime.serializers/DatePeriodIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DatePeriodIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DatePeriodIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DatePeriodIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DatePeriod // kotlinx.datetime.serializers/DatePeriodIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DatePeriod) // kotlinx.datetime.serializers/DatePeriodIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DatePeriod){}[0] +} + +final object kotlinx.datetime.serializers/DateTimePeriodComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DateTimePeriodComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DateTimePeriodComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DateTimePeriodComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DateTimePeriod // kotlinx.datetime.serializers/DateTimePeriodComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimePeriod) // kotlinx.datetime.serializers/DateTimePeriodComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimePeriod){}[0] +} + +final object kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DateTimePeriod // kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimePeriod) // kotlinx.datetime.serializers/DateTimePeriodIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimePeriod){}[0] +} + +final object kotlinx.datetime.serializers/DateTimeUnitSerializer : kotlinx.serialization.internal/AbstractPolymorphicSerializer { // kotlinx.datetime.serializers/DateTimeUnitSerializer|null[0] + final val baseClass // kotlinx.datetime.serializers/DateTimeUnitSerializer.baseClass|{}baseClass[0] + final fun (): kotlin.reflect/KClass // kotlinx.datetime.serializers/DateTimeUnitSerializer.baseClass.|(){}[0] + final val descriptor // kotlinx.datetime.serializers/DateTimeUnitSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DateTimeUnitSerializer.descriptor.|(){}[0] + + final fun findPolymorphicSerializerOrNull(kotlinx.serialization.encoding/CompositeDecoder, kotlin/String?): kotlinx.serialization/DeserializationStrategy? // kotlinx.datetime.serializers/DateTimeUnitSerializer.findPolymorphicSerializerOrNull|findPolymorphicSerializerOrNull(kotlinx.serialization.encoding.CompositeDecoder;kotlin.String?){}[0] + final fun findPolymorphicSerializerOrNull(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimeUnit): kotlinx.serialization/SerializationStrategy? // kotlinx.datetime.serializers/DateTimeUnitSerializer.findPolymorphicSerializerOrNull|findPolymorphicSerializerOrNull(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimeUnit){}[0] +} + +final object kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DateTimeUnit.DayBased // kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimeUnit.DayBased) // kotlinx.datetime.serializers/DayBasedDateTimeUnitSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimeUnit.DayBased){}[0] +} + +final object kotlinx.datetime.serializers/DayOfWeekSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/DayOfWeekSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/DayOfWeekSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/DayOfWeekSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DayOfWeek // kotlinx.datetime.serializers/DayOfWeekSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DayOfWeek) // kotlinx.datetime.serializers/DayOfWeekSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DayOfWeek){}[0] +} + +final object kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/FixedOffsetTimeZone // kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/FixedOffsetTimeZone) // kotlinx.datetime.serializers/FixedOffsetTimeZoneSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.FixedOffsetTimeZone){}[0] +} + +final object kotlinx.datetime.serializers/InstantComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/InstantComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/InstantComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/InstantComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/Instant // kotlinx.datetime.serializers/InstantComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/Instant) // kotlinx.datetime.serializers/InstantComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.Instant){}[0] +} + +final object kotlinx.datetime.serializers/InstantIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/InstantIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/InstantIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/InstantIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/Instant // kotlinx.datetime.serializers/InstantIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/Instant) // kotlinx.datetime.serializers/InstantIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.Instant){}[0] +} + +final object kotlinx.datetime.serializers/LocalDateComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalDateComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalDateComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalDateComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalDate // kotlinx.datetime.serializers/LocalDateComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalDate) // kotlinx.datetime.serializers/LocalDateComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalDate){}[0] +} + +final object kotlinx.datetime.serializers/LocalDateIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalDateIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalDateIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalDateIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalDate // kotlinx.datetime.serializers/LocalDateIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalDate) // kotlinx.datetime.serializers/LocalDateIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalDate){}[0] +} + +final object kotlinx.datetime.serializers/LocalDateTimeComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalDateTimeComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalDateTimeComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalDateTimeComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalDateTime // kotlinx.datetime.serializers/LocalDateTimeComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalDateTime) // kotlinx.datetime.serializers/LocalDateTimeComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalDateTime){}[0] +} + +final object kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalDateTime // kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalDateTime) // kotlinx.datetime.serializers/LocalDateTimeIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalDateTime){}[0] +} + +final object kotlinx.datetime.serializers/LocalTimeComponentSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalTimeComponentSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalTimeComponentSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalTimeComponentSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalTime // kotlinx.datetime.serializers/LocalTimeComponentSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalTime) // kotlinx.datetime.serializers/LocalTimeComponentSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalTime){}[0] +} + +final object kotlinx.datetime.serializers/LocalTimeIso8601Serializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/LocalTimeIso8601Serializer|null[0] + final val descriptor // kotlinx.datetime.serializers/LocalTimeIso8601Serializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/LocalTimeIso8601Serializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/LocalTime // kotlinx.datetime.serializers/LocalTimeIso8601Serializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/LocalTime) // kotlinx.datetime.serializers/LocalTimeIso8601Serializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.LocalTime){}[0] +} + +final object kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DateTimeUnit.MonthBased // kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimeUnit.MonthBased) // kotlinx.datetime.serializers/MonthBasedDateTimeUnitSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimeUnit.MonthBased){}[0] +} + +final object kotlinx.datetime.serializers/MonthSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/MonthSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/MonthSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/MonthSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/Month // kotlinx.datetime.serializers/MonthSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/Month) // kotlinx.datetime.serializers/MonthSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.Month){}[0] +} + +final object kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/DateTimeUnit.TimeBased // kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/DateTimeUnit.TimeBased) // kotlinx.datetime.serializers/TimeBasedDateTimeUnitSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +} + +final object kotlinx.datetime.serializers/TimeZoneSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/TimeZoneSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/TimeZoneSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/TimeZoneSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/TimeZone // kotlinx.datetime.serializers/TimeZoneSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/TimeZone) // kotlinx.datetime.serializers/TimeZoneSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.TimeZone){}[0] +} + +final object kotlinx.datetime.serializers/UtcOffsetSerializer : kotlinx.serialization/KSerializer { // kotlinx.datetime.serializers/UtcOffsetSerializer|null[0] + final val descriptor // kotlinx.datetime.serializers/UtcOffsetSerializer.descriptor|{}descriptor[0] + final fun (): kotlinx.serialization.descriptors/SerialDescriptor // kotlinx.datetime.serializers/UtcOffsetSerializer.descriptor.|(){}[0] + + final fun deserialize(kotlinx.serialization.encoding/Decoder): kotlinx.datetime/UtcOffset // kotlinx.datetime.serializers/UtcOffsetSerializer.deserialize|deserialize(kotlinx.serialization.encoding.Decoder){}[0] + final fun serialize(kotlinx.serialization.encoding/Encoder, kotlinx.datetime/UtcOffset) // kotlinx.datetime.serializers/UtcOffsetSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;kotlinx.datetime.UtcOffset){}[0] +} + +final val kotlinx.datetime/isDistantFuture // kotlinx.datetime/isDistantFuture|@kotlinx.datetime.Instant{}isDistantFuture[0] + final fun (kotlinx.datetime/Instant).(): kotlin/Boolean // kotlinx.datetime/isDistantFuture.|@kotlinx.datetime.Instant(){}[0] +final val kotlinx.datetime/isDistantPast // kotlinx.datetime/isDistantPast|@kotlinx.datetime.Instant{}isDistantPast[0] + final fun (kotlinx.datetime/Instant).(): kotlin/Boolean // kotlinx.datetime/isDistantPast.|@kotlinx.datetime.Instant(){}[0] +final val kotlinx.datetime/isoDayNumber // kotlinx.datetime/isoDayNumber|@kotlinx.datetime.DayOfWeek{}isoDayNumber[0] + final fun (kotlinx.datetime/DayOfWeek).(): kotlin/Int // kotlinx.datetime/isoDayNumber.|@kotlinx.datetime.DayOfWeek(){}[0] +final val kotlinx.datetime/number // kotlinx.datetime/number|@kotlinx.datetime.Month{}number[0] + final fun (kotlinx.datetime/Month).(): kotlin/Int // kotlinx.datetime/number.|@kotlinx.datetime.Month(){}[0] + +final fun (kotlin.time/Duration).kotlinx.datetime/toDateTimePeriod(): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/toDateTimePeriod|toDateTimePeriod@kotlin.time.Duration(){}[0] +final fun (kotlin.time/TimeSource).kotlinx.datetime/asClock(kotlinx.time/Instant): kotlinx.time/Clock // kotlinx.datetime/asClock|asClock@kotlin.time.TimeSource(kotlinx.time.Instant){}[0] +final fun (kotlin/String).kotlinx.datetime/toDatePeriod(): kotlinx.datetime/DatePeriod // kotlinx.datetime/toDatePeriod|toDatePeriod@kotlin.String(){}[0] +final fun (kotlin/String).kotlinx.datetime/toDateTimePeriod(): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/toDateTimePeriod|toDateTimePeriod@kotlin.String(){}[0] +final fun (kotlin/String).kotlinx.datetime/toInstant(): kotlinx.datetime/Instant // kotlinx.datetime/toInstant|toInstant@kotlin.String(){}[0] +final fun (kotlin/String).kotlinx.datetime/toLocalDate(): kotlinx.datetime/LocalDate // kotlinx.datetime/toLocalDate|toLocalDate@kotlin.String(){}[0] +final fun (kotlin/String).kotlinx.datetime/toLocalDateTime(): kotlinx.datetime/LocalDateTime // kotlinx.datetime/toLocalDateTime|toLocalDateTime@kotlin.String(){}[0] +final fun (kotlin/String).kotlinx.datetime/toLocalTime(): kotlinx.datetime/LocalTime // kotlinx.datetime/toLocalTime|toLocalTime@kotlin.String(){}[0] +final fun (kotlinx.datetime.format/DateTimeComponents.Companion).kotlinx.datetime.format/parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat): kotlinx.datetime.format/DateTimeComponents // kotlinx.datetime.format/parse|parse@kotlinx.datetime.format.DateTimeComponents.Companion(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] +final fun (kotlinx.datetime.format/DateTimeFormat).kotlinx.datetime.format/format(kotlin/Function1): kotlin/String // kotlinx.datetime.format/format|format@kotlinx.datetime.format.DateTimeFormat(kotlin.Function1){}[0] +final fun (kotlinx.datetime.format/DateTimeFormatBuilder).kotlinx.datetime.format/byUnicodePattern(kotlin/String) // kotlinx.datetime.format/byUnicodePattern|byUnicodePattern@kotlinx.datetime.format.DateTimeFormatBuilder(kotlin.String){}[0] +final fun (kotlinx.datetime.format/DateTimeFormatBuilder).kotlinx.datetime.format/char(kotlin/Char) // kotlinx.datetime.format/char|char@kotlinx.datetime.format.DateTimeFormatBuilder(kotlin.Char){}[0] +final fun (kotlinx.datetime/Clock).kotlinx.datetime/asTimeSource(): kotlin.time/TimeSource.WithComparableMarks // kotlinx.datetime/asTimeSource|asTimeSource@kotlinx.datetime.Clock(){}[0] +final fun (kotlinx.datetime/Clock).kotlinx.datetime/todayAt(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDate // kotlinx.datetime/todayAt|todayAt@kotlinx.datetime.Clock(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Clock).kotlinx.datetime/todayIn(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDate // kotlinx.datetime/todayIn|todayIn@kotlinx.datetime.Clock(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/DatePeriod).kotlinx.datetime/plus(kotlinx.datetime/DatePeriod): kotlinx.datetime/DatePeriod // kotlinx.datetime/plus|plus@kotlinx.datetime.DatePeriod(kotlinx.datetime.DatePeriod){}[0] +final fun (kotlinx.datetime/DateTimePeriod).kotlinx.datetime/plus(kotlinx.datetime/DateTimePeriod): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/plus|plus@kotlinx.datetime.DateTimePeriod(kotlinx.datetime.DateTimePeriod){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/daysUntil(kotlinx.datetime/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/daysUntil|daysUntil@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat, kotlinx.datetime/UtcOffset =...): kotlin/String // kotlinx.datetime/format|format@kotlinx.datetime.Instant(kotlinx.datetime.format.DateTimeFormat;kotlinx.datetime.UtcOffset){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlin/Int, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlin/Int, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlin/Long, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlin/Long, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimePeriod, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimePeriod;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/Instant, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlin/Long // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/Instant, kotlinx.datetime/DateTimeUnit.TimeBased): kotlin/Long // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/minus(kotlinx.datetime/Instant, kotlinx.datetime/TimeZone): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/minus|minus@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/monthsUntil(kotlinx.datetime/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/monthsUntil|monthsUntil@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/offsetIn(kotlinx.datetime/TimeZone): kotlinx.datetime/UtcOffset // kotlinx.datetime/offsetIn|offsetIn@kotlinx.datetime.Instant(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/periodUntil(kotlinx.datetime/Instant, kotlinx.datetime/TimeZone): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/periodUntil|periodUntil@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlin/Int, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlin/Int, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlin/Long, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlin/Long, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimePeriod, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimePeriod;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.datetime/Instant // kotlinx.datetime/plus|plus@kotlinx.datetime.Instant(kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/toLocalDateTime(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDateTime // kotlinx.datetime/toLocalDateTime|toLocalDateTime@kotlinx.datetime.Instant(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/toLocalDateTime(kotlinx.datetime/UtcOffset): kotlinx.datetime/LocalDateTime // kotlinx.datetime/toLocalDateTime|toLocalDateTime@kotlinx.datetime.Instant(kotlinx.datetime.UtcOffset){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/toNewInstant(): kotlinx.time/Instant // kotlinx.datetime/toNewInstant|toNewInstant@kotlinx.datetime.Instant(){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/until(kotlinx.datetime/Instant, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlin/Long // kotlinx.datetime/until|until@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/until(kotlinx.datetime/Instant, kotlinx.datetime/DateTimeUnit.TimeBased): kotlin/Long // kotlinx.datetime/until|until@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/yearsUntil(kotlinx.datetime/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/yearsUntil|yearsUntil@kotlinx.datetime.Instant(kotlinx.datetime.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/atStartOfDayIn(kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/atStartOfDayIn|atStartOfDayIn@kotlinx.datetime.LocalDate(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/atStartOfDayIn(kotlinx.datetime/TimeZone, kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime/atStartOfDayIn|atStartOfDayIn@kotlinx.datetime.LocalDate(kotlinx.datetime.TimeZone;kotlinx.datetime.DeprecationMarker){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/atTime(kotlin/Int, kotlin/Int, kotlin/Int =..., kotlin/Int =...): kotlinx.datetime/LocalDateTime // kotlinx.datetime/atTime|atTime@kotlinx.datetime.LocalDate(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/atTime(kotlinx.datetime/LocalTime): kotlinx.datetime/LocalDateTime // kotlinx.datetime/atTime|atTime@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalTime){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/daysUntil(kotlinx.datetime/LocalDate): kotlin/Int // kotlinx.datetime/daysUntil|daysUntil@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat): kotlin/String // kotlinx.datetime/format|format@kotlinx.datetime.LocalDate(kotlinx.datetime.format.DateTimeFormat){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/minus(kotlin/Int, kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/minus|minus@kotlinx.datetime.LocalDate(kotlin.Int;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/minus(kotlin/Long, kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/minus|minus@kotlinx.datetime.LocalDate(kotlin.Long;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/minus(kotlinx.datetime/DatePeriod): kotlinx.datetime/LocalDate // kotlinx.datetime/minus|minus@kotlinx.datetime.LocalDate(kotlinx.datetime.DatePeriod){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/minus(kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/minus|minus@kotlinx.datetime.LocalDate(kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/minus(kotlinx.datetime/LocalDate): kotlinx.datetime/DatePeriod // kotlinx.datetime/minus|minus@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/monthsUntil(kotlinx.datetime/LocalDate): kotlin/Int // kotlinx.datetime/monthsUntil|monthsUntil@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/periodUntil(kotlinx.datetime/LocalDate): kotlinx.datetime/DatePeriod // kotlinx.datetime/periodUntil|periodUntil@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/plus(kotlin/Int, kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/plus|plus@kotlinx.datetime.LocalDate(kotlin.Int;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/plus(kotlin/Long, kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/plus|plus@kotlinx.datetime.LocalDate(kotlin.Long;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/plus(kotlinx.datetime/DatePeriod): kotlinx.datetime/LocalDate // kotlinx.datetime/plus|plus@kotlinx.datetime.LocalDate(kotlinx.datetime.DatePeriod){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/plus(kotlinx.datetime/DateTimeUnit.DateBased): kotlinx.datetime/LocalDate // kotlinx.datetime/plus|plus@kotlinx.datetime.LocalDate(kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/until(kotlinx.datetime/LocalDate, kotlinx.datetime/DateTimeUnit.DateBased): kotlin/Long // kotlinx.datetime/until|until@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate;kotlinx.datetime.DateTimeUnit.DateBased){}[0] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/yearsUntil(kotlinx.datetime/LocalDate): kotlin/Int // kotlinx.datetime/yearsUntil|yearsUntil@kotlinx.datetime.LocalDate(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat): kotlin/String // kotlinx.datetime/format|format@kotlinx.datetime.LocalDateTime(kotlinx.datetime.format.DateTimeFormat){}[0] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/toInstant(kotlinx.datetime/TimeZone): kotlinx.datetime/Instant // kotlinx.datetime/toInstant|toInstant@kotlinx.datetime.LocalDateTime(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/toInstant(kotlinx.datetime/TimeZone, kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime/toInstant|toInstant@kotlinx.datetime.LocalDateTime(kotlinx.datetime.TimeZone;kotlinx.datetime.DeprecationMarker){}[0] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/toInstant(kotlinx.datetime/UtcOffset): kotlinx.datetime/Instant // kotlinx.datetime/toInstant|toInstant@kotlinx.datetime.LocalDateTime(kotlinx.datetime.UtcOffset){}[0] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/toInstant(kotlinx.datetime/UtcOffset, kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime/toInstant|toInstant@kotlinx.datetime.LocalDateTime(kotlinx.datetime.UtcOffset;kotlinx.datetime.DeprecationMarker){}[0] +final fun (kotlinx.datetime/LocalTime).kotlinx.datetime/atDate(kotlin/Int, kotlin/Int, kotlin/Int =...): kotlinx.datetime/LocalDateTime // kotlinx.datetime/atDate|atDate@kotlinx.datetime.LocalTime(kotlin.Int;kotlin.Int;kotlin.Int){}[0] +final fun (kotlinx.datetime/LocalTime).kotlinx.datetime/atDate(kotlin/Int, kotlinx.datetime/Month, kotlin/Int =...): kotlinx.datetime/LocalDateTime // kotlinx.datetime/atDate|atDate@kotlinx.datetime.LocalTime(kotlin.Int;kotlinx.datetime.Month;kotlin.Int){}[0] +final fun (kotlinx.datetime/LocalTime).kotlinx.datetime/atDate(kotlinx.datetime/LocalDate): kotlinx.datetime/LocalDateTime // kotlinx.datetime/atDate|atDate@kotlinx.datetime.LocalTime(kotlinx.datetime.LocalDate){}[0] +final fun (kotlinx.datetime/LocalTime).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat): kotlin/String // kotlinx.datetime/format|format@kotlinx.datetime.LocalTime(kotlinx.datetime.format.DateTimeFormat){}[0] +final fun (kotlinx.datetime/TimeZone).kotlinx.datetime/offsetAt(kotlinx.datetime/Instant): kotlinx.datetime/UtcOffset // kotlinx.datetime/offsetAt|offsetAt@kotlinx.datetime.TimeZone(kotlinx.datetime.Instant){}[0] +final fun (kotlinx.datetime/TimeZone).kotlinx.datetime/offsetAt(kotlinx.time/Instant): kotlinx.datetime/UtcOffset // kotlinx.datetime/offsetAt|offsetAt@kotlinx.datetime.TimeZone(kotlinx.time.Instant){}[0] +final fun (kotlinx.datetime/UtcOffset).kotlinx.datetime/asTimeZone(): kotlinx.datetime/FixedOffsetTimeZone // kotlinx.datetime/asTimeZone|asTimeZone@kotlinx.datetime.UtcOffset(){}[0] +final fun (kotlinx.datetime/UtcOffset).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat): kotlin/String // kotlinx.datetime/format|format@kotlinx.datetime.UtcOffset(kotlinx.datetime.format.DateTimeFormat){}[0] +final fun (kotlinx.time/Clock).kotlinx.datetime/asTimeSource(): kotlin.time/TimeSource.WithComparableMarks // kotlinx.datetime/asTimeSource|asTimeSource@kotlinx.time.Clock(){}[0] +final fun (kotlinx.time/Clock).kotlinx.datetime/todayAt(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDate // kotlinx.datetime/todayAt|todayAt@kotlinx.time.Clock(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Clock).kotlinx.datetime/todayIn(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDate // kotlinx.datetime/todayIn|todayIn@kotlinx.time.Clock(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/daysUntil(kotlinx.time/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/daysUntil|daysUntil@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/format(kotlinx.datetime.format/DateTimeFormat, kotlinx.datetime/UtcOffset =...): kotlin/String // kotlinx.datetime/format|format@kotlinx.time.Instant(kotlinx.datetime.format.DateTimeFormat;kotlinx.datetime.UtcOffset){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlin/Int, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlin/Int, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlin/Long, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlin/Long, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimePeriod, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.datetime.DateTimePeriod;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.time/Instant, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlin/Long // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.time/Instant, kotlinx.datetime/DateTimeUnit.TimeBased): kotlin/Long // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/minus(kotlinx.time/Instant, kotlinx.datetime/TimeZone): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/minus|minus@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/monthsUntil(kotlinx.time/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/monthsUntil|monthsUntil@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/offsetIn(kotlinx.datetime/TimeZone): kotlinx.datetime/UtcOffset // kotlinx.datetime/offsetIn|offsetIn@kotlinx.time.Instant(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/periodUntil(kotlinx.time/Instant, kotlinx.datetime/TimeZone): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/periodUntil|periodUntil@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlin/Int, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlin/Int, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlin.Int;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlin/Long, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlin/Long, kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlin.Long;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimePeriod, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlinx.datetime.DateTimePeriod;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/plus(kotlinx.datetime/DateTimeUnit.TimeBased): kotlinx.time/Instant // kotlinx.datetime/plus|plus@kotlinx.time.Instant(kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/toDeprecatedInstant(): kotlinx.datetime/Instant // kotlinx.datetime/toDeprecatedInstant|toDeprecatedInstant@kotlinx.time.Instant(){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/toLocalDateTime(kotlinx.datetime/TimeZone): kotlinx.datetime/LocalDateTime // kotlinx.datetime/toLocalDateTime|toLocalDateTime@kotlinx.time.Instant(kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/until(kotlinx.time/Instant, kotlinx.datetime/DateTimeUnit, kotlinx.datetime/TimeZone): kotlin/Long // kotlinx.datetime/until|until@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.DateTimeUnit;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/until(kotlinx.time/Instant, kotlinx.datetime/DateTimeUnit.TimeBased): kotlin/Long // kotlinx.datetime/until|until@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.DateTimeUnit.TimeBased){}[0] +final fun (kotlinx.time/Instant).kotlinx.datetime/yearsUntil(kotlinx.time/Instant, kotlinx.datetime/TimeZone): kotlin/Int // kotlinx.datetime/yearsUntil|yearsUntil@kotlinx.time.Instant(kotlinx.time.Instant;kotlinx.datetime.TimeZone){}[0] +final fun (kotlinx.time/Instant.Companion).kotlinx.datetime/parse(kotlin/CharSequence, kotlinx.datetime.format/DateTimeFormat): kotlinx.time/Instant // kotlinx.datetime/parse|parse@kotlinx.time.Instant.Companion(kotlin.CharSequence;kotlinx.datetime.format.DateTimeFormat){}[0] +final fun <#A: kotlinx.datetime.format/DateTimeFormatBuilder> (#A).kotlinx.datetime.format/alternativeParsing(kotlin/Array>..., kotlin/Function1<#A, kotlin/Unit>) // kotlinx.datetime.format/alternativeParsing|alternativeParsing@0:0(kotlin.Array>...;kotlin.Function1<0:0,kotlin.Unit>){0§}[0] +final fun <#A: kotlinx.datetime.format/DateTimeFormatBuilder> (#A).kotlinx.datetime.format/optional(kotlin/String =..., kotlin/Function1<#A, kotlin/Unit>) // kotlinx.datetime.format/optional|optional@0:0(kotlin.String;kotlin.Function1<0:0,kotlin.Unit>){0§}[0] +final fun kotlinx.datetime/DateTimePeriod(kotlin/Int =..., kotlin/Int =..., kotlin/Int =..., kotlin/Int =..., kotlin/Int =..., kotlin/Int =..., kotlin/Long =...): kotlinx.datetime/DateTimePeriod // kotlinx.datetime/DateTimePeriod|DateTimePeriod(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Long){}[0] +final fun kotlinx.datetime/DayOfWeek(kotlin/Int): kotlinx.datetime/DayOfWeek // kotlinx.datetime/DayOfWeek|DayOfWeek(kotlin.Int){}[0] +final fun kotlinx.datetime/Month(kotlin/Int): kotlinx.datetime/Month // kotlinx.datetime/Month|Month(kotlin.Int){}[0] +final fun kotlinx.datetime/UtcOffset(): kotlinx.datetime/UtcOffset // kotlinx.datetime/UtcOffset|UtcOffset(){}[0] +final fun kotlinx.datetime/UtcOffset(kotlin/Int? =..., kotlin/Int? =..., kotlin/Int? =...): kotlinx.datetime/UtcOffset // kotlinx.datetime/UtcOffset|UtcOffset(kotlin.Int?;kotlin.Int?;kotlin.Int?){}[0] + +// Targets: [apple] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/toNSDate(): platform.Foundation/NSDate // kotlinx.datetime/toNSDate|toNSDate@kotlinx.datetime.Instant(){}[0] + +// Targets: [apple] +final fun (kotlinx.datetime/LocalDate).kotlinx.datetime/toNSDateComponents(): platform.Foundation/NSDateComponents // kotlinx.datetime/toNSDateComponents|toNSDateComponents@kotlinx.datetime.LocalDate(){}[0] + +// Targets: [apple] +final fun (kotlinx.datetime/LocalDateTime).kotlinx.datetime/toNSDateComponents(): platform.Foundation/NSDateComponents // kotlinx.datetime/toNSDateComponents|toNSDateComponents@kotlinx.datetime.LocalDateTime(){}[0] + +// Targets: [apple] +final fun (kotlinx.datetime/TimeZone).kotlinx.datetime/toNSTimeZone(): platform.Foundation/NSTimeZone // kotlinx.datetime/toNSTimeZone|toNSTimeZone@kotlinx.datetime.TimeZone(){}[0] + +// Targets: [apple] +final fun (kotlinx.time/Instant).kotlinx.datetime/toNSDate(): platform.Foundation/NSDate // kotlinx.datetime/toNSDate|toNSDate@kotlinx.time.Instant(){}[0] + +// Targets: [apple] +final fun (platform.Foundation/NSDate).kotlinx.datetime/toKotlinInstant(): kotlinx.datetime/Instant // kotlinx.datetime/toKotlinInstant|toKotlinInstant@platform.Foundation.NSDate(){}[0] + +// Targets: [apple] +final fun (platform.Foundation/NSDate).kotlinx.datetime/toKotlinInstant(kotlinx.datetime/DeprecationMarker =...): kotlinx.time/Instant // kotlinx.datetime/toKotlinInstant|toKotlinInstant@platform.Foundation.NSDate(kotlinx.datetime.DeprecationMarker){}[0] + +// Targets: [apple] +final fun (platform.Foundation/NSTimeZone).kotlinx.datetime/toKotlinTimeZone(): kotlinx.datetime/TimeZone // kotlinx.datetime/toKotlinTimeZone|toKotlinTimeZone@platform.Foundation.NSTimeZone(){}[0] + +// Targets: [js] +abstract interface kotlinx.datetime.internal/InteropInterface // kotlinx.datetime.internal/InteropInterface|null[0] + +// Targets: [js] +final fun (kotlin.js/Date).kotlinx.datetime/toKotlinInstant(): kotlinx.datetime/Instant // kotlinx.datetime/toKotlinInstant|toKotlinInstant@kotlin.js.Date(){}[0] + +// Targets: [js] +final fun (kotlinx.datetime/Instant).kotlinx.datetime/toJSDate(): kotlin.js/Date // kotlinx.datetime/toJSDate|toJSDate@kotlinx.datetime.Instant(){}[0] + +// Targets: [wasmJs] +open annotation class kotlinx.datetime.internal/JsNonModule : kotlin/Annotation { // kotlinx.datetime.internal/JsNonModule|null[1] + constructor () // kotlinx.datetime.internal/JsNonModule.|(){}[1] +} + +// Targets: [wasmWasi] +abstract interface kotlinx.datetime.internal/TimeZonesProvider { // kotlinx.datetime.internal/TimeZonesProvider|null[0] + abstract fun getTimeZones(): kotlin.collections/Set // kotlinx.datetime.internal/TimeZonesProvider.getTimeZones|getTimeZones(){}[0] + abstract fun zoneDataByName(kotlin/String): kotlin/ByteArray // kotlinx.datetime.internal/TimeZonesProvider.zoneDataByName|zoneDataByName(kotlin.String){}[0] +} + +// Targets: [wasmWasi] +final fun kotlinx.datetime.internal/initializeTimeZonesProvider(kotlinx.datetime.internal/TimeZonesProvider) // kotlinx.datetime.internal/initializeTimeZonesProvider|initializeTimeZonesProvider(kotlinx.datetime.internal.TimeZonesProvider){}[0] diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 063221406..590cfcb4a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -165,6 +165,7 @@ kotlin { commonMain { dependencies { compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") + api(project(":fake-kotlinx-time")) } } diff --git a/core/common/src/Clock.kt b/core/common/src/Clock.kt index 8e7eb10b3..587ee60da 100644 --- a/core/common/src/Clock.kt +++ b/core/common/src/Clock.kt @@ -3,62 +3,17 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:JvmMultifileClass +@file:JvmName("ClockKt") package kotlinx.datetime import kotlin.time.* - -/** - * A source of [Instant] values. - * - * See [Clock.System][Clock.System] for the clock instance that queries the operating system. - * - * It is not recommended to use [Clock.System] directly in the implementation. Instead, you can pass a - * [Clock] explicitly to the necessary functions or classes. - * This way, tests can be written deterministically by providing custom [Clock] implementations - * to the system under test. - */ -public interface Clock { - /** - * Returns the [Instant] corresponding to the current time, according to this clock. - * - * Calling [now] later is not guaranteed to return a larger [Instant]. - * In particular, for [Clock.System], the opposite is completely expected, - * and it must be taken into account. - * See the [System] documentation for details. - * - * Even though [Instant] is defined to be on the UTC-SLS time scale, which enforces a specific way of handling - * leap seconds, [now] is not guaranteed to handle leap seconds in any specific way. - */ - public fun now(): Instant - - /** - * The [Clock] instance that queries the platform-specific system clock as its source of time knowledge. - * - * Successive calls to [now] will not necessarily return increasing [Instant] values, and when they do, - * these increases will not necessarily correspond to the elapsed time. - * - * For example, when using [Clock.System], the following could happen: - * - [now] returns `2023-01-02T22:35:01Z`. - * - The system queries the Internet and recognizes that its clock needs adjusting. - * - [now] returns `2023-01-02T22:32:05Z`. - * - * When you need predictable intervals between successive measurements, consider using [TimeSource.Monotonic]. - * - * For improved testability, you should avoid using [Clock.System] directly in the implementation - * and pass a [Clock] explicitly instead. For example: - * - * @sample kotlinx.datetime.test.samples.ClockSamples.system - * @sample kotlinx.datetime.test.samples.ClockSamples.dependencyInjection - */ - public object System : Clock { - override fun now(): Instant = @Suppress("DEPRECATION_ERROR") Instant.now() - } - - /** A companion object used purely for namespacing. */ - public companion object { - - } -} +import kotlinx.time.Clock +import kotlinx.time.Instant +import kotlinx.time.isDistantFuture +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.time.Duration.Companion.seconds /** * Returns the current date at the given [time zone][timeZone], according to [this Clock][this]. @@ -108,7 +63,7 @@ private class InstantTimeMark(private val instant: Instant, private val clock: C override fun toString(): String = "InstantTimeMark($instant, $clock)" - private fun Instant.isSaturated() = this == Instant.MAX || this == Instant.MIN + private fun Instant.isSaturated() = this.plus(1.seconds) == this || this.plus((-1).seconds) == this private fun Instant.saturatingAdd(duration: Duration): Instant { if (isSaturated()) { if (duration.isInfinite() && duration.isPositive() != this.isDistantFuture) { diff --git a/core/common/src/DeprecatedClock.kt b/core/common/src/DeprecatedClock.kt new file mode 100644 index 000000000..6b8029dee --- /dev/null +++ b/core/common/src/DeprecatedClock.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +@file:JvmMultifileClass +@file:JvmName("ClockKt") +package kotlinx.datetime + +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.time.ComparableTimeMark +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.ExperimentalTime +import kotlin.time.TimeSource + +/** + * A source of [Instant] values. + * + * See [Clock.System][Clock.System] for the clock instance that queries the operating system. + * + * It is not recommended to use [Clock.System] directly in the implementation. Instead, you can pass a + * [Clock] explicitly to the necessary functions or classes. + * This way, tests can be written deterministically by providing custom [Clock] implementations + * to the system under test. + */ +@Deprecated( + "Use kotlin.time.Clock instead", + ReplaceWith("kotlinx.time.Clock", "kotlinx.time.Clock"), + level = DeprecationLevel.ERROR +) +public interface Clock { + /** + * Returns the [Instant] corresponding to the current time, according to this clock. + * + * Calling [now] later is not guaranteed to return a larger [Instant]. + * In particular, for [Clock.System], the opposite is completely expected, + * and it must be taken into account. + * See the [System] documentation for details. + * + * Even though [Instant] is defined to be on the UTC-SLS time scale, which enforces a specific way of handling + * leap seconds, [now] is not guaranteed to handle leap seconds in any specific way. + */ + public fun now(): Instant + + /** + * The [Clock] instance that queries the platform-specific system clock as its source of time knowledge. + * + * Successive calls to [now] will not necessarily return increasing [Instant] values, and when they do, + * these increases will not necessarily correspond to the elapsed time. + * + * For example, when using [Clock.System], the following could happen: + * - [now] returns `2023-01-02T22:35:01Z`. + * - The system queries the Internet and recognizes that its clock needs adjusting. + * - [now] returns `2023-01-02T22:32:05Z`. + * + * When you need predictable intervals between successive measurements, consider using [TimeSource.Monotonic]. + * + * For improved testability, you should avoid using [Clock.System] directly in the implementation + * and pass a [Clock] explicitly instead. For example: + * + * @sample kotlinx.datetime.test.samples.ClockSamples.system + * @sample kotlinx.datetime.test.samples.ClockSamples.dependencyInjection + */ + public object System : Clock { + override fun now(): Instant = kotlinx.time.Clock.System.now().toDeprecatedInstant() + } + + /** A companion object used purely for namespacing. */ + public companion object { + + } +} + +/** + * Returns the current date at the given [time zone][timeZone], according to [this Clock][this]. + * + * The time zone is important because the current date is not the same in all time zones at the same instant. + * + * @sample kotlinx.datetime.test.samples.ClockSamples.todayIn + */ +public fun Clock.todayIn(timeZone: TimeZone): LocalDate = + now().toNewInstant().toLocalDateTime(timeZone).date + +/** + * Returns a [TimeSource] that uses this [Clock] to mark a time instant and to find the amount of time elapsed since that mark. + * + * **Pitfall**: using this function with [Clock.System] is error-prone + * because [Clock.System] is not well suited for measuring time intervals. + * Please only use this conversion function on the [Clock] instances that are fully controlled programmatically. + */ +@ExperimentalTime +public fun Clock.asTimeSource(): TimeSource.WithComparableMarks = object : TimeSource.WithComparableMarks { + override fun markNow(): ComparableTimeMark = DeprecatedInstantTimeMark(now(), this@asTimeSource) +} + +@ExperimentalTime +private class DeprecatedInstantTimeMark(private val instant: Instant, private val clock: Clock) : ComparableTimeMark { + override fun elapsedNow(): Duration = saturatingDiff(clock.now(), instant) + + override fun plus(duration: Duration): ComparableTimeMark = + DeprecatedInstantTimeMark(instant.saturatingAdd(duration), clock) + override fun minus(duration: Duration): ComparableTimeMark = + DeprecatedInstantTimeMark(instant.saturatingAdd(-duration), clock) + + override fun minus(other: ComparableTimeMark): Duration { + if (other !is DeprecatedInstantTimeMark || other.clock != this.clock) { + throw IllegalArgumentException("Subtracting or comparing time marks from different time sources is not possible: $this and $other") + } + return saturatingDiff(this.instant, other.instant) + } + + override fun equals(other: Any?): Boolean { + return other is DeprecatedInstantTimeMark && this.clock == other.clock && this.instant == other.instant + } + + override fun hashCode(): Int = instant.hashCode() + + override fun toString(): String = "InstantTimeMark($instant, $clock)" + + private fun Instant.isSaturated() = this.plus(1.seconds) == this || this.plus((-1).seconds) == this + private fun Instant.saturatingAdd(duration: Duration): Instant { + if (isSaturated()) { + if (duration.isInfinite() && duration.isPositive() != this.isDistantFuture) { + throw IllegalArgumentException("Summing infinities of different signs") + } + return this + } + return this + duration + } + private fun saturatingDiff(instant1: Instant, instant2: Instant): Duration = when { + instant1 == instant2 -> + Duration.ZERO + instant1.isSaturated() || instant2.isSaturated() -> + (instant1 - instant2) * Double.POSITIVE_INFINITY + else -> + instant1 - instant2 + } +} + +@Deprecated("Use Clock.todayIn instead", ReplaceWith("this.todayIn(timeZone)"), DeprecationLevel.WARNING) +public fun Clock.todayAt(timeZone: TimeZone): LocalDate = todayIn(timeZone) diff --git a/core/common/src/DeprecatedInstant.kt b/core/common/src/DeprecatedInstant.kt new file mode 100644 index 000000000..f4d6cedd4 --- /dev/null +++ b/core/common/src/DeprecatedInstant.kt @@ -0,0 +1,645 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +@file:JvmMultifileClass +@file:JvmName("InstantKt") +package kotlinx.datetime + +import kotlinx.datetime.format.DateTimeComponents +import kotlinx.datetime.format.DateTimeFormat +import kotlinx.datetime.format.format +import kotlinx.datetime.format.parse +import kotlinx.datetime.internal.NANOS_PER_ONE +import kotlinx.datetime.internal.clampToInt +import kotlinx.datetime.internal.multiplyAddAndDivide +import kotlinx.datetime.serializers.InstantIso8601Serializer +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.time.Duration +import kotlin.time.Duration.Companion.days +import kotlin.time.TimeSource + +public fun Instant.toNewInstant(): kotlinx.time.Instant = + kotlinx.time.Instant.fromEpochSeconds(epochSeconds, nanosecondsOfSecond) + +public fun kotlinx.time.Instant.toDeprecatedInstant(): Instant = + Instant.fromEpochSeconds(epochSeconds, nanosecondsOfSecond) + +@Deprecated( + "Use kotlin.time.Instant instead", + ReplaceWith("kotlinx.time.Instant", "kotlinx.time.Instant"), + level = DeprecationLevel.ERROR +) +@Serializable(with = InstantIso8601Serializer::class) +public expect class Instant : Comparable { + + /** + * The number of seconds from the epoch instant `1970-01-01T00:00:00Z` rounded down to a [Long] number. + * + * The difference between the rounded number of seconds and the actual number of seconds + * is returned by [nanosecondsOfSecond] property expressed in nanoseconds. + * + * Note that this number doesn't include leap seconds added or removed since the epoch. + * + * @see fromEpochSeconds + * @sample kotlinx.datetime.test.samples.InstantSamples.epochSeconds + */ + public val epochSeconds: Long + + /** + * The number of nanoseconds by which this instant is later than [epochSeconds] from the epoch instant. + * + * The value is always non-negative and lies in the range `0..999_999_999`. + * + * @see fromEpochSeconds + * @sample kotlinx.datetime.test.samples.InstantSamples.nanosecondsOfSecond + */ + public val nanosecondsOfSecond: Int + + /** + * Returns the number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. + * + * Any fractional part of a millisecond is rounded toward zero to the whole number of milliseconds. + * + * If the result does not fit in [Long], + * returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @see fromEpochMilliseconds + * @sample kotlinx.datetime.test.samples.InstantSamples.toEpochMilliseconds + */ + public fun toEpochMilliseconds(): Long + + /** + * Returns an instant that is the result of adding the specified [duration] to this instant. + * + * If the [duration] is positive, the returned instant is later than this instant. + * If the [duration] is negative, the returned instant is earlier than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours and are not calendar-based. + * Consider using the [plus] overload that accepts a multiple of a [DateTimeUnit] instead for calendar-based + * operations instead of using [Duration]. + * For an explanation of why some days are not 24 hours, see [DateTimeUnit.DayBased]. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.plusDuration + */ + public operator fun plus(duration: Duration): Instant + + /** + * Returns an instant that is the result of subtracting the specified [duration] from this instant. + * + * If the [duration] is positive, the returned instant is earlier than this instant. + * If the [duration] is negative, the returned instant is later than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours and are not calendar-based. + * Consider using the [minus] overload that accepts a multiple of a [DateTimeUnit] instead for calendar-based + * operations instead of using [Duration]. + * For an explanation of why some days are not 24 hours, see [DateTimeUnit.DayBased]. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusDuration + */ + public operator fun minus(duration: Duration): Instant + + // questionable + /** + * Returns the [Duration] between two instants: [other] and `this`. + * + * The duration returned is positive if this instant is later than the other, + * and negative if this instant is earlier than the other. + * + * The result is never clamped, but note that for instants that are far apart, + * the value returned may represent the duration between them inexactly due to the loss of precision. + * + * Note that sources of [Instant] values (in particular, [Clock]) are not guaranteed to be in sync with each other + * or even monotonic, so the result of this operation may be negative even if the other instant was observed later + * than this one, or vice versa. + * For measuring time intervals, consider using [TimeSource.Monotonic]. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusInstant + */ + public operator fun minus(other: Instant): Duration + + /** + * Compares `this` instant with the [other] instant. + * Returns zero if this instant represents the same moment as the other (meaning they are equal to one another), + * a negative number if this instant is earlier than the other, + * and a positive number if this instant is later than the other. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.compareToSample + */ + public override operator fun compareTo(other: Instant): Int + + /** + * Converts this instant to the ISO 8601 string representation, for example, `2023-01-02T23:40:57.120Z`. + * + * The representation uses the UTC-SLS time scale instead of UTC. + * In practice, this means that leap second handling will not be readjusted to the UTC. + * Leap seconds will not be added or skipped, so it is impossible to acquire a string + * where the component for seconds is 60, and for any day, it's possible to observe 23:59:59. + * + * @see parse + * @see DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET for a very similar format. The difference is that + * [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] will not add trailing zeros for readability to the + * fractional part of the second. + * @sample kotlinx.datetime.test.samples.InstantSamples.toStringSample + */ + public override fun toString(): String + + + public companion object { + @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) + public fun now(): Instant + + /** + * Returns an [Instant] that is [epochMilliseconds] number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. + * + * Every value of [epochMilliseconds] is guaranteed to be representable as an [Instant]. + * + * Note that [Instant] also supports nanosecond precision via [fromEpochSeconds]. + * + * @see Instant.toEpochMilliseconds + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochMilliseconds + */ + public fun fromEpochMilliseconds(epochMilliseconds: Long): Instant + + /** + * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` + * and the [nanosecondAdjustment] number of nanoseconds from the whole second. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. + * + * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. + * + * @see Instant.epochSeconds + * @see Instant.nanosecondsOfSecond + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSeconds + */ + public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long = 0): Instant + + /** + * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` + * and the [nanosecondAdjustment] number of nanoseconds from the whole second. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. + * + * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. + * + * @see Instant.epochSeconds + * @see Instant.nanosecondsOfSecond + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSecondsIntNanos + */ + public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant + + /** + * A shortcut for calling [DateTimeFormat.parse], followed by [DateTimeComponents.toInstantUsingOffset]. + * + * Parses a string that represents an instant, including date and time components and a mandatory + * time zone offset and returns the parsed [Instant] value. + * + * The string is considered to represent time on the UTC-SLS time scale instead of UTC. + * In practice, this means that, even if there is a leap second on the given day, it will not affect how the + * time is parsed, even if it's in the last 1000 seconds of the day. + * Instead, even if there is a negative leap second on the given day, 23:59:59 is still considered a valid time. + * 23:59:60 is invalid on UTC-SLS, so parsing it will fail. + * + * If the format is not specified, [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] is used. + * `2023-01-02T23:40:57.120Z` is an example of a string in this format. + * + * @throws IllegalArgumentException if the text cannot be parsed or the boundaries of [Instant] are exceeded. + * + * @see Instant.toString for formatting using the default format. + * @see Instant.format for formatting using a custom format. + * @sample kotlinx.datetime.test.samples.InstantSamples.parsing + */ + public fun parse( + input: CharSequence, + format: DateTimeFormat = DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET + ): Instant + + /** + * An instant value that is far in the past. + * + * All instants in the range `DISTANT_PAST..DISTANT_FUTURE` can be [converted][Instant.toLocalDateTime] to + * [LocalDateTime] without exceptions in every time zone. + * + * [isDistantPast] returns true for this value and all earlier ones. + */ + public val DISTANT_PAST: Instant // -100001-12-31T23:59:59.999999999Z + + /** + * An instant value that is far in the future. + * + * All instants in the range `DISTANT_PAST..DISTANT_FUTURE` can be [converted][Instant.toLocalDateTime] to + * [LocalDateTime] without exceptions in every time zone. + * + * [isDistantFuture] returns true for this value and all later ones. + */ + public val DISTANT_FUTURE: Instant // +100000-01-01T00:00:00Z + + internal val MIN: Instant + internal val MAX: Instant + } +} + +/** + * Returns true if the instant is [Instant.DISTANT_PAST] or earlier. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantPast + */ +public val Instant.isDistantPast: Boolean + get() = this <= Instant.DISTANT_PAST + +/** + * Returns true if the instant is [Instant.DISTANT_FUTURE] or later. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantFuture + */ +public val Instant.isDistantFuture: Boolean + get() = this >= Instant.DISTANT_FUTURE + +/** + * @suppress + */ +@Deprecated("Removed to support more idiomatic code. See https://github.com/Kotlin/kotlinx-datetime/issues/339", ReplaceWith("Instant.parse(this)"), DeprecationLevel.WARNING) +public fun String.toInstant(): Instant = Instant.parse(this) + +/** + * Returns an instant that is the result of adding components of [DateTimePeriod] to this instant. The components are + * added in the order from the largest units to the smallest, i.e., from years to nanoseconds. + * + * - If the [DateTimePeriod] only contains time-based components, please consider adding a [Duration] instead, + * as in `Clock.System.now() + 5.hours`. + * Then, it will not be necessary to pass the [timeZone]. + * - If the [DateTimePeriod] only has a single non-zero component (only the months or only the days), + * please consider using a multiple of [DateTimeUnit.DAY] or [DateTimeUnit.MONTH], like in + * `Clock.System.now().plus(5, DateTimeUnit.DAY, TimeZone.currentSystemDefault())`. + * + * @throws DateTimeArithmeticException if this value or the results of intermediate computations are too large to fit in + * [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.plusPeriod + */ +public expect fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Instant + +/** + * Returns an instant that is the result of subtracting components of [DateTimePeriod] from this instant. The components + * are subtracted in the order from the largest units to the smallest, i.e., from years to nanoseconds. + * + * - If the [DateTimePeriod] only contains time-based components, please consider subtracting a [Duration] instead, + * as in `Clock.System.now() - 5.hours`. + * Then, it is not necessary to pass the [timeZone]. + * - If the [DateTimePeriod] only has a single non-zero component (only the months or only the days), + * please consider using a multiple of [DateTimeUnit.DAY] or [DateTimeUnit.MONTH], as in + * `Clock.System.now().minus(5, DateTimeUnit.DAY, TimeZone.currentSystemDefault())`. + * + * @throws DateTimeArithmeticException if this value or the results of intermediate computations are too large to fit in + * [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.minusPeriod + */ +public fun Instant.minus(period: DateTimePeriod, timeZone: TimeZone): Instant = + /* An overflow can happen for any component, but we are only worried about nanoseconds, as having an overflow in + any other component means that `plus` will throw due to the minimum value of the numeric type overflowing the + `Instant` limits. */ + if (period.totalNanoseconds != Long.MIN_VALUE) { + val negatedPeriod = with(period) { buildDateTimePeriod(-totalMonths, -days, -totalNanoseconds) } + plus(negatedPeriod, timeZone) + } else { + val negatedPeriod = with(period) { buildDateTimePeriod(-totalMonths, -days, -(totalNanoseconds+1)) } + plus(negatedPeriod, timeZone).plus(1, DateTimeUnit.NANOSECOND) + } + +/** + * Returns a [DateTimePeriod] representing the difference between `this` and [other] instants. + * + * The components of [DateTimePeriod] are calculated so that adding it to `this` instant results in the [other] instant. + * + * All components of the [DateTimePeriod] returned are: + * - Positive or zero if this instant is earlier than the other. + * - Negative or zero if this instant is later than the other. + * - Exactly zero if this instant is equal to the other. + * + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.periodUntil + */ +public expect fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod + +/** + * Returns the whole number of the specified date or time [units][unit] between `this` and [other] instants + * in the specified [timeZone]. + * + * The value returned is: + * - Positive or zero if this instant is earlier than the other. + * - Negative or zero if this instant is later than the other. + * - Zero if this instant is equal to the other. + * + * If the result does not fit in [Long], returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.untilAsDateTimeUnit + */ +public expect fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long + +/** + * Returns the whole number of the specified time [units][unit] between `this` and [other] instants. + * + * The value returned is: + * - Positive or zero if this instant is earlier than the other. + * - Negative or zero if this instant is later than the other. + * - Zero if this instant is equal to the other. + * + * If the result does not fit in [Long], returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.untilAsTimeBasedUnit + */ +public fun Instant.until(other: Instant, unit: DateTimeUnit.TimeBased): Long = + try { + multiplyAddAndDivide(other.epochSeconds - epochSeconds, + NANOS_PER_ONE.toLong(), + (other.nanosecondsOfSecond - nanosecondsOfSecond).toLong(), + unit.nanoseconds) + } catch (_: ArithmeticException) { + if (this < other) Long.MAX_VALUE else Long.MIN_VALUE + } + +/** + * Returns the number of whole days between two instants in the specified [timeZone]. + * + * If the result does not fit in [Int], returns [Int.MAX_VALUE] for a positive result or [Int.MIN_VALUE] for a negative result. + * + * @see Instant.until + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.daysUntil + */ +public fun Instant.daysUntil(other: Instant, timeZone: TimeZone): Int = + until(other, DateTimeUnit.DAY, timeZone).clampToInt() + +/** + * Returns the number of whole months between two instants in the specified [timeZone]. + * + * If the result does not fit in [Int], returns [Int.MAX_VALUE] for a positive result or [Int.MIN_VALUE] for a negative result. + * + * @see Instant.until + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.monthsUntil + */ +public fun Instant.monthsUntil(other: Instant, timeZone: TimeZone): Int = + until(other, DateTimeUnit.MONTH, timeZone).clampToInt() + +/** + * Returns the number of whole years between two instants in the specified [timeZone]. + * + * If the result does not fit in [Int], returns [Int.MAX_VALUE] for a positive result or [Int.MIN_VALUE] for a negative result. + * + * @see Instant.until + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.yearsUntil + */ +public fun Instant.yearsUntil(other: Instant, timeZone: TimeZone): Int = + until(other, DateTimeUnit.YEAR, timeZone).clampToInt() + +/** + * Returns a [DateTimePeriod] representing the difference between [other] and `this` instants. + * + * The components of [DateTimePeriod] are calculated so that adding it back to the `other` instant results in this instant. + * + * All components of the [DateTimePeriod] returned are: + * - Negative or zero if this instant is earlier than the other. + * - Positive or zero if this instant is later than the other. + * - Exactly zero if this instant is equal to the other. + * + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @see Instant.periodUntil + * @sample kotlinx.datetime.test.samples.InstantSamples.minusInstantInZone + */ +public fun Instant.minus(other: Instant, timeZone: TimeZone): DateTimePeriod = + other.periodUntil(this, timeZone) + + +/** + * Returns an instant that is the result of adding one [unit] to this instant + * in the specified [timeZone]. + * + * The returned instant is later than this instant. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + */ +@Deprecated("Use the plus overload with an explicit number of units", ReplaceWith("this.plus(1, unit, timeZone)")) +public expect fun Instant.plus(unit: DateTimeUnit, timeZone: TimeZone): Instant + +/** + * Returns an instant that is the result of subtracting one [unit] from this instant + * in the specified [timeZone]. + * + * The returned instant is earlier than this instant. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + */ +@Deprecated("Use the minus overload with an explicit number of units", ReplaceWith("this.minus(1, unit, timeZone)")) +public fun Instant.minus(unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(-1, unit, timeZone) + +/** + * Returns an instant that is the result of adding one [unit] to this instant. + * + * The returned instant is later than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + */ +@Deprecated("Use the plus overload with an explicit number of units", ReplaceWith("this.plus(1, unit)")) +public fun Instant.plus(unit: DateTimeUnit.TimeBased): Instant = + plus(1L, unit) + +/** + * Returns an instant that is the result of subtracting one [unit] from this instant. + * + * The returned instant is earlier than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + */ +@Deprecated("Use the minus overload with an explicit number of units", ReplaceWith("this.minus(1, unit)")) +public fun Instant.minus(unit: DateTimeUnit.TimeBased): Instant = + plus(-1L, unit) + +/** + * Returns an instant that is the result of adding the [value] number of the specified [unit] to this instant + * in the specified [timeZone]. + * + * If the [value] is positive, the returned instant is later than this instant. + * If the [value] is negative, the returned instant is earlier than this instant. + * + * Note that the time zone does not need to be passed when the [unit] is a time-based unit. + * It is also not needed when adding date-based units to a [LocalDate][LocalDate.plus]. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.plusDateTimeUnit + */ +public expect fun Instant.plus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant + +/** + * Returns an instant that is the result of subtracting the [value] number of the specified [unit] from this instant + * in the specified [timeZone]. + * + * If the [value] is positive, the returned instant is earlier than this instant. + * If the [value] is negative, the returned instant is later than this instant. + * + * Note that the time zone does not need to be passed when the [unit] is a time-based unit. + * It is also not needed when subtracting date-based units from a [LocalDate]. + * + * If the [value] is positive, the returned instant is earlier than this instant. + * If the [value] is negative, the returned instant is later than this instant. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.minusDateTimeUnit + */ +public expect fun Instant.minus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant + +/** + * Returns an instant that is the result of adding the [value] number of the specified [unit] to this instant. + * + * If the [value] is positive, the returned instant is later than this instant. + * If the [value] is negative, the returned instant is earlier than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.plusTimeBasedUnit + */ +public fun Instant.plus(value: Int, unit: DateTimeUnit.TimeBased): Instant = + plus(value.toLong(), unit) + +/** + * Returns an instant that is the result of subtracting the [value] number of the specified [unit] from this instant. + * + * If the [value] is positive, the returned instant is earlier than this instant. + * If the [value] is negative, the returned instant is later than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusTimeBasedUnit + */ +public fun Instant.minus(value: Int, unit: DateTimeUnit.TimeBased): Instant = + minus(value.toLong(), unit) + +/** + * Returns an instant that is the result of adding the [value] number of the specified [unit] to this instant + * in the specified [timeZone]. + * + * If the [value] is positive, the returned instant is later than this instant. + * If the [value] is negative, the returned instant is earlier than this instant. + * + * Note that the time zone does not need to be passed when the [unit] is a time-based unit. + * It is also not needed when adding date-based units to a [LocalDate]. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.plusDateTimeUnit + */ +public expect fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZone): Instant + +/** + * Returns an instant that is the result of subtracting the [value] number of the specified [unit] from this instant + * in the specified [timeZone]. + * + * If the [value] is positive, the returned instant is earlier than this instant. + * If the [value] is negative, the returned instant is later than this instant. + * + * Note that the time zone does not need to be passed when the [unit] is a time-based unit. + * It is also not needed when subtracting date-based units from a [LocalDate]. + * + * @throws DateTimeArithmeticException if this value or the result is too large to fit in [LocalDateTime]. + * @sample kotlinx.datetime.test.samples.InstantSamples.minusDateTimeUnit + */ +public fun Instant.minus(value: Long, unit: DateTimeUnit, timeZone: TimeZone): Instant = + if (value != Long.MIN_VALUE) { + plus(-value, unit, timeZone) + } else { + plus(-(value + 1), unit, timeZone).plus(1, unit, timeZone) + } + +/** + * Returns an instant that is the result of adding the [value] number of the specified [unit] to this instant. + * + * If the [value] is positive, the returned instant is later than this instant. + * If the [value] is negative, the returned instant is earlier than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.plusTimeBasedUnit + */ +public expect fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Instant + +/** + * Returns an instant that is the result of subtracting the [value] number of the specified [unit] from this instant. + * + * If the [value] is positive, the returned instant is earlier than this instant. + * If the [value] is negative, the returned instant is later than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusTimeBasedUnit + */ +public fun Instant.minus(value: Long, unit: DateTimeUnit.TimeBased): Instant = + if (value != Long.MIN_VALUE) { + plus(-value, unit) + } else { + plus(-(value + 1), unit).plus(1, unit) + } + +/** + * Returns the whole number of the specified date or time [units][unit] between [other] and `this` instants + * in the specified [timeZone]. + * + * The value returned is negative or zero if this instant is earlier than the other, + * and positive or zero if this instant is later than the other. + * + * If the result does not fit in [Long], returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @throws DateTimeArithmeticException if `this` or [other] instant is too large to fit in [LocalDateTime]. + * @see Instant.until for the same operation but with swapped arguments. + * @sample kotlinx.datetime.test.samples.InstantSamples.minusAsDateTimeUnit + */ +public fun Instant.minus(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long = + other.until(this, unit, timeZone) + +/** + * Returns the whole number of the specified time [units][unit] between [other] and `this` instants. + * + * The value returned is negative or zero if this instant is earlier than the other, + * and positive or zero if this instant is later than the other. + * + * If the result does not fit in [Long], returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @see Instant.until for the same operation but with swapped arguments. + * @sample kotlinx.datetime.test.samples.InstantSamples.minusAsTimeBasedUnit + */ +public fun Instant.minus(other: Instant, unit: DateTimeUnit.TimeBased): Long = + other.until(this, unit) + +/** + * Formats this value using the given [format] using the given [offset]. + * + * Equivalent to calling [DateTimeFormat.format] on [format] and using [DateTimeComponents.setDateTimeOffset] in + * the lambda. + * + * [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] is a format very similar to the one used by [toString]. + * The only difference is that [Instant.toString] adds trailing zeros to the fraction-of-second component so that the + * number of digits after a dot is a multiple of three. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.formatting + */ +public fun Instant.format(format: DateTimeFormat, offset: UtcOffset = UtcOffset.ZERO): String { + val instant = this + return format.format { setDateTimeOffset(instant.toNewInstant(), offset) } +} + +public class DeprecationMarker private constructor() { + internal companion object { + internal val INSTANCE = DeprecationMarker() + } +} diff --git a/core/common/src/Instant.kt b/core/common/src/Instant.kt index 3deedd946..7130daaa0 100644 --- a/core/common/src/Instant.kt +++ b/core/common/src/Instant.kt @@ -3,435 +3,49 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:JvmMultifileClass +@file:JvmName("InstantKt") package kotlinx.datetime import kotlinx.datetime.format.* import kotlinx.datetime.internal.* -import kotlinx.datetime.serializers.InstantIso8601Serializer -import kotlinx.datetime.serializers.InstantComponentSerializer -import kotlinx.serialization.Serializable import kotlin.time.* +import kotlinx.time.Instant +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName /** - * A moment in time. + * A shortcut for calling [DateTimeFormat.parse], followed by [DateTimeComponents.toInstantUsingOffset]. * - * A point in time must be uniquely identified in a way that is independent of a time zone. - * For example, `1970-01-01, 00:00:00` does not represent a moment in time since this would happen at different times - * in different time zones: someone in Tokyo would think it is already `1970-01-01` several hours earlier than someone in - * Berlin would. To represent such entities, use [LocalDateTime]. - * In contrast, "the moment the clocks in London first showed 00:00 on Jan 1, 2000" is a specific moment - * in time, as is "1970-01-01, 00:00:00 UTC+0", so it can be represented as an [Instant]. + * Parses a string that represents an instant, including date and time components and a mandatory + * time zone offset and returns the parsed [Instant] value. * - * `Instant` uses the UTC-SLS (smeared leap second) time scale. This time scale doesn't contain instants - * corresponding to leap seconds, but instead "smears" positive and negative leap seconds among the last 1000 seconds - * of the day when a leap second happens. + * The string is considered to represent time on the UTC-SLS time scale instead of UTC. + * In practice, this means that, even if there is a leap second on the given day, it will not affect how the + * time is parsed, even if it's in the last 1000 seconds of the day. + * Instead, even if there is a negative leap second on the given day, 23:59:59 is still considered a valid time. + * 23:59:60 is invalid on UTC-SLS, so parsing it will fail. * - * ### Obtaining the current moment + * [Instant.parse] is equivalent to calling this function with the + * [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] format. + * `2023-01-02T23:40:57.120Z` is an example of a string in this format. * - * The [Clock] interface is the primary way to obtain the current moment: + * @throws IllegalArgumentException if the text cannot be parsed or the boundaries of [Instant] are exceeded. * - * ``` - * val clock: Clock = Clock.System - * val instant = clock.now() - * ``` - * - * The [Clock.System] implementation uses the platform-specific system clock to obtain the current moment. - * Note that this clock is not guaranteed to be monotonic, and the user or the system may adjust it at any time, - * so it should not be used for measuring time intervals. - * For that, consider using [TimeSource.Monotonic] and [TimeMark] instead of [Clock.System] and [Instant]. - * - * ### Obtaining human-readable representations - * - * #### Date and time - * - * [Instant] is essentially the number of seconds and nanoseconds since a designated moment in time, - * stored as something like `1709898983.123456789`. - * [Instant] does not contain information about the day or time, as this depends on the time zone. - * To work with this information for a specific time zone, obtain a [LocalDateTime] using [Instant.toLocalDateTime]: - * - * ``` - * val instant = Instant.fromEpochSeconds(1709898983, 123456789) - * instant.toLocalDateTime(TimeZone.of("Europe/Berlin")) // 2024-03-08T12:56:23.123456789 - * instant.toLocalDateTime(TimeZone.UTC) // 2024-03-08T11:56:23.123456789 - * ``` - * - * For values very far in the past or the future, this conversion may fail. - * The specific range of values that can be converted to [LocalDateTime] is unspecified, but at least - * [DISTANT_PAST], [DISTANT_FUTURE], and all values between them are included in that range. - * - * #### Date or time separately - * - * To obtain a [LocalDate] or [LocalTime], first, obtain a [LocalDateTime], and then use its [LocalDateTime.date] - * and [LocalDateTime.time] properties: - * - * ``` - * val instant = Instant.fromEpochSeconds(1709898983, 123456789) - * instant.toLocalDateTime(TimeZone.of("Europe/Berlin")).date // 2024-03-08 - * ``` - * - * ### Arithmetic operations - * - * #### Elapsed-time-based - * - * The [plus] and [minus] operators can be used to add [Duration]s to and subtract them from an [Instant]: - * - * ``` - * Clock.System.now() + 5.seconds // 5 seconds from now - * ``` - * - * Durations can also be represented as multiples of some [time-based datetime unit][DateTimeUnit.TimeBased]: - * - * ``` - * Clock.System.now().plus(4, DateTimeUnit.HOUR) // 4 hours from now - * ``` - * - * Also, there is a [minus] operator that returns the [Duration] representing the difference between two instants: - * - * ``` - * val start = Clock.System.now() - * val concertStart = LocalDateTime(2023, 1, 1, 20, 0, 0).toInstant(TimeZone.of("Europe/Berlin")) - * val timeUntilConcert = concertStart - start - * ``` - * - * #### Calendar-based - * - * Since [Instant] represents a point in time, it is always well-defined what the result of arithmetic operations on it - * is, including the cases when a calendar is used. - * This is not the case for [LocalDateTime], where the result of arithmetic operations depends on the time zone. - * See the [LocalDateTime] documentation for more details. - * - * Adding and subtracting calendar-based units can be done using the [plus] and [minus] operators, - * requiring a [TimeZone]: - * - * ``` - * // One day from now in Berlin - * Clock.System.now().plus(1, DateTimeUnit.DAY, TimeZone.of("Europe/Berlin")) - * - * // A day and two hours short from two months later in Berlin - * Clock.System.now().plus(DateTimePeriod(months = 2, days = -1, hours = -2), TimeZone.of("Europe/Berlin")) - * ``` - * - * The difference between [Instant] values in terms of calendar-based units can be obtained using the [periodUntil] - * method: - * - * ``` - * val start = Clock.System.now() - * val concertStart = LocalDateTime(2023, 1, 1, 20, 0, 0).toInstant(TimeZone.of("Europe/Berlin")) - * val timeUntilConcert = start.periodUntil(concertStart, TimeZone.of("Europe/Berlin")) - * // Two months, three days, four hours, and five minutes until the concert - * ``` - * - * Or the [Instant.until] method, as well as [Instant.daysUntil], [Instant.monthsUntil], - * and [Instant.yearsUntil] extension functions: - * - * ``` - * val start = Clock.System.now() - * val concertStart = LocalDateTime(2023, 1, 1, 20, 0, 0).toInstant(TimeZone.of("Europe/Berlin")) - * val timeUntilConcert = start.until(concertStart, DateTimeUnit.DAY, TimeZone.of("Europe/Berlin")) - * // 63 days until the concert, rounded down - * ``` - * - * ### Platform specifics - * - * On the JVM, there are `Instant.toJavaInstant()` and `java.time.Instant.toKotlinInstant()` - * extension functions to convert between `kotlinx.datetime` and `java.time` objects used for the same purpose. - * Similarly, on the Darwin platforms, there are `Instant.toNSDate()` and `NSDate.toKotlinInstant()` - * extension functions. - * - * ### Construction, serialization, and deserialization - * - * [fromEpochSeconds] can be used to construct an instant from the number of seconds since - * `1970-01-01T00:00:00Z` (the Unix epoch). - * [epochSeconds] and [nanosecondsOfSecond] can be used to obtain the number of seconds and nanoseconds since the epoch. - * - * ``` - * val instant = Instant.fromEpochSeconds(1709898983, 123456789) - * instant.epochSeconds // 1709898983 - * instant.nanosecondsOfSecond // 123456789 - * ``` - * - * [fromEpochMilliseconds] allows constructing an instant from the number of milliseconds since the epoch. - * [toEpochMilliseconds] can be used to obtain the number of milliseconds since the epoch. - * Note that [Instant] supports nanosecond precision, so converting to milliseconds is a lossy operation. - * - * ``` - * val instant1 = Instant.fromEpochSeconds(1709898983, 123456789) - * instant1.nanosecondsOfSecond // 123456789 - * val milliseconds = instant1.toEpochMilliseconds() // 1709898983123 - * val instant2 = Instant.fromEpochMilliseconds(milliseconds) - * instant2.nanosecondsOfSecond // 123000000 - * ``` - * - * [parse] and [toString] methods can be used to obtain an [Instant] from and convert it to a string in the - * ISO 8601 extended format. - * - * ``` - * val instant = Instant.parse("2023-01-02T22:35:01+01:00") - * instant.toString() // 2023-01-02T21:35:01Z - * ``` - * - * During parsing, the UTC offset is not returned separately. - * If the UTC offset is important, use [DateTimeComponents] with [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] to - * parse the string instead. - * - * [Instant.parse] and [Instant.format] also accept custom formats: - * - * ``` - * val customFormat = DateTimeComponents.Format { - * date(LocalDate.Formats.ISO) - * char(' ') - * time(LocalTime.Formats.ISO) - * char(' ') - * offset(UtcOffset.Formats.ISO) - * } - * val instant = Instant.parse("2023-01-02 22:35:01.14 +01:00", customFormat) - * instant.format(customFormat, offset = UtcOffset(hours = 2)) // 2023-01-02 23:35:01.14 +02:00 - * ``` - * - * Additionally, there are several `kotlinx-serialization` serializers for [Instant]: - * - [InstantIso8601Serializer] for the ISO 8601 extended format. - * - [InstantComponentSerializer] for an object with components. - * - * @see LocalDateTime for a user-visible representation of moments in time in an unspecified time zone. + * @see Instant.toString for formatting using the default format. + * @see Instant.format for formatting using a custom format. + * @see Instant.parse for parsing an ISO string without involving `kotlinx-datetime`. + * @sample kotlinx.datetime.test.samples.InstantSamples.parsing */ -@Serializable(with = InstantIso8601Serializer::class) -public expect class Instant : Comparable { - - /** - * The number of seconds from the epoch instant `1970-01-01T00:00:00Z` rounded down to a [Long] number. - * - * The difference between the rounded number of seconds and the actual number of seconds - * is returned by [nanosecondsOfSecond] property expressed in nanoseconds. - * - * Note that this number doesn't include leap seconds added or removed since the epoch. - * - * @see fromEpochSeconds - * @sample kotlinx.datetime.test.samples.InstantSamples.epochSeconds - */ - public val epochSeconds: Long - - /** - * The number of nanoseconds by which this instant is later than [epochSeconds] from the epoch instant. - * - * The value is always non-negative and lies in the range `0..999_999_999`. - * - * @see fromEpochSeconds - * @sample kotlinx.datetime.test.samples.InstantSamples.nanosecondsOfSecond - */ - public val nanosecondsOfSecond: Int - - /** - * Returns the number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. - * - * Any fractional part of a millisecond is rounded toward zero to the whole number of milliseconds. - * - * If the result does not fit in [Long], - * returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. - * - * @see fromEpochMilliseconds - * @sample kotlinx.datetime.test.samples.InstantSamples.toEpochMilliseconds - */ - public fun toEpochMilliseconds(): Long - - /** - * Returns an instant that is the result of adding the specified [duration] to this instant. - * - * If the [duration] is positive, the returned instant is later than this instant. - * If the [duration] is negative, the returned instant is earlier than this instant. - * - * The return value is clamped to the boundaries of [Instant] if the result exceeds them. - * - * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours and are not calendar-based. - * Consider using the [plus] overload that accepts a multiple of a [DateTimeUnit] instead for calendar-based - * operations instead of using [Duration]. - * For an explanation of why some days are not 24 hours, see [DateTimeUnit.DayBased]. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.plusDuration - */ - public operator fun plus(duration: Duration): Instant - - /** - * Returns an instant that is the result of subtracting the specified [duration] from this instant. - * - * If the [duration] is positive, the returned instant is earlier than this instant. - * If the [duration] is negative, the returned instant is later than this instant. - * - * The return value is clamped to the boundaries of [Instant] if the result exceeds them. - * - * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours and are not calendar-based. - * Consider using the [minus] overload that accepts a multiple of a [DateTimeUnit] instead for calendar-based - * operations instead of using [Duration]. - * For an explanation of why some days are not 24 hours, see [DateTimeUnit.DayBased]. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.minusDuration - */ - public operator fun minus(duration: Duration): Instant - - // questionable - /** - * Returns the [Duration] between two instants: [other] and `this`. - * - * The duration returned is positive if this instant is later than the other, - * and negative if this instant is earlier than the other. - * - * The result is never clamped, but note that for instants that are far apart, - * the value returned may represent the duration between them inexactly due to the loss of precision. - * - * Note that sources of [Instant] values (in particular, [Clock]) are not guaranteed to be in sync with each other - * or even monotonic, so the result of this operation may be negative even if the other instant was observed later - * than this one, or vice versa. - * For measuring time intervals, consider using [TimeSource.Monotonic]. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.minusInstant - */ - public operator fun minus(other: Instant): Duration - - /** - * Compares `this` instant with the [other] instant. - * Returns zero if this instant represents the same moment as the other (meaning they are equal to one another), - * a negative number if this instant is earlier than the other, - * and a positive number if this instant is later than the other. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.compareToSample - */ - public override operator fun compareTo(other: Instant): Int - - /** - * Converts this instant to the ISO 8601 string representation, for example, `2023-01-02T23:40:57.120Z`. - * - * The representation uses the UTC-SLS time scale instead of UTC. - * In practice, this means that leap second handling will not be readjusted to the UTC. - * Leap seconds will not be added or skipped, so it is impossible to acquire a string - * where the component for seconds is 60, and for any day, it's possible to observe 23:59:59. - * - * @see parse - * @see DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET for a very similar format. The difference is that - * [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] will not add trailing zeros for readability to the - * fractional part of the second. - * @sample kotlinx.datetime.test.samples.InstantSamples.toStringSample - */ - public override fun toString(): String - - - public companion object { - @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) - public fun now(): Instant - - /** - * Returns an [Instant] that is [epochMilliseconds] number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. - * - * Every value of [epochMilliseconds] is guaranteed to be representable as an [Instant]. - * - * Note that [Instant] also supports nanosecond precision via [fromEpochSeconds]. - * - * @see Instant.toEpochMilliseconds - * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochMilliseconds - */ - public fun fromEpochMilliseconds(epochMilliseconds: Long): Instant - - /** - * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` - * and the [nanosecondAdjustment] number of nanoseconds from the whole second. - * - * The return value is clamped to the boundaries of [Instant] if the result exceeds them. - * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. - * - * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. - * - * @see Instant.epochSeconds - * @see Instant.nanosecondsOfSecond - * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSeconds - */ - public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long = 0): Instant - - /** - * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` - * and the [nanosecondAdjustment] number of nanoseconds from the whole second. - * - * The return value is clamped to the boundaries of [Instant] if the result exceeds them. - * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. - * - * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. - * - * @see Instant.epochSeconds - * @see Instant.nanosecondsOfSecond - * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSecondsIntNanos - */ - public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant - - /** - * A shortcut for calling [DateTimeFormat.parse], followed by [DateTimeComponents.toInstantUsingOffset]. - * - * Parses a string that represents an instant, including date and time components and a mandatory - * time zone offset and returns the parsed [Instant] value. - * - * The string is considered to represent time on the UTC-SLS time scale instead of UTC. - * In practice, this means that, even if there is a leap second on the given day, it will not affect how the - * time is parsed, even if it's in the last 1000 seconds of the day. - * Instead, even if there is a negative leap second on the given day, 23:59:59 is still considered a valid time. - * 23:59:60 is invalid on UTC-SLS, so parsing it will fail. - * - * If the format is not specified, [DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET] is used. - * `2023-01-02T23:40:57.120Z` is an example of a string in this format. - * - * @throws IllegalArgumentException if the text cannot be parsed or the boundaries of [Instant] are exceeded. - * - * @see Instant.toString for formatting using the default format. - * @see Instant.format for formatting using a custom format. - * @sample kotlinx.datetime.test.samples.InstantSamples.parsing - */ - public fun parse( - input: CharSequence, - format: DateTimeFormat = DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET - ): Instant - - /** - * An instant value that is far in the past. - * - * All instants in the range `DISTANT_PAST..DISTANT_FUTURE` can be [converted][Instant.toLocalDateTime] to - * [LocalDateTime] without exceptions in every time zone. - * - * [isDistantPast] returns true for this value and all earlier ones. - */ - public val DISTANT_PAST: Instant // -100001-12-31T23:59:59.999999999Z - - /** - * An instant value that is far in the future. - * - * All instants in the range `DISTANT_PAST..DISTANT_FUTURE` can be [converted][Instant.toLocalDateTime] to - * [LocalDateTime] without exceptions in every time zone. - * - * [isDistantFuture] returns true for this value and all later ones. - */ - public val DISTANT_FUTURE: Instant // +100000-01-01T00:00:00Z - - internal val MIN: Instant - internal val MAX: Instant - } +public fun Instant.Companion.parse( + input: CharSequence, + format: DateTimeFormat, +): Instant = try { + format.parse(input).toInstantUsingOffset() +} catch (e: IllegalArgumentException) { + throw DateTimeFormatException("Failed to parse an instant from '$input'", e) } -/** - * Returns true if the instant is [Instant.DISTANT_PAST] or earlier. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantPast - */ -public val Instant.isDistantPast: Boolean - get() = this <= Instant.DISTANT_PAST - -/** - * Returns true if the instant is [Instant.DISTANT_FUTURE] or later. - * - * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantFuture - */ -public val Instant.isDistantFuture: Boolean - get() = this >= Instant.DISTANT_FUTURE - -/** - * @suppress - */ -@Deprecated("Removed to support more idiomatic code. See https://github.com/Kotlin/kotlinx-datetime/issues/339", ReplaceWith("Instant.parse(this)"), DeprecationLevel.WARNING) -public fun String.toInstant(): Instant = Instant.parse(this) - /** * Returns an instant that is the result of adding components of [DateTimePeriod] to this instant. The components are * added in the order from the largest units to the smallest, i.e., from years to nanoseconds. diff --git a/core/common/src/TimeZone.kt b/core/common/src/TimeZone.kt index 808a8ad69..3636920e2 100644 --- a/core/common/src/TimeZone.kt +++ b/core/common/src/TimeZone.kt @@ -10,6 +10,7 @@ package kotlinx.datetime import kotlinx.datetime.serializers.* import kotlinx.serialization.Serializable +import kotlinx.time.Instant /** * A time zone, provides the conversion between [Instant] and [LocalDateTime] values @@ -126,6 +127,11 @@ public expect open class TimeZone { */ public fun Instant.toLocalDateTime(): LocalDateTime + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal fun kotlinx.datetime.Instant.toLocalDateTime(): LocalDateTime + /** * Returns an instant that corresponds to this civil datetime value in the time zone provided as an implicit receiver. * @@ -141,7 +147,12 @@ public expect open class TimeZone { * @see Instant.toLocalDateTime * @sample kotlinx.datetime.test.samples.TimeZoneSamples.toInstantWithTwoReceivers */ - public fun LocalDateTime.toInstant(): Instant + public fun LocalDateTime.toInstant(deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal fun LocalDateTime.toInstant(): kotlinx.datetime.Instant } /** @@ -195,6 +206,11 @@ public typealias ZoneOffset = FixedOffsetTimeZone */ public expect fun TimeZone.offsetAt(instant: Instant): UtcOffset +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun TimeZone.offsetAt(instant: kotlinx.datetime.Instant): UtcOffset = + offsetAt(instant.toNewInstant()) + /** * Returns a civil datetime value that this instant has in the specified [timeZone]. * @@ -208,6 +224,11 @@ public expect fun TimeZone.offsetAt(instant: Instant): UtcOffset */ public expect fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun kotlinx.datetime.Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime = + toNewInstant().toLocalDateTime(timeZone) + /** * Returns a civil datetime value that this instant has in the specified [UTC offset][offset]. * @@ -221,6 +242,11 @@ public expect fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime */ internal expect fun Instant.toLocalDateTime(offset: UtcOffset): LocalDateTime +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun kotlinx.datetime.Instant.toLocalDateTime(offset: UtcOffset): LocalDateTime = + toNewInstant().toLocalDateTime(offset) + /** * Finds the offset from UTC the specified [timeZone] has at this instant of physical time. * @@ -235,6 +261,11 @@ internal expect fun Instant.toLocalDateTime(offset: UtcOffset): LocalDateTime public fun Instant.offsetIn(timeZone: TimeZone): UtcOffset = timeZone.offsetAt(this) +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun kotlinx.datetime.Instant.offsetIn(timeZone: TimeZone): UtcOffset = + timeZone.offsetAt(toNewInstant()) + /** * Returns an instant that corresponds to this civil datetime value in the specified [timeZone]. * @@ -250,7 +281,13 @@ public fun Instant.offsetIn(timeZone: TimeZone): UtcOffset = * @see Instant.toLocalDateTime * @sample kotlinx.datetime.test.samples.TimeZoneSamples.localDateTimeToInstantInZone */ -public expect fun LocalDateTime.toInstant(timeZone: TimeZone): Instant +public expect fun LocalDateTime.toInstant(timeZone: TimeZone, deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant + +@PublishedApi +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") +@kotlin.internal.LowPriorityInOverloadResolution +internal fun LocalDateTime.toInstant(timeZone: TimeZone): kotlinx.datetime.Instant = + toInstant(timeZone).toDeprecatedInstant() /** * Returns an instant that corresponds to this civil datetime value that happens at the specified [UTC offset][offset]. @@ -258,7 +295,13 @@ public expect fun LocalDateTime.toInstant(timeZone: TimeZone): Instant * @see Instant.toLocalDateTime * @sample kotlinx.datetime.test.samples.TimeZoneSamples.localDateTimeToInstantInOffset */ -public expect fun LocalDateTime.toInstant(offset: UtcOffset): Instant +public expect fun LocalDateTime.toInstant(offset: UtcOffset, deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant + +@PublishedApi +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") +@kotlin.internal.LowPriorityInOverloadResolution +internal fun LocalDateTime.toInstant(offset: UtcOffset): kotlinx.datetime.Instant = + toInstant(offset).toDeprecatedInstant() /** * Returns an instant that corresponds to the start of this date in the specified [timeZone]. @@ -273,4 +316,10 @@ public expect fun LocalDateTime.toInstant(offset: UtcOffset): Instant * * @sample kotlinx.datetime.test.samples.TimeZoneSamples.atStartOfDayIn */ -public expect fun LocalDate.atStartOfDayIn(timeZone: TimeZone): Instant +public expect fun LocalDate.atStartOfDayIn(timeZone: TimeZone, deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant + +@PublishedApi +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") +@kotlin.internal.LowPriorityInOverloadResolution +internal fun LocalDate.atStartOfDayIn(timeZone: TimeZone): kotlinx.datetime.Instant = + atStartOfDayIn(timeZone).toDeprecatedInstant() diff --git a/core/common/src/format/DateTimeComponents.kt b/core/common/src/format/DateTimeComponents.kt index 436fa4992..e2a535fb2 100644 --- a/core/common/src/format/DateTimeComponents.kt +++ b/core/common/src/format/DateTimeComponents.kt @@ -12,6 +12,7 @@ import kotlinx.datetime.internal.format.* import kotlinx.datetime.internal.format.parser.Copyable import kotlinx.datetime.internal.safeMultiply import kotlin.reflect.* +import kotlinx.time.Instant /** * A collection of datetime fields used specifically for parsing and formatting. @@ -244,6 +245,12 @@ public class DateTimeComponents internal constructor(internal val contents: Date year = year!! + ((instant.epochSeconds / SECONDS_PER_10000_YEARS) * 10000).toInt() } + @PublishedApi + @Suppress("DEPRECATION_ERROR") + internal fun setDateTimeOffset(instant: kotlinx.datetime.Instant, utcOffset: UtcOffset) { + setDateTimeOffset(instant.toNewInstant(), utcOffset) + } + /** * Writes the contents of the specified [localDateTime] and [utcOffset] to this [DateTimeComponents]. * @@ -474,7 +481,7 @@ public class DateTimeComponents internal constructor(internal val contents: Date * with one another. * @sample kotlinx.datetime.test.samples.format.DateTimeComponentsSamples.toInstantUsingOffset */ - public fun toInstantUsingOffset(): Instant { + public fun toInstantUsingOffset(deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant { val offset = toUtcOffset() val time = toLocalTime() val truncatedDate = contents.date.copy() @@ -492,10 +499,16 @@ public class DateTimeComponents internal constructor(internal val contents: Date } catch (e: ArithmeticException) { throw DateTimeFormatException("The parsed date is outside the range representable by Instant", e) } - if (totalSeconds < Instant.MIN.epochSeconds || totalSeconds > Instant.MAX.epochSeconds) + val result = Instant.fromEpochSeconds(totalSeconds, nanosecond ?: 0) + if (result.epochSeconds != totalSeconds) throw DateTimeFormatException("The parsed date is outside the range representable by Instant") - return Instant.fromEpochSeconds(totalSeconds, nanosecond ?: 0) + return result } + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal fun toInstantUsingOffset(): kotlinx.datetime.Instant = toInstantUsingOffset().toDeprecatedInstant() } /** diff --git a/core/common/src/serializers/InstantSerializers.kt b/core/common/src/serializers/DeprecatedInstantSerializers.kt similarity index 98% rename from core/common/src/serializers/InstantSerializers.kt rename to core/common/src/serializers/DeprecatedInstantSerializers.kt index c64bdf475..9d4d67f58 100644 --- a/core/common/src/serializers/InstantSerializers.kt +++ b/core/common/src/serializers/DeprecatedInstantSerializers.kt @@ -3,6 +3,7 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:Suppress("DEPRECATION_ERROR") package kotlinx.datetime.serializers import kotlinx.datetime.Instant diff --git a/core/common/test/ClockTimeSourceTest.kt b/core/common/test/ClockTimeSourceTest.kt index 75e30106d..53a6dfca6 100644 --- a/core/common/test/ClockTimeSourceTest.kt +++ b/core/common/test/ClockTimeSourceTest.kt @@ -11,6 +11,8 @@ import kotlin.time.* import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds +import kotlinx.time.Clock +import kotlinx.time.Instant @OptIn(ExperimentalTime::class) @Suppress("DEPRECATION") @@ -45,7 +47,7 @@ class ClockTimeSourceTest { clock.instant -= 2.days assertEquals(-1.days, mark.elapsedNow()) - clock.instant = Instant.MAX + clock.instant = Instant.fromEpochSeconds(Long.MAX_VALUE) assertEquals(Duration.INFINITE, mark.elapsedNow()) } diff --git a/core/common/test/DeprecatedClockTimeSourceTest.kt b/core/common/test/DeprecatedClockTimeSourceTest.kt new file mode 100644 index 000000000..75030f3aa --- /dev/null +++ b/core/common/test/DeprecatedClockTimeSourceTest.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2019-2023 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +package kotlinx.datetime.test + +import kotlinx.datetime.* +import kotlin.test.* +import kotlin.time.* +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.nanoseconds + +@OptIn(ExperimentalTime::class) +class DeprecatedClockTimeSourceTest { + @Test + fun arithmetic() { + val timeSource = Clock.System.asTimeSource() + val mark0 = timeSource.markNow() + + val markPast = mark0 - 1.days + val markFuture = mark0 + 1.days + + assertTrue(markPast < mark0) + assertTrue(markFuture > mark0) + assertEquals(mark0, markPast + 1.days) + assertEquals(2.days, markFuture - markPast) + } + + @Test + fun elapsed() { + val clock = object : Clock { + var instant = Clock.System.now() + override fun now(): Instant = instant + } + val timeSource = clock.asTimeSource() + val mark = timeSource.markNow() + assertEquals(Duration.ZERO, mark.elapsedNow()) + + clock.instant += 1.days + assertEquals(1.days, mark.elapsedNow()) + + clock.instant -= 2.days + assertEquals(-1.days, mark.elapsedNow()) + + clock.instant = Instant.fromEpochSeconds(Long.MAX_VALUE) + assertEquals(Duration.INFINITE, mark.elapsedNow()) + } + + @Test + fun differentSources() { + val mark1 = Clock.System.asTimeSource().markNow() + val mark2 = object : Clock { + override fun now(): Instant = Instant.DISTANT_FUTURE + }.asTimeSource().markNow() + assertNotEquals(mark1, mark2) + assertFailsWith { mark1 - mark2 } + assertFailsWith { mark1 compareTo mark2 } + } + + @Test + fun saturation() { + val mark0 = Clock.System.asTimeSource().markNow() + + val markFuture = mark0 + Duration.INFINITE + val markPast = mark0 - Duration.INFINITE + + for (delta in listOf(Duration.ZERO, 1.nanoseconds, 1.days)) { + assertEquals(markFuture, markFuture - delta) + assertEquals(markFuture, markFuture + delta) + + assertEquals(markPast, markPast - delta) + assertEquals(markPast, markPast + delta) + } + val infinitePairs = listOf(markFuture to markPast, markFuture to mark0, mark0 to markPast) + for ((later, earlier) in infinitePairs) { + assertEquals(Duration.INFINITE, later - earlier) + assertEquals(-Duration.INFINITE, earlier - later) + } + assertEquals(Duration.ZERO, markFuture - markFuture) + assertEquals(Duration.ZERO, markPast - markPast) + + assertFailsWith { markFuture - Duration.INFINITE } + assertFailsWith { markPast + Duration.INFINITE } + } +} diff --git a/core/common/test/DeprecatedInstantTest.kt b/core/common/test/DeprecatedInstantTest.kt new file mode 100644 index 000000000..43be6ae20 --- /dev/null +++ b/core/common/test/DeprecatedInstantTest.kt @@ -0,0 +1,640 @@ +/* + * Copyright 2019-2020 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +package kotlinx.datetime.test + +import kotlinx.datetime.* +import kotlinx.datetime.format.* +import kotlinx.datetime.internal.* +import kotlin.random.* +import kotlin.test.* +import kotlin.time.* +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds + +class DeprecatedInstantTest { + + @Test + fun testNow() { + val instant = Clock.System.now() + val millis = instant.toEpochMilliseconds() + + assertTrue(millis > 1_500_000_000_000L) + + println(instant) + println(instant.toEpochMilliseconds()) + + val millisInstant = Instant.fromEpochMilliseconds(millis) + + assertEquals(millis, millisInstant.toEpochMilliseconds()) + + val notEqualInstant = Instant.fromEpochMilliseconds(millis + 1) + assertNotEquals(notEqualInstant, instant) + } + + @Test + fun instantArithmetic() { + val instant = Clock.System.now().toEpochMilliseconds().let { Instant.fromEpochMilliseconds(it) } // round to millis + val diffMillis = Random.nextLong(1000, 1_000_000_000) + val diff = diffMillis.milliseconds + + val nextInstant = (instant.toEpochMilliseconds() + diffMillis).let { Instant.fromEpochMilliseconds(it) } + + assertEquals(diff, nextInstant - instant) + assertEquals(nextInstant, instant + diff) + assertEquals(instant, nextInstant - diff) + + println("this: $instant, next: $nextInstant, diff: ${diff.toIsoString()}") + } + + @Test + fun instantToLocalDTConversion() { + val now = Clock.System.now() + println(now.toLocalDateTime(TimeZone.UTC)) + println(now.toLocalDateTime(TimeZone.currentSystemDefault())) + } + + /* Based on the ThreeTenBp project. + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + */ + @Test + fun parseIsoString() { + val instants = arrayOf( + Triple("1970-01-01T00:00:00Z", 0, 0), + Triple("1970-01-01t00:00:00Z", 0, 0), + Triple("1970-01-01T00:00:00z", 0, 0), + Triple("1970-01-01T00:00:00.0Z", 0, 0), + Triple("1970-01-01T00:00:00.000000000Z", 0, 0), + Triple("1970-01-01T00:00:00.000000001Z", 0, 1), + Triple("1970-01-01T00:00:00.100000000Z", 0, 100000000), + Triple("1970-01-01T00:00:01Z", 1, 0), + Triple("1970-01-01T00:01:00Z", 60, 0), + Triple("1970-01-01T00:01:01Z", 61, 0), + Triple("1970-01-01T00:01:01.000000001Z", 61, 1), + Triple("1970-01-01T01:00:00.000000000Z", 3600, 0), + Triple("1970-01-01T01:01:01.000000001Z", 3661, 1), + Triple("1970-01-02T01:01:01.100000000Z", 90061, 100000000)) + instants.forEach { + val (str, seconds, nanos) = it + val instant = Instant.parse(str) + assertEquals(seconds.toLong() * 1000 + nanos / 1000000, instant.toEpochMilliseconds()) + } + + assertInvalidFormat { Instant.parse("1970-01-01T23:59:60Z")} + assertInvalidFormat { Instant.parse("1970-01-01T24:00:00Z")} + assertInvalidFormat { Instant.parse("1970-01-01T23:59Z")} + assertInvalidFormat { Instant.parse("x") } + assertInvalidFormat { Instant.parse("12020-12-31T23:59:59.000000000Z") } + // this string represents an Instant that is currently larger than Instant.MAX any of the implementations: + assertInvalidFormat { Instant.parse("+1000000001-12-31T23:59:59.000000000Z") } + } + + @Test + fun parseStringsWithOffsets() { + val strings = arrayOf( + Pair("2020-01-01T00:01:01.02+18:00", "2019-12-31T06:01:01.020Z"), + Pair("2020-01-01T00:01:01.123456789-17:59:59", "2020-01-01T18:01:00.123456789Z"), + Pair("2020-01-01T00:01:01.010203040+17:59:59", "2019-12-31T06:01:02.010203040Z"), + Pair("2020-01-01T00:01:01.010203040+17:59", "2019-12-31T06:02:01.010203040Z"), + Pair("2020-01-01T00:01:01+00", "2020-01-01T00:01:01Z"), + ) + strings.forEach { (str, strInZ) -> + val instant = Instant.parse(str) + assertEquals(Instant.parse(strInZ), instant, str) + assertEquals(strInZ, instant.toString(), str) + } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+18:01") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+1801") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+0") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+000000") } + + val instants = listOf( + Instant.DISTANT_FUTURE, + Instant.DISTANT_PAST, + Instant.fromEpochSeconds(0, 0)) + + val offsetStrings = listOf( + "Z", + "+03:12:14", + "-03:12:14", + "+02:35", + "-02:35", + "+04", + "-04", + ) + + val offsetFormat = UtcOffset.Format { + optional("Z") { + offsetHours() + optional { + char(':'); offsetMinutesOfHour() + optional { char(':'); offsetSecondsOfMinute() } + } + } + } + val offsets = offsetStrings.map { UtcOffset.parse(it, offsetFormat) } + + for (instant in instants) { + for (offsetIx in offsets.indices) { + val str = instant.format(DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET, offsets[offsetIx]) + val offsetString = offsets[offsetIx].toString() + assertEquals(offsetString, offsetString.commonSuffixWith(str)) + assertEquals(instant, Instant.parse(str, DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET)) + assertEquals(instant, Instant.parse(str)) + } + } + } + + @Test + fun instantCalendarArithmetic() { + val zone = TimeZone.of("Europe/Berlin") + + fun expectBetween(instant1: Instant, instant2: Instant, expected: Long, unit: DateTimeUnit) { + assertEquals(expected, instant1.until(instant2, unit, zone), "i1.until(i2)") + assertEquals(expected, -instant2.until(instant1, unit, zone), "i2.until(i1)") + assertEquals(expected, instant2.minus(instant1, unit, zone), "i2.minus(i1)") + assertEquals(expected, -instant1.minus(instant2, unit, zone), "i1.minus(i2)") + + for (timeUnit in listOf(DateTimeUnit.MICROSECOND, DateTimeUnit.MILLISECOND, DateTimeUnit.SECOND, DateTimeUnit.MINUTE, DateTimeUnit.HOUR)) { + val diff = instant2.minus(instant1, timeUnit, zone) + assertEquals(instant2 - instant1, timeUnit.duration * diff.toDouble()) + assertEquals(instant2, instant1.plus(diff, timeUnit, zone)) + assertEquals(instant1, instant2.minus(diff, timeUnit, zone)) + assertEquals(instant2, instant1.plus(diff, timeUnit)) + assertEquals(instant1, instant2.minus(diff, timeUnit)) + } + } + + val instant1 = LocalDateTime(2019, Month.OCTOBER, 27, 2, 59).toInstant(zone).toDeprecatedInstant() + checkComponents(instant1.toLocalDateTime(zone), 2019, 10, 27, 2, 59) + + val instant2 = instant1.plus(DateTimePeriod(hours = 24), zone) + checkComponents(instant2.toLocalDateTime(zone), 2019, 10, 28, 1, 59) + expectBetween(instant1, instant2, 24, DateTimeUnit.HOUR) + assertEquals(instant1, instant2.minus(DateTimePeriod(hours = 24), zone)) + + val instant3 = instant1.plus(1, DateTimeUnit.DAY, zone) + checkComponents(instant3.toLocalDateTime(zone), 2019, 10, 28, 2, 59) + expectBetween(instant1, instant3, 25, DateTimeUnit.HOUR) + expectBetween(instant1, instant3, 1, DateTimeUnit.DAY) + assertEquals(1, instant1.daysUntil(instant3, zone)) + assertEquals(instant1.minus(1, DateTimeUnit.HOUR), instant2.minus(1, DateTimeUnit.DAY, zone)) + + val instant4 = instant1.plus(14, DateTimeUnit.MONTH, zone) + checkComponents(instant4.toLocalDateTime(zone), 2020, 12, 27, 2, 59) + expectBetween(instant1, instant4, 1, DateTimeUnit.YEAR) + expectBetween(instant1, instant4, 4, DateTimeUnit.QUARTER) + expectBetween(instant1, instant4, 14, DateTimeUnit.MONTH) + expectBetween(instant1, instant4, 61, DateTimeUnit.WEEK) + expectBetween(instant1, instant4, 366 + 31 + 30, DateTimeUnit.DAY) + expectBetween(instant1, instant4, (366 + 31 + 30) * 24 + 1, DateTimeUnit.HOUR) + assertEquals(instant1.plus(1, DateTimeUnit.HOUR), instant4.minus(14, DateTimeUnit.MONTH, zone)) + + val period = DateTimePeriod(days = 1, hours = 1) + val instant5 = instant1.plus(period, zone) + checkComponents(instant5.toLocalDateTime(zone), 2019, 10, 28, 3, 59) + assertEquals(period, instant1.periodUntil(instant5, zone)) + assertEquals(period, instant5.minus(instant1, zone)) + assertEquals(26.hours, instant5.minus(instant1)) + assertEquals(instant1.plus(1, DateTimeUnit.HOUR), instant5.minus(period, zone)) + + val instant6 = instant1.plus(23, DateTimeUnit.HOUR, zone) + checkComponents(instant6.toLocalDateTime(zone), 2019, 10, 28, 0, 59) + expectBetween(instant1, instant6, 23, DateTimeUnit.HOUR) + expectBetween(instant1, instant6, 0, DateTimeUnit.DAY) + assertEquals(instant1, instant6.minus(23, DateTimeUnit.HOUR, zone)) + } + + @Test + fun addingMultiplesOf2_32() { + val pow2_32 = 1L shl 32 + val instant1 = Instant.fromEpochSeconds(0) + val instant2 = instant1.plus(pow2_32, DateTimeUnit.NANOSECOND, TimeZone.UTC) + assertEquals(pow2_32 / NANOS_PER_ONE, instant2.epochSeconds) + assertEquals(pow2_32 % NANOS_PER_ONE, instant2.nanosecondsOfSecond.toLong()) + + val instant3 = instant1.plus(pow2_32, DateTimeUnit.SECOND, TimeZone.UTC) + assertEquals(pow2_32, instant3.epochSeconds) + } + + @Test + fun unitMultiplesUntil() { + val unit1000days = DateTimeUnit.DAY * 1000 + val unit4years = DateTimeUnit.YEAR * 4 // longer than 1000-DAY + + val zone = TimeZone.UTC + val min = LocalDateTime.MIN.toInstant(zone) + val max = LocalDateTime.MAX.toInstant(zone) + val diffDays = min.until(max, unit1000days, zone) + val diffYears = min.until(max, unit4years, zone) + assertTrue(diffDays in 0..Int.MAX_VALUE, "difference in $unit1000days should fit in Int, was $diffDays") + assertTrue(diffDays > diffYears, "difference in $unit1000days unit must be more than in $unit4years unit, was $diffDays $diffYears") + + val unit500ns = DateTimeUnit.NANOSECOND * 500 + val start = Instant.parse("1700-01-01T00:00:00Z") + val end = start.plus(300, DateTimeUnit.YEAR, zone) + val diffNs = start.until(end, unit500ns, zone) + val diffUs = start.until(end, DateTimeUnit.MICROSECOND, zone) + assertEquals(diffUs * 2, diffNs) + + assertEquals(end, start.plus(diffNs, unit500ns, zone)) + assertEquals(start, end.plus(-diffUs, DateTimeUnit.MICROSECOND, zone)) + } + + @Test + fun instantOffset() { + val zone = TimeZone.of("Europe/Berlin") + val instant1 = LocalDateTime(2019, 10, 27, 2, 59, 0, 0).toInstant(zone) + val ldt1 = instant1.toLocalDateTime(zone) + val offset1 = instant1.offsetIn(zone) + checkComponents(ldt1, 2019, 10, 27, 2, 59) + assertEquals(instant1, ldt1.toInstant(offset1)) + + val instant2 = instant1 + 1.hours + val ldt2 = instant2.toLocalDateTime(zone) + val offset2 = instant2.offsetIn(zone) + assertEquals(ldt1, ldt2) + assertEquals(instant2, ldt2.toInstant(offset2)) + assertNotEquals(offset1, offset2) + assertEquals(offset1.totalSeconds.seconds, offset2.totalSeconds.seconds + 1.hours) + + val instant3 = instant2 - 2.hours + val offset3 = instant3.offsetIn(zone) + assertEquals(offset1, offset3) + + // without the minus, this test fails on JVM + (Instant.MAX - (2 * 365).days).offsetIn(zone) + } + + @Test + fun changingTimeZoneRules() { + val start = Instant.parse("1991-01-25T23:15:15.855Z") + val end = Instant.parse("2006-04-24T22:07:32.561Z") + val diff = start.periodUntil(end, TimeZone.of("Europe/Moscow")) + val end2 = start.plus(diff, TimeZone.of("Europe/Moscow")) + assertEquals(end, end2) + } + + @Test + fun diffInvariant() { + repeat(STRESS_TEST_ITERATIONS) { + val millis1 = Random.nextLong(2_000_000_000_000L) + val millis2 = Random.nextLong(2_000_000_000_000L) + val instant1 = Instant.fromEpochMilliseconds(millis1) + val instant2 = Instant.fromEpochMilliseconds(millis2) + + val diff = instant1.periodUntil(instant2, TimeZone.currentSystemDefault()) + val instant3 = instant1.plus(diff, TimeZone.currentSystemDefault()) + + if (instant2 != instant3) + println("start: $instant1, end: $instant2, start + diff: $instant3, diff: $diff") + } + } + + @Test + fun diffInvariantSameAsDate() { + repeat(STRESS_TEST_ITERATIONS) { + val millis1 = Random.nextLong(2_000_000_000_000L) + val millis2 = Random.nextLong(2_000_000_000_000L) + with(TimeZone.UTC) TZ@ { + val date1 = Instant.fromEpochMilliseconds(millis1).toLocalDateTime().date + val date2 = Instant.fromEpochMilliseconds(millis2).toLocalDateTime().date + val instant1 = date1.atStartOfDayIn(this@TZ) + val instant2 = date2.atStartOfDayIn(this@TZ) + + val diff1 = instant1.periodUntil(instant2, this@TZ) + val diff2 = date1.periodUntil(date2) + + if (diff1 != diff2) + throw AssertionError( + "start: $instant1, end: $instant2, diff by instants: $diff1, diff by dates: $diff2" + ) + } + } + } + + + @Test + fun zoneDependentDiff() { + val instant1 = Instant.parse("2019-04-01T00:00:00Z") + val instant2 = Instant.parse("2019-05-01T04:00:00Z") + + for (zone in (-12..12 step 3).map { h -> TimeZone.of("${if (h >= 0) "+" else ""}$h") }) { + val dt1 = instant1.toLocalDateTime(zone) + val dt2 = instant2.toLocalDateTime(zone) + val diff = instant1.periodUntil(instant2, zone) + println("diff between $dt1 and $dt2 at zone $zone: $diff") + } + } + + /* Based on the ThreeTenBp project. + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + */ + @Test + fun nanosecondAdjustment() { + for (i in -2..2L) { + for (j in 0..9) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i, t.epochSeconds) + assertEquals(j, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + for (j in -10..-1) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i - 1, t.epochSeconds) + assertEquals(j + 1000000000, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + for (j in 999_999_990..999_999_999) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i, t.epochSeconds) + assertEquals(j, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + } + val t = Instant.fromEpochSeconds(0, Int.MAX_VALUE) + assertEquals((Int.MAX_VALUE / 1_000_000_000).toLong(), t.epochSeconds) + assertEquals(Int.MAX_VALUE % 1_000_000_000, t.nanosecondsOfSecond) + val t2 = Instant.fromEpochSeconds(0, Long.MAX_VALUE) + assertEquals(Long.MAX_VALUE / 1_000_000_000, t2.epochSeconds) + assertEquals((Long.MAX_VALUE % 1_000_000_000).toInt(), t2.nanosecondsOfSecond) + } + + /* Based on the ThreeTenBp project. + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + */ + @Test + fun strings() { + assertEquals("0000-01-02T00:00:00Z", LocalDateTime(0, 1, 2, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("0000-01-01T12:30:00Z", LocalDateTime(0, 1, 1, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("0000-01-01T00:00:00.000000001Z", LocalDateTime(0, 1, 1, 0, 0, 0, 1).toInstant(TimeZone.UTC).toString()) + assertEquals("0000-01-01T00:00:00Z", LocalDateTime(0, 1, 1, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-0001-12-31T23:59:59.999999999Z", LocalDateTime(-1, 12, 31, 23, 59, 59, 999999999).toInstant(TimeZone.UTC).toString()) + assertEquals("-0001-12-31T12:30:00Z", LocalDateTime(-1, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-0001-12-30T12:30:00Z", LocalDateTime(-1, 12, 30, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-9999-01-02T12:30:00Z", LocalDateTime(-9999, 1, 2, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-9999-01-01T12:30:00Z", LocalDateTime(-9999, 1, 1, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-9999-01-01T00:00:00Z", LocalDateTime(-9999, 1, 1, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-10000-12-31T23:59:59.999999999Z", LocalDateTime(-10000, 12, 31, 23, 59, 59, 999999999).toInstant(TimeZone.UTC).toString()) + assertEquals("-10000-12-31T12:30:00Z", LocalDateTime(-10000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-10000-12-30T12:30:00Z", LocalDateTime(-10000, 12, 30, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-15000-12-31T12:30:00Z", LocalDateTime(-15000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-19999-01-02T12:30:00Z", LocalDateTime(-19999, 1, 2, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-19999-01-01T12:30:00Z", LocalDateTime(-19999, 1, 1, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-19999-01-01T00:00:00Z", LocalDateTime(-19999, 1, 1, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-20000-12-31T23:59:59.999999999Z", LocalDateTime(-20000, 12, 31, 23, 59, 59, 999999999).toInstant(TimeZone.UTC).toString()) + assertEquals("-20000-12-31T12:30:00Z", LocalDateTime(-20000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-20000-12-30T12:30:00Z", LocalDateTime(-20000, 12, 30, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("-25000-12-31T12:30:00Z", LocalDateTime(-25000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("9999-12-30T12:30:00Z", LocalDateTime(9999, 12, 30, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("9999-12-31T12:30:00Z", LocalDateTime(9999, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("9999-12-31T23:59:59.999999999Z", LocalDateTime(9999, 12, 31, 23, 59, 59, 999999999).toInstant(TimeZone.UTC).toString()) + assertEquals("+10000-01-01T00:00:00Z", LocalDateTime(10000, 1, 1, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+10000-01-01T12:30:00Z", LocalDateTime(10000, 1, 1, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+10000-01-02T12:30:00Z", LocalDateTime(10000, 1, 2, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+15000-12-31T12:30:00Z", LocalDateTime(15000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-30T12:30:00Z", LocalDateTime(19999, 12, 30, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T12:30:00Z", LocalDateTime(19999, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.999999999Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 999999999).toInstant(TimeZone.UTC).toString()) + assertEquals("+20000-01-01T00:00:00Z", LocalDateTime(20000, 1, 1, 0, 0, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+20000-01-01T12:30:00Z", LocalDateTime(20000, 1, 1, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+20000-01-02T12:30:00Z", LocalDateTime(20000, 1, 2, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+25000-12-31T12:30:00Z", LocalDateTime(25000, 12, 31, 12, 30, 0, 0).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.009999999Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 9999999).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.999999Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 999999000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.009999Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 9999000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.123Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 123000000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.100Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 100000000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.020Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 20000000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.003Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 3000000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000400Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 400000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000050Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 50000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000006Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 6000).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000000700Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 700).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000000080Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 80).toInstant(TimeZone.UTC).toString()) + assertEquals("+19999-12-31T23:59:59.000000009Z", LocalDateTime(19999, 12, 31, 23, 59, 59, 9).toInstant(TimeZone.UTC).toString()) + } + + @Test + fun distantPastAndFuture() { + val distantFutureString = "+100000-01-01T00:00:00Z" + val distantPastString = "-100001-12-31T23:59:59.999999999Z" + assertEquals(distantFutureString, Instant.DISTANT_FUTURE.toString()) + assertEquals(Instant.DISTANT_FUTURE, distantFutureString.toInstant()) + assertEquals(distantPastString, Instant.DISTANT_PAST.toString()) + assertEquals(Instant.DISTANT_PAST, distantPastString.toInstant()) + assertTrue(Instant.DISTANT_PAST.isDistantPast) + assertTrue(Instant.DISTANT_FUTURE.isDistantFuture) + assertFalse(Instant.DISTANT_PAST.isDistantFuture) + assertFalse(Instant.DISTANT_FUTURE.isDistantPast) + assertFalse((Instant.DISTANT_PAST + 1.nanoseconds).isDistantPast) + assertFalse((Instant.DISTANT_FUTURE - 1.nanoseconds).isDistantFuture) + assertTrue((Instant.DISTANT_PAST - 1.nanoseconds).isDistantPast) + assertTrue((Instant.DISTANT_FUTURE + 1.nanoseconds).isDistantFuture) + assertTrue(Instant.MAX.isDistantFuture) + assertFalse(Instant.MAX.isDistantPast) + assertTrue(Instant.MIN.isDistantPast) + assertFalse(Instant.MIN.isDistantFuture) + } + +} + +class DeprecatedInstantRangeTest { + private val UTC = TimeZone.UTC + private val maxValidInstant = LocalDateTime.MAX.toInstant(UTC).toDeprecatedInstant() + private val minValidInstant = LocalDateTime.MIN.toInstant(UTC).toDeprecatedInstant() + + private val largePositiveLongs = listOf(Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 50) + private val largeNegativeLongs = listOf(Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 50) + + private val largePositiveInstants = listOf(Instant.MAX, Instant.MAX - 1.seconds, Instant.MAX - 50.seconds) + private val largeNegativeInstants = listOf(Instant.MIN, Instant.MIN + 1.seconds, Instant.MIN + 50.seconds) + + private val smallInstants = listOf( + Instant.fromEpochMilliseconds(0), + Instant.fromEpochMilliseconds(1003), + Instant.fromEpochMilliseconds(253112) + ) + + + @Test + fun epochMillisecondsClamping() { + /* Any number of milliseconds in Long is representable as an Instant */ + for (instant in largePositiveInstants) { + assertEquals(Long.MAX_VALUE, instant.toEpochMilliseconds(), "$instant") + } + for (instant in largeNegativeInstants) { + assertEquals(Long.MIN_VALUE, instant.toEpochMilliseconds(), "$instant") + } + for (milliseconds in largePositiveLongs + largeNegativeLongs) { + assertEquals(milliseconds, Instant.fromEpochMilliseconds(milliseconds).toEpochMilliseconds(), + "$milliseconds") + } + } + + @Test + fun epochSecondsClamping() { + // fromEpochSeconds + // On all platforms Long.MAX_VALUE of seconds is not a valid instant. + for (seconds in largePositiveLongs) { + assertEquals(Instant.MAX, Instant.fromEpochSeconds(seconds, 35)) + } + for (seconds in largeNegativeLongs) { + assertEquals(Instant.MIN, Instant.fromEpochSeconds(seconds, 35)) + } + for (instant in largePositiveInstants + smallInstants + largeNegativeInstants) { + assertEquals(instant, Instant.fromEpochSeconds(instant.epochSeconds, instant.nanosecondsOfSecond.toLong())) + } + } + + @Test + fun durationArithmeticClamping() { + val longDurations = listOf(Duration.INFINITE) + + for (duration in longDurations) { + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant + duration) + } + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MIN, instant - duration) + } + } + assertEquals(Instant.MAX, (Instant.MAX - 4.seconds) + 5.seconds) + assertEquals(Instant.MIN, (Instant.MIN + 10.seconds) - 12.seconds) + } + + @Test + fun periodArithmeticOutOfRange() { + // Instant.plus(DateTimePeriod(), TimeZone) + // Arithmetic overflow + for (instant in largePositiveInstants) { + assertArithmeticFails("$instant") { instant.plus(DateTimePeriod(nanoseconds = Long.MAX_VALUE), UTC) } + } + for (instant in largeNegativeInstants) { + assertArithmeticFails("$instant") { instant.plus(DateTimePeriod(nanoseconds = Long.MIN_VALUE), UTC) } + } + // Arithmetic overflow in an Int + for (instant in smallInstants + listOf(maxValidInstant)) { + assertEquals(instant.epochSeconds + Int.MIN_VALUE, + instant.plus(Int.MIN_VALUE, DateTimeUnit.SECOND, UTC).epochSeconds) + assertEquals(instant.epochSeconds - Int.MAX_VALUE, + instant.minus(Int.MAX_VALUE, DateTimeUnit.SECOND, UTC).epochSeconds) + } + for (instant in smallInstants + listOf(minValidInstant)) { + assertEquals(instant.epochSeconds + Int.MAX_VALUE, + instant.plus(Int.MAX_VALUE, DateTimeUnit.SECOND, UTC).epochSeconds) + assertEquals(instant.epochSeconds - Int.MIN_VALUE, + instant.minus(Int.MIN_VALUE, DateTimeUnit.SECOND, UTC).epochSeconds) + } + // Overflowing a LocalDateTime in input + maxValidInstant.plus(DateTimePeriod(nanoseconds = -1), UTC) + minValidInstant.plus(DateTimePeriod(nanoseconds = 1), UTC) + assertArithmeticFails { (maxValidInstant + 1.nanoseconds).plus(DateTimePeriod(nanoseconds = -2), UTC) } + assertArithmeticFails { (minValidInstant - 1.nanoseconds).plus(DateTimePeriod(nanoseconds = 2), UTC) } + // Overflowing a LocalDateTime in result + assertArithmeticFails { maxValidInstant.plus(DateTimePeriod(nanoseconds = 1), UTC) } + assertArithmeticFails { minValidInstant.plus(DateTimePeriod(nanoseconds = -1), UTC) } + // Overflowing a LocalDateTime in intermediate computations + assertArithmeticFails { maxValidInstant.plus(DateTimePeriod(days = 1, nanoseconds = -1_000_000_001), UTC) } + assertArithmeticFails { maxValidInstant.plus(DateTimePeriod(months = 1, days = -48), UTC) } + } + + @Test + fun unitArithmeticOutOfRange() { + // Instant.plus(Long, DateTimeUnit, TimeZone) + // Arithmetic overflow + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertArithmeticFails("$instant") { instant.plus(Long.MAX_VALUE, DateTimeUnit.SECOND, UTC) } + assertArithmeticFails("$instant") { instant.plus(Long.MIN_VALUE, DateTimeUnit.SECOND, UTC) } + assertArithmeticFails("$instant") { instant.plus(Long.MAX_VALUE, DateTimeUnit.YEAR, UTC) } + assertArithmeticFails("$instant") { instant.plus(Long.MIN_VALUE, DateTimeUnit.YEAR, UTC) } + } + for (instant in smallInstants) { + instant.plus(2 * Int.MAX_VALUE.toLong(), DateTimeUnit.DAY, UTC) + instant.plus(2 * Int.MIN_VALUE.toLong(), DateTimeUnit.DAY, UTC) + instant.plus(2 * Int.MAX_VALUE.toLong(), DateTimeUnit.MONTH, UTC) + instant.plus(2 * Int.MIN_VALUE.toLong(), DateTimeUnit.MONTH, UTC) + } + // Overflowing a LocalDateTime in input + maxValidInstant.plus(-1, DateTimeUnit.NANOSECOND, UTC) + minValidInstant.plus(1, DateTimeUnit.NANOSECOND, UTC) + assertArithmeticFails { (maxValidInstant + 1.nanoseconds).plus(-2, DateTimeUnit.NANOSECOND, UTC) } + assertArithmeticFails { (minValidInstant - 1.nanoseconds).plus(2, DateTimeUnit.NANOSECOND, UTC) } + // Overflowing a LocalDateTime in result + assertArithmeticFails { maxValidInstant.plus(1, DateTimeUnit.NANOSECOND, UTC) } + assertArithmeticFails { maxValidInstant.plus(1, DateTimeUnit.YEAR, UTC) } + assertArithmeticFails { minValidInstant.plus(-1, DateTimeUnit.NANOSECOND, UTC) } + assertArithmeticFails { minValidInstant.plus(-1, DateTimeUnit.YEAR, UTC) } + } + + @Test + fun timeBasedUnitArithmeticOutOfRange() { + // Instant.plus(Long, DateTimeUnit.TimeBased) + // Arithmetic overflow + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant.plus(Long.MAX_VALUE, DateTimeUnit.SECOND)) + assertEquals(Instant.MIN, instant.plus(Long.MIN_VALUE, DateTimeUnit.SECOND)) + } + // Overflow of Instant boundaries + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant.plus(Instant.MAX.epochSeconds - instant.epochSeconds + 1, DateTimeUnit.SECOND)) + assertEquals(Instant.MIN, instant.plus(Instant.MIN.epochSeconds - instant.epochSeconds - 1, DateTimeUnit.SECOND)) + } + } + + + @Test + fun periodUntilOutOfRange() { + // Instant.periodUntil + maxValidInstant.periodUntil(maxValidInstant, UTC) + assertArithmeticFails { (maxValidInstant + 1.nanoseconds).periodUntil(maxValidInstant, UTC) } + assertArithmeticFails { minValidInstant.periodUntil(minValidInstant - 1.nanoseconds, UTC) } + } + + @Test + fun unitsUntilClamping() { + // Arithmetic overflow of the resulting number + assertEquals(Long.MAX_VALUE, minValidInstant.until(maxValidInstant, DateTimeUnit.NANOSECOND, UTC)) + assertEquals(Long.MIN_VALUE, maxValidInstant.until(minValidInstant, DateTimeUnit.NANOSECOND, UTC)) + assertEquals(Long.MAX_VALUE, minValidInstant.until(maxValidInstant, DateTimeUnit.NANOSECOND)) + assertEquals(Long.MIN_VALUE, maxValidInstant.until(minValidInstant, DateTimeUnit.NANOSECOND)) + } + + @Test + fun unitsUntilOutOfRange() { + // Instant.until + // Overflowing a LocalDateTime in input + assertArithmeticFails { (maxValidInstant + 1.nanoseconds).until(maxValidInstant, DateTimeUnit.NANOSECOND, UTC) } + assertArithmeticFails { maxValidInstant.until(maxValidInstant + 1.nanoseconds, DateTimeUnit.NANOSECOND, UTC) } + // Overloads without a TimeZone should not fail on overflowing a LocalDateTime + (maxValidInstant + 1.nanoseconds).until(maxValidInstant, DateTimeUnit.NANOSECOND) + maxValidInstant.until(maxValidInstant + 1.nanoseconds, DateTimeUnit.NANOSECOND) + } + + // https://github.com/Kotlin/kotlinx-datetime/issues/263 + @Test + fun addSmallDurationsToLargeInstants() { + for (smallDuration in listOf(1.nanoseconds, 999_999.nanoseconds, 1.seconds - 1.nanoseconds)) { + assertEquals(expected = Instant.MAX, actual = Instant.MAX + smallDuration) + assertEquals(expected = Instant.MIN, actual = Instant.MIN - smallDuration) + } + } + + @Test + fun subtractInstants() { + val max = Instant.fromEpochSeconds(31494816403199L) + val min = Instant.fromEpochSeconds(-31619119219200L) + assertEquals(max.epochSeconds - min.epochSeconds, (max - min).inWholeSeconds) + } +} diff --git a/core/common/test/InstantTest.kt b/core/common/test/InstantTest.kt index 8bc41f019..3479cc530 100644 --- a/core/common/test/InstantTest.kt +++ b/core/common/test/InstantTest.kt @@ -16,6 +16,10 @@ import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds +import kotlinx.time.Clock +import kotlinx.time.Instant +import kotlinx.time.isDistantFuture +import kotlinx.time.isDistantPast class InstantTest { @@ -59,99 +63,6 @@ class InstantTest { println(now.toLocalDateTime(TimeZone.currentSystemDefault())) } - /* Based on the ThreeTenBp project. - * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos - */ - @Test - fun parseIsoString() { - val instants = arrayOf( - Triple("1970-01-01T00:00:00Z", 0, 0), - Triple("1970-01-01t00:00:00Z", 0, 0), - Triple("1970-01-01T00:00:00z", 0, 0), - Triple("1970-01-01T00:00:00.0Z", 0, 0), - Triple("1970-01-01T00:00:00.000000000Z", 0, 0), - Triple("1970-01-01T00:00:00.000000001Z", 0, 1), - Triple("1970-01-01T00:00:00.100000000Z", 0, 100000000), - Triple("1970-01-01T00:00:01Z", 1, 0), - Triple("1970-01-01T00:01:00Z", 60, 0), - Triple("1970-01-01T00:01:01Z", 61, 0), - Triple("1970-01-01T00:01:01.000000001Z", 61, 1), - Triple("1970-01-01T01:00:00.000000000Z", 3600, 0), - Triple("1970-01-01T01:01:01.000000001Z", 3661, 1), - Triple("1970-01-02T01:01:01.100000000Z", 90061, 100000000)) - instants.forEach { - val (str, seconds, nanos) = it - val instant = Instant.parse(str) - assertEquals(seconds.toLong() * 1000 + nanos / 1000000, instant.toEpochMilliseconds()) - } - - assertInvalidFormat { Instant.parse("1970-01-01T23:59:60Z")} - assertInvalidFormat { Instant.parse("1970-01-01T24:00:00Z")} - assertInvalidFormat { Instant.parse("1970-01-01T23:59Z")} - assertInvalidFormat { Instant.parse("x") } - assertInvalidFormat { Instant.parse("12020-12-31T23:59:59.000000000Z") } - // this string represents an Instant that is currently larger than Instant.MAX any of the implementations: - assertInvalidFormat { Instant.parse("+1000000001-12-31T23:59:59.000000000Z") } - } - - @Test - fun parseStringsWithOffsets() { - val strings = arrayOf( - Pair("2020-01-01T00:01:01.02+18:00", "2019-12-31T06:01:01.020Z"), - Pair("2020-01-01T00:01:01.123456789-17:59:59", "2020-01-01T18:01:00.123456789Z"), - Pair("2020-01-01T00:01:01.010203040+17:59:59", "2019-12-31T06:01:02.010203040Z"), - Pair("2020-01-01T00:01:01.010203040+17:59", "2019-12-31T06:02:01.010203040Z"), - Pair("2020-01-01T00:01:01+00", "2020-01-01T00:01:01Z"), - ) - strings.forEach { (str, strInZ) -> - val instant = Instant.parse(str) - assertEquals(Instant.parse(strInZ), instant, str) - assertEquals(strInZ, instant.toString(), str) - } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+18:01") } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+1801") } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+0") } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+") } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01") } - assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+000000") } - - val instants = listOf( - Instant.DISTANT_FUTURE, - Instant.DISTANT_PAST, - Instant.fromEpochSeconds(0, 0)) - - val offsetStrings = listOf( - "Z", - "+03:12:14", - "-03:12:14", - "+02:35", - "-02:35", - "+04", - "-04", - ) - - val offsetFormat = UtcOffset.Format { - optional("Z") { - offsetHours() - optional { - char(':'); offsetMinutesOfHour() - optional { char(':'); offsetSecondsOfMinute() } - } - } - } - val offsets = offsetStrings.map { UtcOffset.parse(it, offsetFormat) } - - for (instant in instants) { - for (offsetIx in offsets.indices) { - val str = instant.format(DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET, offsets[offsetIx]) - val offsetString = offsets[offsetIx].toString() - assertEquals(offsetString, offsetString.commonSuffixWith(str)) - assertEquals(instant, Instant.parse(str, DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET)) - assertEquals(instant, Instant.parse(str)) - } - } - } - @Test fun instantCalendarArithmetic() { val zone = TimeZone.of("Europe/Berlin") @@ -428,9 +339,9 @@ class InstantTest { val distantFutureString = "+100000-01-01T00:00:00Z" val distantPastString = "-100001-12-31T23:59:59.999999999Z" assertEquals(distantFutureString, Instant.DISTANT_FUTURE.toString()) - assertEquals(Instant.DISTANT_FUTURE, distantFutureString.toInstant()) + assertEquals(Instant.DISTANT_FUTURE, distantFutureString.let(Instant::parse)) assertEquals(distantPastString, Instant.DISTANT_PAST.toString()) - assertEquals(Instant.DISTANT_PAST, distantPastString.toInstant()) + assertEquals(Instant.DISTANT_PAST, distantPastString.let(Instant::parse)) assertTrue(Instant.DISTANT_PAST.isDistantPast) assertTrue(Instant.DISTANT_FUTURE.isDistantFuture) assertFalse(Instant.DISTANT_PAST.isDistantFuture) @@ -638,3 +549,9 @@ class InstantRangeTest { assertEquals(max.epochSeconds - min.epochSeconds, (max - min).inWholeSeconds) } } + +private val maxInstant = Instant.fromEpochSeconds(Long.MAX_VALUE) +private val minInstant = Instant.fromEpochSeconds(Long.MIN_VALUE) + +internal val Instant.Companion.MAX get() = maxInstant +internal val Instant.Companion.MIN get() = minInstant diff --git a/core/common/test/LocalDateTest.kt b/core/common/test/LocalDateTest.kt index 6d4065626..7e47e155d 100644 --- a/core/common/test/LocalDateTest.kt +++ b/core/common/test/LocalDateTest.kt @@ -7,6 +7,7 @@ package kotlinx.datetime.test import kotlinx.datetime.* import kotlinx.datetime.internal.* +import kotlinx.time.Clock import kotlin.random.* import kotlin.test.* diff --git a/core/common/test/LocalDateTimeTest.kt b/core/common/test/LocalDateTimeTest.kt index 906ef9339..5587e0aeb 100644 --- a/core/common/test/LocalDateTimeTest.kt +++ b/core/common/test/LocalDateTimeTest.kt @@ -6,7 +6,8 @@ package kotlinx.datetime.test import kotlinx.datetime.* -import kotlinx.datetime.Clock +import kotlinx.time.Clock +import kotlinx.time.Instant import kotlin.test.* import kotlin.time.* import kotlin.time.Duration.Companion.hours @@ -50,8 +51,8 @@ class LocalDateTimeTest { val diff = with(TimeZone.UTC) { ldt2.toInstant() - ldt1.toInstant() } assertEquals(with(Duration) { 1.hours + 7.minutes - 15.seconds + 400100.microseconds }, diff) - assertFailsWith { (Instant.MAX - 3.days).toLocalDateTime(TimeZone.UTC) } - assertFailsWith { (Instant.MIN + 6.hours).toLocalDateTime(TimeZone.UTC) } + assertFailsWith { (Instant.fromEpochSeconds(Long.MAX_VALUE) - 3.days).toLocalDateTime(TimeZone.UTC) } + assertFailsWith { (Instant.fromEpochSeconds(Long.MIN_VALUE) + 6.hours).toLocalDateTime(TimeZone.UTC) } } @Test @@ -67,7 +68,7 @@ class LocalDateTimeTest { val instant = Instant.parse("2019-10-01T18:43:15.100500Z") val datetime = instant.toLocalDateTime(TimeZone.UTC) checkComponents(datetime, 2019, 10, 1, 18, 43, 15, 100500000) - assertFailsWith { Instant.MAX.toLocalDateTime(TimeZone.UTC) } + assertFailsWith { Instant.fromEpochSeconds(Long.MAX_VALUE).toLocalDateTime(TimeZone.UTC) } } @Test diff --git a/core/common/test/ReadmeTest.kt b/core/common/test/ReadmeTest.kt index 696ff1510..490cbe837 100644 --- a/core/common/test/ReadmeTest.kt +++ b/core/common/test/ReadmeTest.kt @@ -9,6 +9,8 @@ import kotlinx.datetime.* import kotlinx.datetime.format.* import kotlin.test.* import kotlin.time.* +import kotlinx.time.Clock +import kotlinx.time.Instant /** * Tests the code snippets in the README.md file. diff --git a/core/common/test/TimeZoneTest.kt b/core/common/test/TimeZoneTest.kt index f59bd2cec..add0fa443 100644 --- a/core/common/test/TimeZoneTest.kt +++ b/core/common/test/TimeZoneTest.kt @@ -9,6 +9,8 @@ package kotlinx.datetime.test import kotlinx.datetime.* import kotlin.test.* +import kotlinx.time.Clock +import kotlinx.time.Instant class TimeZoneTest { diff --git a/core/common/test/format/DateTimeComponentsFormatTest.kt b/core/common/test/format/DateTimeComponentsFormatTest.kt index 07973d757..07a5862d4 100644 --- a/core/common/test/format/DateTimeComponentsFormatTest.kt +++ b/core/common/test/format/DateTimeComponentsFormatTest.kt @@ -8,6 +8,7 @@ package kotlinx.datetime.test.format import kotlinx.datetime.* import kotlinx.datetime.format.* import kotlin.test.* +import kotlinx.time.Instant class DateTimeComponentsFormatTest { diff --git a/core/common/test/format/DateTimeComponentsTest.kt b/core/common/test/format/DateTimeComponentsTest.kt index c61841265..e5c78b850 100644 --- a/core/common/test/format/DateTimeComponentsTest.kt +++ b/core/common/test/format/DateTimeComponentsTest.kt @@ -8,6 +8,7 @@ package kotlinx.datetime.test.format import kotlinx.datetime.* import kotlinx.datetime.format.* import kotlin.test.* +import kotlinx.time.Clock class DateTimeComponentsTest { @Test diff --git a/core/common/test/samples/ClockSamples.kt b/core/common/test/samples/ClockSamples.kt index 70683efa5..862df90df 100644 --- a/core/common/test/samples/ClockSamples.kt +++ b/core/common/test/samples/ClockSamples.kt @@ -9,6 +9,8 @@ import kotlinx.datetime.* import kotlin.test.* import kotlin.time.Duration.Companion.seconds import kotlin.time.TestTimeSource +import kotlinx.time.Clock +import kotlinx.time.Instant class ClockSamples { @Test diff --git a/core/common/test/samples/DayOfWeekSamples.kt b/core/common/test/samples/DayOfWeekSamples.kt index c8393ae98..4d4e1e0cd 100644 --- a/core/common/test/samples/DayOfWeekSamples.kt +++ b/core/common/test/samples/DayOfWeekSamples.kt @@ -7,6 +7,7 @@ package kotlinx.datetime.test.samples import kotlinx.datetime.* import kotlin.test.* +import kotlinx.time.Clock class DayOfWeekSamples { diff --git a/core/common/test/samples/InstantSamples.kt b/core/common/test/samples/InstantSamples.kt index 8fec354b7..7e2a483cf 100644 --- a/core/common/test/samples/InstantSamples.kt +++ b/core/common/test/samples/InstantSamples.kt @@ -10,6 +10,10 @@ import kotlinx.datetime.format.* import kotlin.random.* import kotlin.test.* import kotlin.time.Duration.Companion.hours +import kotlinx.time.Clock +import kotlinx.time.Instant +import kotlinx.time.isDistantFuture +import kotlinx.time.isDistantPast class InstantSamples { diff --git a/core/common/test/samples/MonthSamples.kt b/core/common/test/samples/MonthSamples.kt index 70128845a..3efe3d46b 100644 --- a/core/common/test/samples/MonthSamples.kt +++ b/core/common/test/samples/MonthSamples.kt @@ -7,6 +7,7 @@ package kotlinx.datetime.test.samples import kotlinx.datetime.* import kotlin.test.* +import kotlinx.time.Clock class MonthSamples { diff --git a/core/common/test/samples/TimeZoneSamples.kt b/core/common/test/samples/TimeZoneSamples.kt index 71ef13fb6..3456a9599 100644 --- a/core/common/test/samples/TimeZoneSamples.kt +++ b/core/common/test/samples/TimeZoneSamples.kt @@ -8,6 +8,8 @@ package kotlinx.datetime.test.samples import kotlinx.datetime.* import kotlinx.datetime.format.* import kotlin.test.* +import kotlinx.time.Instant +import kotlinx.time.Clock class TimeZoneSamples { diff --git a/core/common/test/samples/format/DateTimeComponentsSamples.kt b/core/common/test/samples/format/DateTimeComponentsSamples.kt index e3e81daa9..bebe0251b 100644 --- a/core/common/test/samples/format/DateTimeComponentsSamples.kt +++ b/core/common/test/samples/format/DateTimeComponentsSamples.kt @@ -8,6 +8,7 @@ package kotlinx.datetime.test.samples.format import kotlinx.datetime.* import kotlinx.datetime.format.* import kotlin.test.* +import kotlinx.time.Instant class DateTimeComponentsSamples { diff --git a/core/commonJs/src/internal/Platform.kt b/core/commonJs/src/internal/Platform.kt index c5ba347b7..ac759d3b0 100644 --- a/core/commonJs/src/internal/Platform.kt +++ b/core/commonJs/src/internal/Platform.kt @@ -8,6 +8,7 @@ package kotlinx.datetime.internal import kotlinx.datetime.* import kotlinx.datetime.UtcOffset import kotlinx.datetime.internal.JSJoda.ZoneId +import kotlinx.time.Instant private val tzdb: Result = runCatching { /** @@ -139,10 +140,7 @@ internal fun rulesForId(zoneId: String): TimeZoneRules? = tzdb.getOrThrow()?.rul internal actual fun getAvailableZoneIds(): Set = tzdb.getOrThrow()?.availableTimeZoneIds() ?: setOf("UTC") -internal actual fun currentTime(): Instant = Instant.fromEpochMilliseconds(Date().getTime().toLong()) - internal external class Date() { constructor(milliseconds: Double) - fun getTime(): Double fun getTimezoneOffset(): Double } diff --git a/core/commonJs/test/JsJodaTimezoneTest.kt b/core/commonJs/test/JsJodaTimezoneTest.kt index 138ed28ac..635fbf749 100644 --- a/core/commonJs/test/JsJodaTimezoneTest.kt +++ b/core/commonJs/test/JsJodaTimezoneTest.kt @@ -12,6 +12,7 @@ import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.datetime.test.JSJoda.Instant as jtInstant import kotlinx.datetime.test.JSJoda.ZoneId as jtZoneId +import kotlinx.time.Instant class JsJodaTimezoneTest { @Test diff --git a/core/commonKotlin/src/DeprecatedInstant.kt b/core/commonKotlin/src/DeprecatedInstant.kt new file mode 100644 index 000000000..7818fed19 --- /dev/null +++ b/core/commonKotlin/src/DeprecatedInstant.kt @@ -0,0 +1,288 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +@file:JvmMultifileClass +@file:JvmName("InstantKt") +package kotlinx.datetime + +import kotlinx.datetime.format.* +import kotlinx.datetime.internal.* +import kotlinx.datetime.internal.MILLIS_PER_ONE +import kotlinx.datetime.internal.NANOS_PER_MILLI +import kotlinx.datetime.internal.NANOS_PER_ONE +import kotlinx.datetime.internal.safeAdd +import kotlinx.datetime.internal.safeMultiply +import kotlinx.datetime.serializers.InstantIso8601Serializer +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName +import kotlin.time.Duration +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds + +/** + * The minimum supported epoch second. + */ +private const val MIN_SECOND = -31557014167219200L // -1000000000-01-01T00:00:00Z + +/** + * The maximum supported epoch second. + */ +private const val MAX_SECOND = 31556889864403199L // +1000000000-12-31T23:59:59Z + +@Deprecated( + "Use kotlin.time.Instant instead", + ReplaceWith("kotlinx.time.Instant", "kotlinx.time.Instant"), + level = DeprecationLevel.ERROR +) +@Serializable(with = InstantIso8601Serializer::class) +public actual class Instant internal constructor(public actual val epochSeconds: Long, public actual val nanosecondsOfSecond: Int) : Comparable { + + init { + require(epochSeconds in MIN_SECOND..MAX_SECOND) { "Instant exceeds minimum or maximum instant" } + } + + // org.threeten.bp.Instant#toEpochMilli + public actual fun toEpochMilliseconds(): Long = try { + if (epochSeconds >= 0) { + val millis = safeMultiply(epochSeconds, MILLIS_PER_ONE.toLong()) + safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI).toLong()) + } else { + // prevent an overflow in seconds * 1000 + // instead of going form the second farther away from 0 + // going toward 0 + // we go from the second closer to 0 away from 0 + // that way we always stay in the valid long range + // seconds + 1 can not overflow because it is negative + val millis = safeMultiply(epochSeconds + 1, MILLIS_PER_ONE.toLong()) + safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI - MILLIS_PER_ONE).toLong()) + } + } catch (_: ArithmeticException) { + if (epochSeconds > 0) Long.MAX_VALUE else Long.MIN_VALUE + } + + // org.threeten.bp.Instant#plus(long, long) + /** + * @throws ArithmeticException if arithmetic overflow occurs + * @throws IllegalArgumentException if the boundaries of Instant are overflown + */ + internal fun plus(secondsToAdd: Long, nanosToAdd: Long): Instant { + if ((secondsToAdd or nanosToAdd) == 0L) { + return this + } + val newEpochSeconds: Long = safeAdd(safeAdd(epochSeconds, secondsToAdd), (nanosToAdd / NANOS_PER_ONE)) + val newNanosToAdd = nanosToAdd % NANOS_PER_ONE + val nanoAdjustment = (nanosecondsOfSecond + newNanosToAdd) // safe int+NANOS_PER_ONE + return fromEpochSecondsThrowing(newEpochSeconds, nanoAdjustment) + } + + public actual operator fun plus(duration: Duration): Instant = duration.toComponents { secondsToAdd, nanosecondsToAdd -> + try { + plus(secondsToAdd, nanosecondsToAdd.toLong()) + } catch (_: IllegalArgumentException) { + if (duration.isPositive()) MAX else MIN + } catch (_: ArithmeticException) { + if (duration.isPositive()) MAX else MIN + } + } + + public actual operator fun minus(duration: Duration): Instant = plus(-duration) + + public actual operator fun minus(other: Instant): Duration = + (this.epochSeconds - other.epochSeconds).seconds + // won't overflow given the instant bounds + (this.nanosecondsOfSecond - other.nanosecondsOfSecond).nanoseconds + + actual override fun compareTo(other: Instant): Int { + val s = epochSeconds.compareTo(other.epochSeconds) + if (s != 0) { + return s + } + return nanosecondsOfSecond.compareTo(other.nanosecondsOfSecond) + } + + override fun equals(other: Any?): Boolean = + this === other || other is Instant && this.epochSeconds == other.epochSeconds && this.nanosecondsOfSecond == other.nanosecondsOfSecond + + // org.threeten.bp.Instant#hashCode + override fun hashCode(): Int = + (epochSeconds xor (epochSeconds ushr 32)).toInt() + 51 * nanosecondsOfSecond + + // org.threeten.bp.format.DateTimeFormatterBuilder.InstantPrinterParser#print + actual override fun toString(): String = format(ISO_DATE_TIME_OFFSET_WITH_TRAILING_ZEROS) + + public actual companion object { + internal actual val MIN = Instant(MIN_SECOND, 0) + internal actual val MAX = Instant(MAX_SECOND, 999_999_999) + + @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) + public actual fun now(): Instant = Clock.System.now() + + // org.threeten.bp.Instant#ofEpochMilli + public actual fun fromEpochMilliseconds(epochMilliseconds: Long): Instant { + val epochSeconds = epochMilliseconds.floorDiv(MILLIS_PER_ONE.toLong()) + val nanosecondsOfSecond = (epochMilliseconds.mod(MILLIS_PER_ONE.toLong()) * NANOS_PER_MILLI).toInt() + return when { + epochSeconds < MIN_SECOND -> MIN + epochSeconds > MAX_SECOND -> MAX + else -> fromEpochSeconds(epochSeconds, nanosecondsOfSecond) + } + } + + /** + * @throws ArithmeticException if arithmetic overflow occurs + * @throws IllegalArgumentException if the boundaries of Instant are overflown + */ + private fun fromEpochSecondsThrowing(epochSeconds: Long, nanosecondAdjustment: Long): Instant { + val secs = safeAdd(epochSeconds, nanosecondAdjustment.floorDiv(NANOS_PER_ONE.toLong())) + val nos = nanosecondAdjustment.mod(NANOS_PER_ONE.toLong()).toInt() + return Instant(secs, nos) + } + + // org.threeten.bp.Instant#ofEpochSecond(long, long) + public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long): Instant = + try { + fromEpochSecondsThrowing(epochSeconds, nanosecondAdjustment) + } catch (_: ArithmeticException) { + if (epochSeconds > 0) MAX else MIN + } catch (_: IllegalArgumentException) { + if (epochSeconds > 0) MAX else MIN + } + + public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant = + fromEpochSeconds(epochSeconds, nanosecondAdjustment.toLong()) + + public actual fun parse(input: CharSequence, format: DateTimeFormat): Instant = try { + format.parse(input).toInstantUsingOffset().toDeprecatedInstant() + } catch (e: IllegalArgumentException) { + throw DateTimeFormatException("Failed to parse an instant from '$input'", e) + } + + @Deprecated("This overload is only kept for binary compatibility", level = DeprecationLevel.HIDDEN) + public fun parse(isoString: String): Instant = parse(input = isoString) + + public actual val DISTANT_PAST: Instant = fromEpochSeconds(DISTANT_PAST_SECONDS, 999_999_999) + + public actual val DISTANT_FUTURE: Instant = fromEpochSeconds(DISTANT_FUTURE_SECONDS, 0) + } + +} + +private fun Instant.toZonedDateTimeFailing(zone: TimeZone): ZonedDateTime = try { + toZonedDateTime(zone) +} catch (e: IllegalArgumentException) { + throw DateTimeArithmeticException("Can not convert instant $this to LocalDateTime to perform computations", e) +} + +/** + * @throws IllegalArgumentException if the [Instant] exceeds the boundaries of [LocalDateTime] + */ +private fun Instant.toZonedDateTime(zone: TimeZone): ZonedDateTime { + val currentOffset = zone.offsetAtImpl(this.toNewInstant()) + return ZonedDateTime(toNewInstant().toLocalDateTimeImpl(currentOffset), zone, currentOffset) +} + +/** Check that [Instant] fits in [ZonedDateTime]. + * This is done on the results of computations for consistency with other platforms. + */ +private fun Instant.check(zone: TimeZone): Instant = this@check.also { + toZonedDateTimeFailing(zone) +} + +public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Instant = try { + with(period) { + val withDate = toZonedDateTimeFailing(timeZone) + .run { if (totalMonths != 0L) plus(totalMonths, DateTimeUnit.MONTH) else this } + .run { if (days != 0) plus(days.toLong(), DateTimeUnit.DAY) else this } + withDate.toDeprecatedInstant() + .run { if (totalNanoseconds != 0L) plus(0, totalNanoseconds).check(timeZone) else this } + }.check(timeZone) +} catch (e: ArithmeticException) { + throw DateTimeArithmeticException("Arithmetic overflow when adding CalendarPeriod to an Instant", e) +} catch (e: IllegalArgumentException) { + throw DateTimeArithmeticException("Boundaries of Instant exceeded when adding CalendarPeriod", e) +} + +@Deprecated("Use the plus overload with an explicit number of units", ReplaceWith("this.plus(1, unit, timeZone)")) +public actual fun Instant.plus(unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(1L, unit, timeZone) +public actual fun Instant.plus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(value.toLong(), unit, timeZone) +public actual fun Instant.minus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(-value.toLong(), unit, timeZone) +public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZone): Instant = try { + when (unit) { + is DateTimeUnit.DateBased -> + toZonedDateTimeFailing(timeZone).plus(value, unit).toDeprecatedInstant() + is DateTimeUnit.TimeBased -> + check(timeZone).plus(value, unit).check(timeZone) + } +} catch (e: ArithmeticException) { + throw DateTimeArithmeticException("Arithmetic overflow when adding to an Instant", e) +} catch (e: IllegalArgumentException) { + throw DateTimeArithmeticException("Boundaries of Instant exceeded when adding a value", e) +} + +public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Instant = + try { + multiplyAndDivide(value, unit.nanoseconds, NANOS_PER_ONE.toLong()).let { (seconds, nanoseconds) -> + plus(seconds, nanoseconds) + } + } catch (_: ArithmeticException) { + if (value > 0) Instant.MAX else Instant.MIN + } catch (_: IllegalArgumentException) { + if (value > 0) Instant.MAX else Instant.MIN + } + +public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod { + var thisLdt = toZonedDateTimeFailing(timeZone) + val otherLdt = other.toZonedDateTimeFailing(timeZone) + + val months = thisLdt.until(otherLdt, DateTimeUnit.MONTH) // `until` on dates never fails + thisLdt = thisLdt.plus(months, DateTimeUnit.MONTH) // won't throw: thisLdt + months <= otherLdt, which is known to be valid + val days = thisLdt.until(otherLdt, DateTimeUnit.DAY) // `until` on dates never fails + thisLdt = thisLdt.plus(days, DateTimeUnit.DAY) // won't throw: thisLdt + days <= otherLdt + val nanoseconds = thisLdt.until(otherLdt, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h + + return buildDateTimePeriod(months, days.toInt(), nanoseconds) +} + +public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long = + when (unit) { + is DateTimeUnit.DateBased -> + toZonedDateTimeFailing(timeZone).dateTime.until(other.toZonedDateTimeFailing(timeZone).dateTime, unit) + .toLong() + is DateTimeUnit.TimeBased -> { + check(timeZone); other.check(timeZone) + until(other, unit) + } + } + +private fun ZonedDateTime.toDeprecatedInstant(): Instant = + Instant.fromEpochSeconds(dateTime.toEpochSecond(offset), dateTime.nanosecond) + +private val ISO_DATE_TIME_OFFSET_WITH_TRAILING_ZEROS = DateTimeComponents.Format { + date(ISO_DATE) + alternativeParsing({ + char('t') + }) { + char('T') + } + hour() + char(':') + minute() + char(':') + second() + optional { + char('.') + secondFractionInternal(1, 9, FractionalSecondDirective.GROUP_BY_THREE) + } + isoOffset( + zOnZero = true, + useSeparator = true, + outputMinute = WhenToOutput.IF_NONZERO, + outputSecond = WhenToOutput.IF_NONZERO + ) +} diff --git a/core/commonKotlin/src/Instant.kt b/core/commonKotlin/src/Instant.kt index 654302e6f..0bfa06295 100644 --- a/core/commonKotlin/src/Instant.kt +++ b/core/commonKotlin/src/Instant.kt @@ -8,14 +8,10 @@ package kotlinx.datetime -import kotlinx.datetime.format.* import kotlinx.datetime.internal.* -import kotlinx.datetime.serializers.InstantIso8601Serializer -import kotlinx.serialization.Serializable -import kotlin.time.* +import kotlinx.time.Instant import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds -import kotlin.math.absoluteValue public actual enum class DayOfWeek { MONDAY, @@ -27,412 +23,6 @@ public actual enum class DayOfWeek { SUNDAY; } -/** - * The minimum supported epoch second. - */ -private const val MIN_SECOND = -31557014167219200L // -1000000000-01-01T00:00:00Z - -/** - * The maximum supported epoch second. - */ -private const val MAX_SECOND = 31556889864403199L // +1000000000-12-31T23:59:59 - -@Serializable(with = InstantIso8601Serializer::class) -public actual class Instant internal constructor(public actual val epochSeconds: Long, public actual val nanosecondsOfSecond: Int) : Comparable { - - init { - require(epochSeconds in MIN_SECOND..MAX_SECOND) { "Instant exceeds minimum or maximum instant" } - } - - // org.threeten.bp.Instant#toEpochMilli - public actual fun toEpochMilliseconds(): Long = try { - if (epochSeconds >= 0) { - val millis = safeMultiply(epochSeconds, MILLIS_PER_ONE.toLong()) - safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI).toLong()) - } else { - // prevent an overflow in seconds * 1000 - // instead of going form the second farther away from 0 - // going toward 0 - // we go from the second closer to 0 away from 0 - // that way we always stay in the valid long range - // seconds + 1 can not overflow because it is negative - val millis = safeMultiply(epochSeconds + 1, MILLIS_PER_ONE.toLong()) - safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI - MILLIS_PER_ONE).toLong()) - } - } catch (_: ArithmeticException) { - if (epochSeconds > 0) Long.MAX_VALUE else Long.MIN_VALUE - } - - // org.threeten.bp.Instant#plus(long, long) - /** - * @throws ArithmeticException if arithmetic overflow occurs - * @throws IllegalArgumentException if the boundaries of Instant are overflown - */ - internal fun plus(secondsToAdd: Long, nanosToAdd: Long): Instant { - if ((secondsToAdd or nanosToAdd) == 0L) { - return this - } - val newEpochSeconds: Long = safeAdd(safeAdd(epochSeconds, secondsToAdd), (nanosToAdd / NANOS_PER_ONE)) - val newNanosToAdd = nanosToAdd % NANOS_PER_ONE - val nanoAdjustment = (nanosecondsOfSecond + newNanosToAdd) // safe int+NANOS_PER_ONE - return fromEpochSecondsThrowing(newEpochSeconds, nanoAdjustment) - } - - public actual operator fun plus(duration: Duration): Instant = duration.toComponents { secondsToAdd, nanosecondsToAdd -> - try { - plus(secondsToAdd, nanosecondsToAdd.toLong()) - } catch (_: IllegalArgumentException) { - if (duration.isPositive()) MAX else MIN - } catch (_: ArithmeticException) { - if (duration.isPositive()) MAX else MIN - } - } - - public actual operator fun minus(duration: Duration): Instant = plus(-duration) - - public actual operator fun minus(other: Instant): Duration = - (this.epochSeconds - other.epochSeconds).seconds + // won't overflow given the instant bounds - (this.nanosecondsOfSecond - other.nanosecondsOfSecond).nanoseconds - - actual override fun compareTo(other: Instant): Int { - val s = epochSeconds.compareTo(other.epochSeconds) - if (s != 0) { - return s - } - return nanosecondsOfSecond.compareTo(other.nanosecondsOfSecond) - } - - override fun equals(other: Any?): Boolean = - this === other || other is Instant && this.epochSeconds == other.epochSeconds && this.nanosecondsOfSecond == other.nanosecondsOfSecond - - // org.threeten.bp.Instant#hashCode - override fun hashCode(): Int = - (epochSeconds xor (epochSeconds ushr 32)).toInt() + 51 * nanosecondsOfSecond - - // org.threeten.bp.format.DateTimeFormatterBuilder.InstantPrinterParser#print - actual override fun toString(): String = format(ISO_DATE_TIME_OFFSET_WITH_TRAILING_ZEROS) - - public actual companion object { - internal actual val MIN = Instant(MIN_SECOND, 0) - internal actual val MAX = Instant(MAX_SECOND, 999_999_999) - - @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) - public actual fun now(): Instant = currentTime() - - // org.threeten.bp.Instant#ofEpochMilli - public actual fun fromEpochMilliseconds(epochMilliseconds: Long): Instant { - val epochSeconds = epochMilliseconds.floorDiv(MILLIS_PER_ONE.toLong()) - val nanosecondsOfSecond = (epochMilliseconds.mod(MILLIS_PER_ONE.toLong()) * NANOS_PER_MILLI).toInt() - return when { - epochSeconds < MIN_SECOND -> MIN - epochSeconds > MAX_SECOND -> MAX - else -> fromEpochSeconds(epochSeconds, nanosecondsOfSecond) - } - } - - /** - * @throws ArithmeticException if arithmetic overflow occurs - * @throws IllegalArgumentException if the boundaries of Instant are overflown - */ - private fun fromEpochSecondsThrowing(epochSeconds: Long, nanosecondAdjustment: Long): Instant { - val secs = safeAdd(epochSeconds, nanosecondAdjustment.floorDiv(NANOS_PER_ONE.toLong())) - val nos = nanosecondAdjustment.mod(NANOS_PER_ONE.toLong()).toInt() - return Instant(secs, nos) - } - - // org.threeten.bp.Instant#ofEpochSecond(long, long) - public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long): Instant = - try { - fromEpochSecondsThrowing(epochSeconds, nanosecondAdjustment) - } catch (_: ArithmeticException) { - if (epochSeconds > 0) MAX else MIN - } catch (_: IllegalArgumentException) { - if (epochSeconds > 0) MAX else MIN - } - - public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant = - fromEpochSeconds(epochSeconds, nanosecondAdjustment.toLong()) - - public actual fun parse(input: CharSequence, format: DateTimeFormat): Instant = try { - format.parse(input).toInstantUsingOffset() - } catch (e: IllegalArgumentException) { - throw DateTimeFormatException("Failed to parse an instant from '$input'", e) - } - - @Deprecated("This overload is only kept for binary compatibility", level = DeprecationLevel.HIDDEN) - public fun parse(isoString: String): Instant = parse(input = isoString) - - public actual val DISTANT_PAST: Instant = fromEpochSeconds(DISTANT_PAST_SECONDS, 999_999_999) - - public actual val DISTANT_FUTURE: Instant = fromEpochSeconds(DISTANT_FUTURE_SECONDS, 0) - } - -} - -private class UnboundedLocalDateTime( - val year: Int, - val month: Int, - val day: Int, - val hour: Int, - val minute: Int, - val second: Int, - val nanosecond: Int, -) { - fun toInstant(offsetSeconds: Int): Instant { - val epochSeconds = run { - // org.threeten.bp.LocalDate#toEpochDay - val epochDays = run { - val y = year.toLong() - var total = 365 * y - if (y >= 0) { - total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400 - } else { - total -= y / -4 - y / -100 + y / -400 - } - total += ((367 * month - 362) / 12) - total += day - 1 - if (month > 2) { - total-- - if (!isLeapYear(year)) { - total-- - } - } - total - DAYS_0000_TO_1970 - } - // org.threeten.bp.LocalTime#toSecondOfDay - val daySeconds = hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second - // org.threeten.bp.chrono.ChronoLocalDateTime#toEpochSecond - epochDays * 86400L + daySeconds - offsetSeconds - } - if (epochSeconds < Instant.MIN.epochSeconds || epochSeconds > Instant.MAX.epochSeconds) - throw DateTimeFormatException( - "The parsed date is outside the range representable by Instant (Unix epoch second $epochSeconds)" - ) - return Instant.fromEpochSeconds(epochSeconds, nanosecond) - } - - override fun toString(): String = "UnboundedLocalDateTime($year-$month-$day $hour:$minute:$second.$nanosecond)" - - companion object { - fun fromInstant(instant: Instant, offsetSeconds: Int): UnboundedLocalDateTime { - val localSecond: Long = instant.epochSeconds + offsetSeconds - val epochDays = localSecond.floorDiv(SECONDS_PER_DAY.toLong()) - val secsOfDay = localSecond.mod(SECONDS_PER_DAY.toLong()).toInt() - val year: Int - val month: Int - val day: Int - // org.threeten.bp.LocalDate#toEpochDay - run { - var zeroDay = epochDays + DAYS_0000_TO_1970 - // find the march-based year - zeroDay -= 60 // adjust to 0000-03-01 so leap day is at end of four year cycle - - var adjust = 0L - if (zeroDay < 0) { // adjust negative years to positive for calculation - val adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1 - adjust = adjustCycles * 400 - zeroDay += -adjustCycles * DAYS_PER_CYCLE - } - var yearEst = ((400 * zeroDay.toLong() + 591) / DAYS_PER_CYCLE) - var doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400) - if (doyEst < 0) { // fix estimate - yearEst-- - doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400) - } - yearEst += adjust // reset any negative year - - val marchDoy0 = doyEst.toInt() - - // convert march-based values back to january-based - val marchMonth0 = (marchDoy0 * 5 + 2) / 153 - month = (marchMonth0 + 2) % 12 + 1 - day = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1 - year = (yearEst + marchMonth0 / 10).toInt() - } - val hours = (secsOfDay / SECONDS_PER_HOUR) - val secondWithoutHours = secsOfDay - hours * SECONDS_PER_HOUR - val minutes = (secondWithoutHours / SECONDS_PER_MINUTE) - val second = secondWithoutHours - minutes * SECONDS_PER_MINUTE - return UnboundedLocalDateTime(year, month, day, hours, minutes, second, instant.nanosecondsOfSecond) - } - } -} - -internal fun parseIso(isoString: String): Instant { - fun parseFailure(error: String): Nothing { - throw IllegalArgumentException("$error when parsing an Instant from $isoString") - } - inline fun expect(what: String, where: Int, predicate: (Char) -> Boolean) { - val c = isoString[where] - if (!predicate(c)) { - parseFailure("Expected $what, but got $c at position $where") - } - } - val s = isoString - var i = 0 - require(s.isNotEmpty()) { "An empty string is not a valid Instant" } - val yearSign = when (val c = s[i]) { - '+', '-' -> { ++i; c } - else -> ' ' - } - val yearStart = i - var absYear = 0 - while (i < s.length && s[i] in '0'..'9') { - absYear = absYear * 10 + (s[i] - '0') - ++i - } - val year = when { - i > yearStart + 10 -> { - parseFailure("Expected at most 10 digits for the year number, got ${i - yearStart} digits") - } - i == yearStart + 10 && s[yearStart] >= '2' -> { - parseFailure("Expected at most 9 digits for the year number or year 1000000000, got ${i - yearStart} digits") - } - i - yearStart < 4 -> { - parseFailure("The year number must be padded to 4 digits, got ${i - yearStart} digits") - } - else -> { - if (yearSign == '+' && i - yearStart == 4) { - parseFailure("The '+' sign at the start is only valid for year numbers longer than 4 digits") - } - if (yearSign == ' ' && i - yearStart != 4) { - parseFailure("A '+' or '-' sign is required for year numbers longer than 4 digits") - } - if (yearSign == '-') -absYear else absYear - } - } - // reading at least -MM-DDTHH:MM:SSZ - // 0123456789012345 16 chars - if (s.length < i + 16) { - parseFailure("The input string is too short") - } - expect("'-'", i) { it == '-' } - expect("'-'", i + 3) { it == '-' } - expect("'T' or 't'", i + 6) { it == 'T' || it == 't' } - expect("':'", i + 9) { it == ':' } - expect("':'", i + 12) { it == ':' } - for (j in asciiDigitPositionsInIsoStringAfterYear) { - expect("an ASCII digit", i + j) { it in '0'..'9' } - } - fun twoDigitNumber(index: Int) = (s[index] - '0') * 10 + (s[index + 1] - '0') - val month = twoDigitNumber(i + 1) - val day = twoDigitNumber(i + 4) - val hour = twoDigitNumber(i + 7) - val minute = twoDigitNumber(i + 10) - val second = twoDigitNumber(i + 13) - val nanosecond = if (s[i + 15] == '.') { - val fractionStart = i + 16 - i = fractionStart - var fraction = 0 - while (i < s.length && s[i] in '0'..'9') { - fraction = fraction * 10 + (s[i] - '0') - ++i - } - if (i - fractionStart in 1..9) { - fraction * POWERS_OF_TEN[fractionStart + 9 - i] - } else { - parseFailure("1..9 digits are supported for the fraction of the second, got {i - fractionStart}") - } - } else { - i += 15 - 0 - } - val offsetSeconds = when (val sign = s.getOrNull(i)) { - null -> { - parseFailure("The UTC offset at the end of the string is missing") - } - 'z', 'Z' -> if (s.length == i + 1) { - 0 - } else { - parseFailure("Extra text after the instant at position ${i + 1}") - } - '-', '+' -> { - val offsetStrLength = s.length - i - if (offsetStrLength % 3 != 0) { parseFailure("Invalid UTC offset string '${s.substring(i)}'") } - if (offsetStrLength > 9) { parseFailure("The UTC offset string '${s.substring(i)}' is too long") } - for (j in colonsInIsoOffsetString) { - if (s.getOrNull(i + j) ?: break != ':') - parseFailure("Expected ':' at index ${i + j}, got '${s[i + j]}'") - } - for (j in asciiDigitsInIsoOffsetString) { - if (s.getOrNull(i + j) ?: break !in '0'..'9') - parseFailure("Expected a digit at index ${i + j}, got '${s[i + j]}'") - } - val offsetHour = twoDigitNumber(i + 1) - val offsetMinute = if (offsetStrLength > 3) { twoDigitNumber(i + 4) } else { 0 } - val offsetSecond = if (offsetStrLength > 6) { twoDigitNumber(i + 7) } else { 0 } - if (offsetMinute > 59) { parseFailure("Expected offset-minute-of-hour in 0..59, got $offsetMinute") } - if (offsetSecond > 59) { parseFailure("Expected offset-second-of-minute in 0..59, got $offsetSecond") } - if (offsetHour > 17 && !(offsetHour == 18 && offsetMinute == 0 && offsetSecond == 0)) { - parseFailure("Expected an offset in -18:00..+18:00, got $sign$offsetHour:$offsetMinute:$offsetSecond") - } - (offsetHour * 3600 + offsetMinute * 60 + offsetSecond) * if (sign == '-') -1 else 1 - } - else -> { - parseFailure("Expected the UTC offset at position $i, got '$sign'") - } - } - if (month !in 1..12) { parseFailure("Expected a month number in 1..12, got $month") } - if (day !in 1..month.monthLength(isLeapYear(year))) { - parseFailure("Expected a valid day-of-month for $year-$month, got $day") - } - if (hour > 23) { parseFailure("Expected hour in 0..23, got $hour") } - if (minute > 59) { parseFailure("Expected minute-of-hour in 0..59, got $minute") } - if (second > 59) { parseFailure("Expected second-of-minute in 0..59, got $second") } - return UnboundedLocalDateTime(year, month, day, hour, minute, second, nanosecond).toInstant(offsetSeconds) -} - -private val asciiDigitPositionsInIsoStringAfterYear by lazy { listOf(1, 2, 4, 5, 7, 8, 10, 11, 13, 14) } -private val colonsInIsoOffsetString by lazy { listOf(3, 6) } -private val asciiDigitsInIsoOffsetString by lazy { listOf(1, 2, 4, 5, 7, 8) } - -internal fun formatIso(instant: Instant): String = buildString { - val ldt = UnboundedLocalDateTime.fromInstant(instant, 0) - fun Appendable.appendTwoDigits(number: Int) { - if (number < 10) append('0') - append(number) - } - run { - val number = ldt.year - when { - number.absoluteValue < 1_000 -> { - val innerBuilder = StringBuilder() - if (number >= 0) { - innerBuilder.append((number + 10_000)).deleteAt(0) - } else { - innerBuilder.append((number - 10_000)).deleteAt(1) - } - append(innerBuilder) - } - else -> { - if (number >= 10_000) append('+') - append(number) - } - } - } - append('-') - appendTwoDigits(ldt.month) - append('-') - appendTwoDigits(ldt.day) - append('T') - appendTwoDigits(ldt.hour) - append(':') - appendTwoDigits(ldt.minute) - append(':') - appendTwoDigits(ldt.second) - if (ldt.nanosecond != 0) { - append('.') - var zerosToStrip = 0 - while (ldt.nanosecond % POWERS_OF_TEN[zerosToStrip + 1] == 0) { - ++zerosToStrip - } - zerosToStrip -= zerosToStrip % 3 // rounding down to a multiple of 3 - val numberToOutput = ldt.nanosecond / POWERS_OF_TEN[zerosToStrip] - append((numberToOutput + POWERS_OF_TEN[9 - zerosToStrip]).toString().substring(1)) - } - append('Z') -} - private fun Instant.toZonedDateTimeFailing(zone: TimeZone): ZonedDateTime = try { toZonedDateTime(zone) } catch (e: IllegalArgumentException) { @@ -460,7 +50,14 @@ public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Inst .run { if (totalMonths != 0L) plus(totalMonths, DateTimeUnit.MONTH) else this } .run { if (days != 0) plus(days.toLong(), DateTimeUnit.DAY) else this } withDate.toInstant() - .run { if (totalNanoseconds != 0L) plus(0, totalNanoseconds).check(timeZone) else this } + .run { + if (totalNanoseconds != 0L) + // we don't add nanoseconds directly, as `totalNanoseconds.nanoseconds` can hit `Duration.INFINITE` + plus((totalNanoseconds / NANOS_PER_ONE).seconds) + .plus((totalNanoseconds % NANOS_PER_ONE).nanoseconds) + .check(timeZone) + else this + } }.check(timeZone) } catch (e: ArithmeticException) { throw DateTimeArithmeticException("Arithmetic overflow when adding CalendarPeriod to an Instant", e) @@ -491,12 +88,12 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Instant = try { multiplyAndDivide(value, unit.nanoseconds, NANOS_PER_ONE.toLong()).let { (seconds, nanoseconds) -> - plus(seconds, nanoseconds) + plus(seconds.seconds).plus(nanoseconds.nanoseconds) } } catch (_: ArithmeticException) { - if (value > 0) Instant.MAX else Instant.MIN + Instant.fromEpochSeconds(if (value > 0) Long.MAX_VALUE else Long.MIN_VALUE) } catch (_: IllegalArgumentException) { - if (value > 0) Instant.MAX else Instant.MIN + Instant.fromEpochSeconds(if (value > 0) Long.MAX_VALUE else Long.MIN_VALUE) } public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod { @@ -522,27 +119,3 @@ public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: Ti until(other, unit) } } - -private val ISO_DATE_TIME_OFFSET_WITH_TRAILING_ZEROS = DateTimeComponents.Format { - date(ISO_DATE) - alternativeParsing({ - char('t') - }) { - char('T') - } - hour() - char(':') - minute() - char(':') - second() - optional { - char('.') - secondFractionInternal(1, 9, FractionalSecondDirective.GROUP_BY_THREE) - } - isoOffset( - zOnZero = true, - useSeparator = true, - outputMinute = WhenToOutput.IF_NONZERO, - outputSecond = WhenToOutput.IF_NONZERO - ) -} diff --git a/core/commonKotlin/src/TimeZone.kt b/core/commonKotlin/src/TimeZone.kt index 4aa6aa5e3..76256a263 100644 --- a/core/commonKotlin/src/TimeZone.kt +++ b/core/commonKotlin/src/TimeZone.kt @@ -12,6 +12,7 @@ import kotlinx.datetime.format.* import kotlinx.datetime.internal.* import kotlinx.datetime.serializers.* import kotlinx.serialization.Serializable +import kotlinx.time.Instant @Serializable(with = TimeZoneSerializer::class) public actual open class TimeZone internal constructor() { @@ -80,7 +81,20 @@ public actual open class TimeZone internal constructor() { get() = error("Should be overridden") public actual fun Instant.toLocalDateTime(): LocalDateTime = instantToLocalDateTime(this) - public actual fun LocalDateTime.toInstant(): Instant = localDateTimeToInstant(this) + public actual fun LocalDateTime.toInstant(deprecationMarker: DeprecationMarker): Instant = + localDateTimeToInstant(this) + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal actual fun kotlinx.datetime.Instant.toLocalDateTime(): LocalDateTime = + toNewInstant().toLocalDateTime() + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal actual fun LocalDateTime.toInstant(): kotlinx.datetime.Instant = + toInstant(this@TimeZone).toDeprecatedInstant() internal open fun atStartOfDay(date: LocalDate): Instant = error("Should be overridden") //value.atStartOfDay(date) internal open fun offsetAtImpl(instant: Instant): UtcOffset = error("Should be overridden") @@ -147,13 +161,13 @@ internal fun Instant.toLocalDateTimeImpl(offset: UtcOffset): LocalDateTime { return LocalDateTime(date, time) } -public actual fun LocalDateTime.toInstant(timeZone: TimeZone): Instant = +public actual fun LocalDateTime.toInstant(timeZone: TimeZone, deprecationMarker: DeprecationMarker): Instant = timeZone.localDateTimeToInstant(this) -public actual fun LocalDateTime.toInstant(offset: UtcOffset): Instant = - Instant(this.toEpochSecond(offset), this.nanosecond) +public actual fun LocalDateTime.toInstant(offset: UtcOffset, deprecationMarker: DeprecationMarker): Instant = + Instant.fromEpochSeconds(this.toEpochSecond(offset), this.nanosecond) -public actual fun LocalDate.atStartOfDayIn(timeZone: TimeZone): Instant = +public actual fun LocalDate.atStartOfDayIn(timeZone: TimeZone, deprecationMarker: DeprecationMarker): Instant = timeZone.atStartOfDay(this) private val lenientOffsetFormat = UtcOffsetFormat.build { diff --git a/core/commonKotlin/src/ZonedDateTime.kt b/core/commonKotlin/src/ZonedDateTime.kt index effd5acd0..c10011ded 100644 --- a/core/commonKotlin/src/ZonedDateTime.kt +++ b/core/commonKotlin/src/ZonedDateTime.kt @@ -8,6 +8,8 @@ package kotlinx.datetime +import kotlinx.time.Instant + internal class ZonedDateTime(val dateTime: LocalDateTime, private val zone: TimeZone, val offset: UtcOffset) { /** * @throws IllegalArgumentException if the result exceeds the boundaries @@ -46,7 +48,7 @@ internal class ZonedDateTime(val dateTime: LocalDateTime, private val zone: Time } internal fun ZonedDateTime.toInstant(): Instant = - Instant(dateTime.toEpochSecond(offset), dateTime.nanosecond) + Instant.fromEpochSeconds(dateTime.toEpochSecond(offset), dateTime.nanosecond) // org.threeten.bp.ZonedDateTime#until diff --git a/core/commonKotlin/src/internal/MonthDayTime.kt b/core/commonKotlin/src/internal/MonthDayTime.kt index 65d331dd9..4be2e994f 100644 --- a/core/commonKotlin/src/internal/MonthDayTime.kt +++ b/core/commonKotlin/src/internal/MonthDayTime.kt @@ -6,6 +6,7 @@ package kotlinx.datetime.internal import kotlinx.datetime.* +import kotlinx.time.Instant /** * A rule expressing how to create a date in a given year. diff --git a/core/commonKotlin/src/internal/OffsetInfo.kt b/core/commonKotlin/src/internal/OffsetInfo.kt index a89946da8..4685475dc 100644 --- a/core/commonKotlin/src/internal/OffsetInfo.kt +++ b/core/commonKotlin/src/internal/OffsetInfo.kt @@ -6,6 +6,7 @@ package kotlinx.datetime.internal import kotlinx.datetime.* +import kotlinx.time.Instant internal sealed interface OffsetInfo { data class Gap( @@ -43,4 +44,3 @@ internal fun OffsetInfo(transitionInstant: Instant, offsetBefore: UtcOffset, off } else { OffsetInfo.Overlap(transitionInstant, offsetBefore, offsetAfter) } - diff --git a/core/commonKotlin/src/internal/Platform.kt b/core/commonKotlin/src/internal/Platform.kt index 8227af253..d941eeded 100644 --- a/core/commonKotlin/src/internal/Platform.kt +++ b/core/commonKotlin/src/internal/Platform.kt @@ -5,7 +5,6 @@ package kotlinx.datetime.internal -import kotlinx.datetime.Instant import kotlinx.datetime.TimeZone internal expect fun timeZoneById(zoneId: String): TimeZone @@ -13,5 +12,3 @@ internal expect fun timeZoneById(zoneId: String): TimeZone internal expect fun getAvailableZoneIds(): Set internal expect fun currentSystemDefaultZone(): Pair - -internal expect fun currentTime(): Instant diff --git a/core/commonKotlin/src/internal/RegionTimeZone.kt b/core/commonKotlin/src/internal/RegionTimeZone.kt index d4e7bc6b6..9bec9e27f 100644 --- a/core/commonKotlin/src/internal/RegionTimeZone.kt +++ b/core/commonKotlin/src/internal/RegionTimeZone.kt @@ -6,6 +6,7 @@ package kotlinx.datetime.internal import kotlinx.datetime.* +import kotlinx.time.Instant internal class RegionTimeZone(private val tzid: TimeZoneRules, override val id: String) : TimeZone() { diff --git a/core/commonKotlin/src/internal/TimeZoneRules.kt b/core/commonKotlin/src/internal/TimeZoneRules.kt index 0d56aceb7..0c9bd948a 100644 --- a/core/commonKotlin/src/internal/TimeZoneRules.kt +++ b/core/commonKotlin/src/internal/TimeZoneRules.kt @@ -5,8 +5,11 @@ package kotlinx.datetime.internal -import kotlinx.datetime.* +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.UtcOffset +import kotlinx.datetime.toLocalDateTime import kotlin.math.* +import kotlinx.time.Instant internal class TimeZoneRules( /** diff --git a/core/commonKotlin/test/TimeZoneRulesTest.kt b/core/commonKotlin/test/TimeZoneRulesTest.kt index c4666a62b..03742b2d7 100644 --- a/core/commonKotlin/test/TimeZoneRulesTest.kt +++ b/core/commonKotlin/test/TimeZoneRulesTest.kt @@ -8,6 +8,7 @@ package kotlinx.datetime.test import kotlinx.datetime.* import kotlinx.datetime.internal.* import kotlin.test.* +import kotlinx.time.Instant class TimeZoneRulesTest { @Test diff --git a/core/darwin/src/Converters.kt b/core/darwin/src/Converters.kt index 6ffdfe653..7f9df981d 100644 --- a/core/darwin/src/Converters.kt +++ b/core/darwin/src/Converters.kt @@ -10,6 +10,7 @@ package kotlinx.datetime import kotlinx.cinterop.* import kotlinx.datetime.internal.NANOS_PER_ONE import platform.Foundation.* +import kotlinx.time.Instant /** * Converts the [Instant] to an instance of [NSDate]. @@ -25,6 +26,10 @@ public fun Instant.toNSDate(): NSDate { return NSDate.dateWithTimeIntervalSince1970(secs) } +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun kotlinx.datetime.Instant.toNSDate(): NSDate = toNewInstant().toNSDate() + /** * Converts the [NSDate] to the corresponding [Instant]. * @@ -33,13 +38,19 @@ public fun Instant.toNSDate(): NSDate { * For example, if the [NSDate] only has millisecond or microsecond precision logically, * due to conversion artifacts in [Double] values, the result may include non-zero nanoseconds. */ -public fun NSDate.toKotlinInstant(): Instant { +public fun NSDate.toKotlinInstant(deprecationMarker: DeprecationMarker = DeprecationMarker.INSTANCE): Instant { val secs = timeIntervalSince1970() val fullSeconds = secs.toLong() val nanos = (secs - fullSeconds) * NANOS_PER_ONE return Instant.fromEpochSeconds(fullSeconds, nanos.toLong()) } +@PublishedApi +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") +@kotlin.internal.LowPriorityInOverloadResolution +internal fun NSDate.toKotlinInstant(): kotlinx.datetime.Instant = + toKotlinInstant().toDeprecatedInstant() + /** * Converts the [TimeZone] to [NSTimeZone]. * diff --git a/core/darwin/test/ConvertersTest.kt b/core/darwin/test/ConvertersTest.kt index 9efe07750..38ccb959c 100644 --- a/core/darwin/test/ConvertersTest.kt +++ b/core/darwin/test/ConvertersTest.kt @@ -11,6 +11,8 @@ import platform.Foundation.* import kotlin.math.* import kotlin.random.* import kotlin.test.* +import kotlinx.time.Clock +import kotlinx.time.Instant class ConvertersTest { diff --git a/core/js/src/DeprecatedConverters.kt b/core/js/src/DeprecatedConverters.kt new file mode 100644 index 000000000..544e2abc9 --- /dev/null +++ b/core/js/src/DeprecatedConverters.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2019-2022 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +package kotlinx.datetime + +import kotlin.js.* + +/** + * Converts the [Instant] to an instance of JS [Date]. + * + * The conversion is lossy: JS uses millisecond precision to represent dates, and [Instant] allows for nanosecond + * resolution. + */ +public fun Instant.toJSDate(): Date = Date(milliseconds = toEpochMilliseconds().toDouble()) + +/** + * Converts the JS [Date] to the corresponding [Instant]. + */ +public fun Date.toKotlinInstant(): Instant = Instant.fromEpochMilliseconds(getTime().toLong()) diff --git a/core/js/test/JsConverterTest.kt b/core/js/test/DeprecatedJsConverterTest.kt similarity index 92% rename from core/js/test/JsConverterTest.kt rename to core/js/test/DeprecatedJsConverterTest.kt index de5eeb6f3..f90b33d0e 100644 --- a/core/js/test/JsConverterTest.kt +++ b/core/js/test/DeprecatedJsConverterTest.kt @@ -3,13 +3,14 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:Suppress("DEPRECATION_ERROR") package kotlinx.datetime.test import kotlinx.datetime.* import kotlin.js.* import kotlin.test.* -class JsConverterTest { +class DeprecatedJsConverterTest { @Test fun toJSDateTest() { val releaseInstant = Instant.parse("2016-02-15T00:00:00Z") diff --git a/core/jvm/src/Converters.kt b/core/jvm/src/Converters.kt index 6db8339d3..751c87230 100644 --- a/core/jvm/src/Converters.kt +++ b/core/jvm/src/Converters.kt @@ -8,12 +8,17 @@ package kotlinx.datetime /** * Converts this [kotlinx.datetime.Instant][Instant] value to a [java.time.Instant][java.time.Instant] value. */ -public fun Instant.toJavaInstant(): java.time.Instant = this.value +@PublishedApi +@Suppress("DEPRECATION_ERROR") +internal fun Instant.toJavaInstant(): java.time.Instant = this.value /** * Converts this [java.time.Instant][java.time.Instant] value to a [kotlinx.datetime.Instant][Instant] value. */ -public fun java.time.Instant.toKotlinInstant(): Instant = Instant(this) +@PublishedApi +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") +@kotlin.internal.LowPriorityInOverloadResolution +internal fun java.time.Instant.toKotlinInstant(): Instant = Instant(this) /** @@ -92,4 +97,3 @@ public fun UtcOffset.toJavaZoneOffset(): java.time.ZoneOffset = this.zoneOffset * Converts this [java.time.ZoneOffset][java.time.ZoneOffset] value to a [kotlinx.datetime.UtcOffset][UtcOffset] value. */ public fun java.time.ZoneOffset.toKotlinUtcOffset(): UtcOffset = UtcOffset(this) - diff --git a/core/jvm/src/DeprecatedInstant.kt b/core/jvm/src/DeprecatedInstant.kt new file mode 100644 index 000000000..05ab31e7d --- /dev/null +++ b/core/jvm/src/DeprecatedInstant.kt @@ -0,0 +1,190 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +@file:Suppress("DEPRECATION_ERROR") +@file:JvmMultifileClass +@file:JvmName("InstantJvmKt") +package kotlinx.datetime + +import kotlinx.datetime.format.DateTimeComponents +import kotlinx.datetime.format.DateTimeFormat +import kotlinx.datetime.internal.NANOS_PER_ONE +import kotlinx.datetime.internal.multiplyAndDivide +import kotlinx.datetime.internal.safeMultiply +import kotlinx.datetime.serializers.InstantIso8601Serializer +import kotlinx.serialization.Serializable +import java.time.Clock +import java.time.DateTimeException +import java.time.temporal.ChronoUnit +import kotlin.time.Duration +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds + +@Deprecated( + "Use kotlin.time.Instant instead", + ReplaceWith("kotlinx.time.Instant", "kotlinx.time.Instant"), + level = DeprecationLevel.ERROR +) +@Serializable(with = InstantIso8601Serializer::class) +public actual class Instant internal constructor(internal val value: java.time.Instant) : Comparable { + + public actual val epochSeconds: Long + get() = value.epochSecond + public actual val nanosecondsOfSecond: Int + get() = value.nano + + public actual fun toEpochMilliseconds(): Long = try { + value.toEpochMilli() + } catch (e: ArithmeticException) { + if (value.isAfter(java.time.Instant.EPOCH)) Long.MAX_VALUE else Long.MIN_VALUE + } + + public actual operator fun plus(duration: Duration): Instant = duration.toComponents { seconds, nanoseconds -> + try { + Instant(value.plusSeconds(seconds).plusNanos(nanoseconds.toLong())) + } catch (e: java.lang.Exception) { + if (e !is ArithmeticException && e !is DateTimeException) throw e + if (duration.isPositive()) MAX else MIN + } + } + + public actual operator fun minus(duration: Duration): Instant = plus(-duration) + + public actual operator fun minus(other: Instant): Duration = + (this.value.epochSecond - other.value.epochSecond).seconds + // won't overflow given the instant bounds + (this.value.nano - other.value.nano).nanoseconds + + public actual override operator fun compareTo(other: Instant): Int = this.value.compareTo(other.value) + + override fun equals(other: Any?): Boolean = + (this === other) || (other is Instant && this.value == other.value) + + override fun hashCode(): Int = value.hashCode() + + actual override fun toString(): String = value.toString() + + public actual companion object { + @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) + public actual fun now(): Instant = + Instant(Clock.systemUTC().instant()) + + public actual fun fromEpochMilliseconds(epochMilliseconds: Long): Instant = + Instant(java.time.Instant.ofEpochMilli(epochMilliseconds)) + + // TODO: implement a custom parser to 1) help DCE get rid of the formatting machinery 2) move Instant to stdlib + public actual fun parse(input: CharSequence, format: DateTimeFormat): Instant = try { + /** + * Can't use built-in Java Time's handling of `Instant.parse` because it supports 24:00:00 and + * 23:59:60, and also doesn't support non-`Z` UTC offsets on older JDKs. + * Can't use custom Java Time's formats because Java 8 doesn't support the UTC offset format with + * optional minutes and seconds and `:` between them: + * https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendOffset-java.lang.String-java.lang.String- + */ + format.parse(input).toInstantUsingOffset().toDeprecatedInstant() + } catch (e: IllegalArgumentException) { + throw DateTimeFormatException("Failed to parse an instant from '$input'", e) + } + + @Deprecated("This overload is only kept for binary compatibility", level = DeprecationLevel.HIDDEN) + public fun parse(isoString: String): Instant = parse(input = isoString) + + public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long): Instant = try { + Instant(java.time.Instant.ofEpochSecond(epochSeconds, nanosecondAdjustment)) + } catch (e: Exception) { + if (e !is ArithmeticException && e !is DateTimeException) throw e + if (epochSeconds > 0) MAX else MIN + } + + public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant = + fromEpochSeconds(epochSeconds, nanosecondAdjustment.toLong()) + + public actual val DISTANT_PAST: Instant = Instant(java.time.Instant.ofEpochSecond(DISTANT_PAST_SECONDS, 999_999_999)) + public actual val DISTANT_FUTURE: Instant = Instant(java.time.Instant.ofEpochSecond(DISTANT_FUTURE_SECONDS, 0)) + + internal actual val MIN: Instant = Instant(java.time.Instant.MIN) + internal actual val MAX: Instant = Instant(java.time.Instant.MAX) + } +} + +private fun Instant.atZone(zone: TimeZone): java.time.ZonedDateTime = try { + value.atZone(zone.zoneId) +} catch (e: DateTimeException) { + throw DateTimeArithmeticException(e) +} + +public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Instant { + try { + val thisZdt = atZone(timeZone) + return with(period) { + thisZdt + .run { if (totalMonths != 0L) plusMonths(totalMonths) else this } + .run { if (days != 0) plusDays(days.toLong()) else this } + .run { if (totalNanoseconds != 0L) plusNanos(totalNanoseconds) else this } + }.toInstant().let(::Instant) + } catch (e: DateTimeException) { + throw DateTimeArithmeticException(e) + } +} + +@Deprecated("Use the plus overload with an explicit number of units", ReplaceWith("this.plus(1, unit, timeZone)")) +public actual fun Instant.plus(unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(1L, unit, timeZone) + +public actual fun Instant.plus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(value.toLong(), unit, timeZone) + +public actual fun Instant.minus(value: Int, unit: DateTimeUnit, timeZone: TimeZone): Instant = + plus(-value.toLong(), unit, timeZone) + +public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZone): Instant = + try { + val thisZdt = atZone(timeZone) + when (unit) { + is DateTimeUnit.TimeBased -> + plus(value, unit).value.also { it.atZone(timeZone.zoneId) } + is DateTimeUnit.DayBased -> + thisZdt.plusDays(safeMultiply(value, unit.days.toLong())).toInstant() + is DateTimeUnit.MonthBased -> + thisZdt.plusMonths(safeMultiply(value, unit.months.toLong())).toInstant() + }.let(::Instant) + } catch (e: Exception) { + if (e !is DateTimeException && e !is ArithmeticException) throw e + throw DateTimeArithmeticException("Instant $this cannot be represented as local date when adding $value $unit to it", e) + } + +public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Instant = + try { + multiplyAndDivide(value, unit.nanoseconds, NANOS_PER_ONE.toLong()).let { (d, r) -> + Instant(this.value.plusSeconds(d).plusNanos(r)) + } + } catch (e: Exception) { + if (e !is DateTimeException && e !is ArithmeticException) throw e + if (value > 0) Instant.MAX else Instant.MIN + } + +public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod { + var thisZdt = this.atZone(timeZone) + val otherZdt = other.atZone(timeZone) + + val months = thisZdt.until(otherZdt, ChronoUnit.MONTHS); thisZdt = thisZdt.plusMonths(months) + val days = thisZdt.until(otherZdt, ChronoUnit.DAYS); thisZdt = thisZdt.plusDays(days) + val nanoseconds = thisZdt.until(otherZdt, ChronoUnit.NANOS) + + return buildDateTimePeriod(months, days.toInt(), nanoseconds) +} + +public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long = try { + val thisZdt = this.atZone(timeZone) + val otherZdt = other.atZone(timeZone) + when(unit) { + is DateTimeUnit.TimeBased -> until(other, unit) + is DateTimeUnit.DayBased -> thisZdt.until(otherZdt, ChronoUnit.DAYS) / unit.days + is DateTimeUnit.MonthBased -> thisZdt.until(otherZdt, ChronoUnit.MONTHS) / unit.months + } +} catch (e: DateTimeException) { + throw DateTimeArithmeticException(e) +} catch (e: ArithmeticException) { + if (this.value < other.value) Long.MAX_VALUE else Long.MIN_VALUE +} diff --git a/core/jvm/src/Instant.kt b/core/jvm/src/Instant.kt index 53c670449..69988c086 100644 --- a/core/jvm/src/Instant.kt +++ b/core/jvm/src/Instant.kt @@ -2,106 +2,23 @@ * Copyright 2019-2020 JetBrains s.r.o. * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:JvmMultifileClass @file:JvmName("InstantJvmKt") package kotlinx.datetime -import kotlinx.datetime.format.* import kotlinx.datetime.internal.safeMultiply import kotlinx.datetime.internal.* -import kotlinx.datetime.serializers.InstantIso8601Serializer -import kotlinx.serialization.Serializable import java.time.DateTimeException import java.time.temporal.* -import kotlin.time.* +import kotlinx.time.Instant +import kotlinx.time.toJavaInstant +import kotlinx.time.toKotlinInstant import kotlin.time.Duration.Companion.nanoseconds import kotlin.time.Duration.Companion.seconds -import java.time.Instant as jtInstant -import java.time.Clock as jtClock - -@Serializable(with = InstantIso8601Serializer::class) -public actual class Instant internal constructor(internal val value: jtInstant) : Comparable { - - public actual val epochSeconds: Long - get() = value.epochSecond - public actual val nanosecondsOfSecond: Int - get() = value.nano - - public actual fun toEpochMilliseconds(): Long = try { - value.toEpochMilli() - } catch (e: ArithmeticException) { - if (value.isAfter(java.time.Instant.EPOCH)) Long.MAX_VALUE else Long.MIN_VALUE - } - - public actual operator fun plus(duration: Duration): Instant = duration.toComponents { seconds, nanoseconds -> - try { - Instant(value.plusSeconds(seconds).plusNanos(nanoseconds.toLong())) - } catch (e: java.lang.Exception) { - if (e !is ArithmeticException && e !is DateTimeException) throw e - if (duration.isPositive()) MAX else MIN - } - } - - public actual operator fun minus(duration: Duration): Instant = plus(-duration) - - public actual operator fun minus(other: Instant): Duration = - (this.value.epochSecond - other.value.epochSecond).seconds + // won't overflow given the instant bounds - (this.value.nano - other.value.nano).nanoseconds - - public actual override operator fun compareTo(other: Instant): Int = this.value.compareTo(other.value) - - override fun equals(other: Any?): Boolean = - (this === other) || (other is Instant && this.value == other.value) - - override fun hashCode(): Int = value.hashCode() - - actual override fun toString(): String = value.toString() - - public actual companion object { - @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) - public actual fun now(): Instant = - Instant(jtClock.systemUTC().instant()) - - public actual fun fromEpochMilliseconds(epochMilliseconds: Long): Instant = - Instant(jtInstant.ofEpochMilli(epochMilliseconds)) - - // TODO: implement a custom parser to 1) help DCE get rid of the formatting machinery 2) move Instant to stdlib - public actual fun parse(input: CharSequence, format: DateTimeFormat): Instant = try { - /** - * Can't use built-in Java Time's handling of `Instant.parse` because it supports 24:00:00 and - * 23:59:60, and also doesn't support non-`Z` UTC offsets on older JDKs. - * Can't use custom Java Time's formats because Java 8 doesn't support the UTC offset format with - * optional minutes and seconds and `:` between them: - * https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendOffset-java.lang.String-java.lang.String- - */ - format.parse(input).toInstantUsingOffset() - } catch (e: IllegalArgumentException) { - throw DateTimeFormatException("Failed to parse an instant from '$input'", e) - } - - @Deprecated("This overload is only kept for binary compatibility", level = DeprecationLevel.HIDDEN) - public fun parse(isoString: String): Instant = parse(input = isoString) - - public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long): Instant = try { - Instant(jtInstant.ofEpochSecond(epochSeconds, nanosecondAdjustment)) - } catch (e: Exception) { - if (e !is ArithmeticException && e !is DateTimeException) throw e - if (epochSeconds > 0) MAX else MIN - } - - public actual fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant = - fromEpochSeconds(epochSeconds, nanosecondAdjustment.toLong()) - - public actual val DISTANT_PAST: Instant = Instant(jtInstant.ofEpochSecond(DISTANT_PAST_SECONDS, 999_999_999)) - public actual val DISTANT_FUTURE: Instant = Instant(jtInstant.ofEpochSecond(DISTANT_FUTURE_SECONDS, 0)) - - internal actual val MIN: Instant = Instant(jtInstant.MIN) - internal actual val MAX: Instant = Instant(jtInstant.MAX) - } -} private fun Instant.atZone(zone: TimeZone): java.time.ZonedDateTime = try { - value.atZone(zone.zoneId) + toJavaInstant().atZone(zone.zoneId) } catch (e: DateTimeException) { throw DateTimeArithmeticException(e) } @@ -114,7 +31,7 @@ public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Inst .run { if (totalMonths != 0L) plusMonths(totalMonths) else this } .run { if (days != 0) plusDays(days.toLong()) else this } .run { if (totalNanoseconds != 0L) plusNanos(totalNanoseconds) else this } - }.toInstant().let(::Instant) + }.toInstant().toKotlinInstant() } catch (e: DateTimeException) { throw DateTimeArithmeticException(e) } @@ -135,12 +52,12 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo val thisZdt = atZone(timeZone) when (unit) { is DateTimeUnit.TimeBased -> - plus(value, unit).value.also { it.atZone(timeZone.zoneId) } + plus(value, unit).toJavaInstant().also { it.atZone(timeZone.zoneId) } is DateTimeUnit.DayBased -> thisZdt.plusDays(safeMultiply(value, unit.days.toLong())).toInstant() is DateTimeUnit.MonthBased -> thisZdt.plusMonths(safeMultiply(value, unit.months.toLong())).toInstant() - }.let(::Instant) + }.toKotlinInstant() } catch (e: Exception) { if (e !is DateTimeException && e !is ArithmeticException) throw e throw DateTimeArithmeticException("Instant $this cannot be represented as local date when adding $value $unit to it", e) @@ -149,11 +66,11 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Instant = try { multiplyAndDivide(value, unit.nanoseconds, NANOS_PER_ONE.toLong()).let { (d, r) -> - Instant(this.value.plusSeconds(d).plusNanos(r)) + this.plus(d.seconds).plus(r.nanoseconds) } } catch (e: Exception) { if (e !is DateTimeException && e !is ArithmeticException) throw e - if (value > 0) Instant.MAX else Instant.MIN + Instant.fromEpochSeconds(if (value > 0) Long.MAX_VALUE else Long.MIN_VALUE) } public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod { @@ -178,5 +95,5 @@ public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: Ti } catch (e: DateTimeException) { throw DateTimeArithmeticException(e) } catch (e: ArithmeticException) { - if (this.value < other.value) Long.MAX_VALUE else Long.MIN_VALUE + if (this < other) Long.MAX_VALUE else Long.MIN_VALUE } diff --git a/core/jvm/src/TimeZoneJvm.kt b/core/jvm/src/TimeZoneJvm.kt index cd90993ef..482a82b3b 100644 --- a/core/jvm/src/TimeZoneJvm.kt +++ b/core/jvm/src/TimeZoneJvm.kt @@ -13,6 +13,9 @@ import kotlinx.serialization.Serializable import java.time.DateTimeException import java.time.ZoneId import java.time.ZoneOffset as jtZoneOffset +import kotlinx.time.Instant +import kotlinx.time.toJavaInstant +import kotlinx.time.toKotlinInstant @Serializable(with = TimeZoneSerializer::class) public actual open class TimeZone internal constructor(internal val zoneId: ZoneId) { @@ -21,7 +24,19 @@ public actual open class TimeZone internal constructor(internal val zoneId: Zone // experimental member-extensions public actual fun Instant.toLocalDateTime(): LocalDateTime = toLocalDateTime(this@TimeZone) - public actual fun LocalDateTime.toInstant(): Instant = toInstant(this@TimeZone) + public actual fun LocalDateTime.toInstant(deprecationMarker: DeprecationMarker): Instant = toInstant(this@TimeZone) + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal actual fun kotlinx.datetime.Instant.toLocalDateTime(): LocalDateTime = + toNewInstant().toLocalDateTime() + + @PublishedApi + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "DEPRECATION_ERROR") + @kotlin.internal.LowPriorityInOverloadResolution + internal actual fun LocalDateTime.toInstant(): kotlinx.datetime.Instant = + toInstant(this@TimeZone).toDeprecatedInstant() actual override fun equals(other: Any?): Boolean = (this === other) || (other is TimeZone && this.zoneId == other.zoneId) @@ -74,26 +89,26 @@ internal constructor(public actual val offset: UtcOffset, zoneId: ZoneId): TimeZ } public actual fun TimeZone.offsetAt(instant: Instant): UtcOffset = - zoneId.rules.getOffset(instant.value).let(::UtcOffset) + zoneId.rules.getOffset(instant.toJavaInstant()).let(::UtcOffset) public actual fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime = try { - java.time.LocalDateTime.ofInstant(this.value, timeZone.zoneId).let(::LocalDateTime) + java.time.LocalDateTime.ofInstant(this.toJavaInstant(), timeZone.zoneId).let(::LocalDateTime) } catch (e: DateTimeException) { throw DateTimeArithmeticException(e) } internal actual fun Instant.toLocalDateTime(offset: UtcOffset): LocalDateTime = try { - java.time.LocalDateTime.ofInstant(this.value, offset.zoneOffset).let(::LocalDateTime) + java.time.LocalDateTime.ofInstant(this.toJavaInstant(), offset.zoneOffset).let(::LocalDateTime) } catch (e: DateTimeException) { throw DateTimeArithmeticException(e) } -public actual fun LocalDateTime.toInstant(timeZone: TimeZone): Instant = - this.value.atZone(timeZone.zoneId).toInstant().let(::Instant) +public actual fun LocalDateTime.toInstant(timeZone: TimeZone, deprecationMarker: DeprecationMarker): Instant = + this.value.atZone(timeZone.zoneId).toInstant().toKotlinInstant() -public actual fun LocalDateTime.toInstant(offset: UtcOffset): Instant = - this.value.toInstant(offset.zoneOffset).let(::Instant) +public actual fun LocalDateTime.toInstant(offset: UtcOffset, deprecationMarker: DeprecationMarker): Instant = + this.value.toInstant(offset.zoneOffset).toKotlinInstant() -public actual fun LocalDate.atStartOfDayIn(timeZone: TimeZone): Instant = - this.value.atStartOfDay(timeZone.zoneId).toInstant().let(::Instant) +public actual fun LocalDate.atStartOfDayIn(timeZone: TimeZone, deprecationMarker: DeprecationMarker): Instant = + this.value.atStartOfDay(timeZone.zoneId).toInstant().toKotlinInstant() diff --git a/core/jvm/test/ConvertersTest.kt b/core/jvm/test/ConvertersTest.kt index 18d759938..1cfa81566 100644 --- a/core/jvm/test/ConvertersTest.kt +++ b/core/jvm/test/ConvertersTest.kt @@ -14,6 +14,8 @@ import java.time.LocalDate as JTLocalDate import java.time.Period as JTPeriod import java.time.ZoneId import java.time.ZoneOffset as JTZoneOffset +import kotlinx.time.Instant +import kotlinx.time.* class ConvertersTest { @@ -26,7 +28,7 @@ class ConvertersTest { assertEquals(ktInstant, jtInstant.toKotlinInstant()) assertEquals(jtInstant, ktInstant.toJavaInstant()) - assertEquals(ktInstant, jtInstant.toString().toInstant()) + assertEquals(ktInstant, jtInstant.toString().let(Instant::parse)) assertEquals(jtInstant, ktInstant.toString().let(JTInstant::parse)) } diff --git a/core/jvm/test/InstantParsing.kt b/core/jvm/test/InstantParsing.kt index 4c29b81e9..aac16b775 100644 --- a/core/jvm/test/InstantParsing.kt +++ b/core/jvm/test/InstantParsing.kt @@ -2,6 +2,8 @@ package kotlinx.datetime import kotlinx.datetime.format.* import kotlin.test.* +import kotlinx.time.Instant +import kotlinx.time.* class InstantParsing { @Test diff --git a/core/tzdbOnFilesystem/test/TimeZoneRulesCompleteTest.kt b/core/tzdbOnFilesystem/test/TimeZoneRulesCompleteTest.kt index 43437708a..40fea247f 100644 --- a/core/tzdbOnFilesystem/test/TimeZoneRulesCompleteTest.kt +++ b/core/tzdbOnFilesystem/test/TimeZoneRulesCompleteTest.kt @@ -11,6 +11,7 @@ import kotlinx.datetime.internal.* import platform.posix.* import kotlin.io.encoding.* import kotlin.test.* +import kotlinx.time.Instant class TimeZoneRulesCompleteTest { @OptIn(ExperimentalEncodingApi::class) diff --git a/core/windows/test/TimeZoneRulesCompleteTest.kt b/core/windows/test/TimeZoneRulesCompleteTest.kt index 34d3b8684..cd1aa32bf 100644 --- a/core/windows/test/TimeZoneRulesCompleteTest.kt +++ b/core/windows/test/TimeZoneRulesCompleteTest.kt @@ -13,6 +13,7 @@ import kotlinx.datetime.internal.* import platform.windows.* import kotlin.test.* import kotlin.time.Duration.Companion.milliseconds +import kotlinx.time.Instant class TimeZoneRulesCompleteTest { diff --git a/fake-kotlinx-time/api/fake-kotlinx-time.api b/fake-kotlinx-time/api/fake-kotlinx-time.api new file mode 100644 index 000000000..c41e07cf5 --- /dev/null +++ b/fake-kotlinx-time/api/fake-kotlinx-time.api @@ -0,0 +1,49 @@ +public abstract interface class kotlinx/time/Clock { + public static final field Companion Lkotlinx/time/Clock$Companion; + public abstract fun now ()Lkotlinx/time/Instant; +} + +public final class kotlinx/time/Clock$Companion { +} + +public final class kotlinx/time/Clock$System : kotlinx/time/Clock { + public static final field INSTANCE Lkotlinx/time/Clock$System; + public fun now ()Lkotlinx/time/Instant; +} + +public final class kotlinx/time/ConvertersKt { + public static final fun toJavaInstant (Lkotlinx/time/Instant;)Ljava/time/Instant; + public static final fun toKotlinInstant (Ljava/time/Instant;)Lkotlinx/time/Instant; +} + +public final class kotlinx/time/Instant : java/lang/Comparable { + public static final field Companion Lkotlinx/time/Instant$Companion; + public synthetic fun compareTo (Ljava/lang/Object;)I + public fun compareTo (Lkotlinx/time/Instant;)I + public fun equals (Ljava/lang/Object;)Z + public final fun getEpochSeconds ()J + public final fun getNanosecondsOfSecond ()I + public fun hashCode ()I + public final fun minus-5sfh64U (Lkotlinx/time/Instant;)J + public final fun minus-LRDsOJo (J)Lkotlinx/time/Instant; + public final fun plus-LRDsOJo (J)Lkotlinx/time/Instant; + public final fun toEpochMilliseconds ()J + public fun toString ()Ljava/lang/String; +} + +public final class kotlinx/time/Instant$Companion { + public final fun fromEpochMilliseconds (J)Lkotlinx/time/Instant; + public final fun fromEpochSeconds (JI)Lkotlinx/time/Instant; + public final fun fromEpochSeconds (JJ)Lkotlinx/time/Instant; + public static synthetic fun fromEpochSeconds$default (Lkotlinx/time/Instant$Companion;JJILjava/lang/Object;)Lkotlinx/time/Instant; + public final fun getDISTANT_FUTURE ()Lkotlinx/time/Instant; + public final fun getDISTANT_PAST ()Lkotlinx/time/Instant; + public final fun now ()Lkotlinx/time/Instant; + public final fun parse (Ljava/lang/CharSequence;)Lkotlinx/time/Instant; +} + +public final class kotlinx/time/InstantKt { + public static final fun isDistantFuture (Lkotlinx/time/Instant;)Z + public static final fun isDistantPast (Lkotlinx/time/Instant;)Z +} + diff --git a/fake-kotlinx-time/api/fake-kotlinx-time.klib.api b/fake-kotlinx-time/api/fake-kotlinx-time.klib.api new file mode 100644 index 000000000..b8dda29b2 --- /dev/null +++ b/fake-kotlinx-time/api/fake-kotlinx-time.klib.api @@ -0,0 +1,57 @@ +// Klib ABI Dump +// Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, js, linuxArm32Hfp, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, wasmWasi, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +abstract interface kotlinx.time/Clock { // kotlinx.time/Clock|null[0] + abstract fun now(): kotlinx.time/Instant // kotlinx.time/Clock.now|now(){}[0] + + final object Companion // kotlinx.time/Clock.Companion|null[0] + + final object System : kotlinx.time/Clock { // kotlinx.time/Clock.System|null[0] + final fun now(): kotlinx.time/Instant // kotlinx.time/Clock.System.now|now(){}[0] + } +} + +final class kotlinx.time/Instant : kotlin/Comparable { // kotlinx.time/Instant|null[0] + final val epochSeconds // kotlinx.time/Instant.epochSeconds|{}epochSeconds[0] + final fun (): kotlin/Long // kotlinx.time/Instant.epochSeconds.|(){}[0] + final val nanosecondsOfSecond // kotlinx.time/Instant.nanosecondsOfSecond|{}nanosecondsOfSecond[0] + final fun (): kotlin/Int // kotlinx.time/Instant.nanosecondsOfSecond.|(){}[0] + + final fun compareTo(kotlinx.time/Instant): kotlin/Int // kotlinx.time/Instant.compareTo|compareTo(kotlinx.time.Instant){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.time/Instant.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // kotlinx.time/Instant.hashCode|hashCode(){}[0] + final fun minus(kotlin.time/Duration): kotlinx.time/Instant // kotlinx.time/Instant.minus|minus(kotlin.time.Duration){}[0] + final fun minus(kotlinx.time/Instant): kotlin.time/Duration // kotlinx.time/Instant.minus|minus(kotlinx.time.Instant){}[0] + final fun plus(kotlin.time/Duration): kotlinx.time/Instant // kotlinx.time/Instant.plus|plus(kotlin.time.Duration){}[0] + final fun toEpochMilliseconds(): kotlin/Long // kotlinx.time/Instant.toEpochMilliseconds|toEpochMilliseconds(){}[0] + final fun toString(): kotlin/String // kotlinx.time/Instant.toString|toString(){}[0] + + final object Companion { // kotlinx.time/Instant.Companion|null[0] + final val DISTANT_FUTURE // kotlinx.time/Instant.Companion.DISTANT_FUTURE|{}DISTANT_FUTURE[0] + final fun (): kotlinx.time/Instant // kotlinx.time/Instant.Companion.DISTANT_FUTURE.|(){}[0] + final val DISTANT_PAST // kotlinx.time/Instant.Companion.DISTANT_PAST|{}DISTANT_PAST[0] + final fun (): kotlinx.time/Instant // kotlinx.time/Instant.Companion.DISTANT_PAST.|(){}[0] + + final fun fromEpochMilliseconds(kotlin/Long): kotlinx.time/Instant // kotlinx.time/Instant.Companion.fromEpochMilliseconds|fromEpochMilliseconds(kotlin.Long){}[0] + final fun fromEpochSeconds(kotlin/Long, kotlin/Int): kotlinx.time/Instant // kotlinx.time/Instant.Companion.fromEpochSeconds|fromEpochSeconds(kotlin.Long;kotlin.Int){}[0] + final fun fromEpochSeconds(kotlin/Long, kotlin/Long =...): kotlinx.time/Instant // kotlinx.time/Instant.Companion.fromEpochSeconds|fromEpochSeconds(kotlin.Long;kotlin.Long){}[0] + final fun now(): kotlinx.time/Instant // kotlinx.time/Instant.Companion.now|now(){}[0] + final fun parse(kotlin/CharSequence): kotlinx.time/Instant // kotlinx.time/Instant.Companion.parse|parse(kotlin.CharSequence){}[0] + } +} + +final val kotlinx.time/isDistantFuture // kotlinx.time/isDistantFuture|@kotlinx.time.Instant{}isDistantFuture[0] + final fun (kotlinx.time/Instant).(): kotlin/Boolean // kotlinx.time/isDistantFuture.|@kotlinx.time.Instant(){}[0] +final val kotlinx.time/isDistantPast // kotlinx.time/isDistantPast|@kotlinx.time.Instant{}isDistantPast[0] + final fun (kotlinx.time/Instant).(): kotlin/Boolean // kotlinx.time/isDistantPast.|@kotlinx.time.Instant(){}[0] + +// Targets: [js] +final fun (kotlin.js/Date).kotlinx.time/toKotlinInstant(): kotlinx.time/Instant // kotlinx.time/toKotlinInstant|toKotlinInstant@kotlin.js.Date(){}[0] + +// Targets: [js] +final fun (kotlinx.time/Instant).kotlinx.time/toJSDate(): kotlin.js/Date // kotlinx.time/toJSDate|toJSDate@kotlinx.time.Instant(){}[0] diff --git a/fake-kotlinx-time/build.gradle.kts b/fake-kotlinx-time/build.gradle.kts new file mode 100644 index 000000000..2cfd7a452 --- /dev/null +++ b/fake-kotlinx-time/build.gradle.kts @@ -0,0 +1,112 @@ +import java.util.Locale + +plugins { + id("kotlin-multiplatform") + id("org.jetbrains.kotlinx.kover") +} + +val mainJavaToolchainVersion: String by project +val serializationVersion: String by project + +java { + toolchain { languageVersion.set(JavaLanguageVersion.of(mainJavaToolchainVersion)) } +} + +kotlin { + explicitApi() + infra { + target("linuxX64") + target("linuxArm64") + target("linuxArm32Hfp") + target("mingwX64") + target("macosX64") + target("macosArm64") + target("iosX64") + target("iosArm64") + target("iosSimulatorArm64") + target("watchosArm32") + target("watchosArm64") + target("watchosX64") + target("watchosSimulatorArm64") + target("watchosDeviceArm64") + target("tvosArm64") + target("tvosX64") + target("tvosSimulatorArm64") + target("androidNativeArm32") + target("androidNativeArm64") + target("androidNativeX86") + target("androidNativeX64") + } + + jvm { + attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) + } + } + + js { + nodejs { + } + compilations.all { + kotlinOptions { + sourceMap = true + moduleKind = "umd" + metaInfo = true + } + } + } + + + wasmJs { + nodejs { + } + } + + wasmWasi { + nodejs { + } + } + + sourceSets.all { + val suffixIndex = name.indexOfLast { it.isUpperCase() } + val targetName = name.substring(0, suffixIndex) + val suffix = name.substring(suffixIndex).toLowerCase(Locale.ROOT).takeIf { it != "main" } + kotlin.srcDir("$targetName/${suffix ?: "src"}") + resources.srcDir("$targetName/${suffix?.let { it + "Resources" } ?: "resources"}") + } + + targets.withType { + compilations["test"].kotlinOptions { + freeCompilerArgs += listOf("-trw") + } + } + + sourceSets { + commonMain { + dependencies { + } + } + + commonTest { + dependencies { + api("org.jetbrains.kotlin:kotlin-test") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") + } + } + + val jvmMain by getting + val jvmTest by getting + + val jsMain by getting + val jsTest by getting + + val wasmJsMain by getting + val wasmJsTest by getting + + val wasmWasiMain by getting + val wasmWasiTest by getting + + val nativeMain by getting + val nativeTest by getting + } +} diff --git a/fake-kotlinx-time/common/src/Clock.kt b/fake-kotlinx-time/common/src/Clock.kt new file mode 100644 index 000000000..c5e2feec7 --- /dev/null +++ b/fake-kotlinx-time/common/src/Clock.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +import kotlin.time.* + +/** + * A source of [Instant] values. + * + * See [Clock.System][Clock.System] for the clock instance that queries the operating system. + * + * It is not recommended to use [Clock.System] directly in the implementation. Instead, you can pass a + * [Clock] explicitly to the necessary functions or classes. + * This way, tests can be written deterministically by providing custom [Clock] implementations + * to the system under test. + */ +public interface Clock { + /** + * Returns the [Instant] corresponding to the current time, according to this clock. + * + * Calling [now] later is not guaranteed to return a larger [Instant]. + * In particular, for [Clock.System], the opposite is completely expected, + * and it must be taken into account. + * See the [System] documentation for details. + * + * Even though [Instant] is defined to be on the UTC-SLS time scale, which enforces a specific way of handling + * leap seconds, [now] is not guaranteed to handle leap seconds in any specific way. + */ + public fun now(): Instant + + /** + * The [Clock] instance that queries the platform-specific system clock as its source of time knowledge. + * + * Successive calls to [now] will not necessarily return increasing [Instant] values, and when they do, + * these increases will not necessarily correspond to the elapsed time. + * + * For example, when using [Clock.System], the following could happen: + * - [now] returns `2023-01-02T22:35:01Z`. + * - The system queries the Internet and recognizes that its clock needs adjusting. + * - [now] returns `2023-01-02T22:32:05Z`. + * + * When you need predictable intervals between successive measurements, consider using [TimeSource.Monotonic]. + * + * For improved testability, you should avoid using [Clock.System] directly in the implementation + * and pass a [Clock] explicitly instead. For example: + * + * @sample kotlinx.datetime.test.samples.ClockSamples.system + * @sample kotlinx.datetime.test.samples.ClockSamples.dependencyInjection + */ + public object System : Clock { + override fun now(): Instant = @Suppress("DEPRECATION_ERROR") Instant.now() + } + + /** A companion object used purely for namespacing. */ + public companion object { + + } +} diff --git a/fake-kotlinx-time/common/src/Instant.kt b/fake-kotlinx-time/common/src/Instant.kt new file mode 100644 index 000000000..24ebc7d13 --- /dev/null +++ b/fake-kotlinx-time/common/src/Instant.kt @@ -0,0 +1,774 @@ +/* + * Copyright 2019-2020 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +import kotlin.math.absoluteValue +import kotlin.time.* +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds + +/** + * A moment in time. + * + * A point in time must be uniquely identified in a way that is independent of a time zone. + * For example, `1970-01-01, 00:00:00` does not represent a moment in time since this would happen at different times + * in different time zones: someone in Tokyo would think it is already `1970-01-01` several hours earlier than someone in + * Berlin would. To represent such entities, use the `LocalDateTime` from `kotlinx-datetime`. + * In contrast, "the moment the clocks in London first showed 00:00 on Jan 1, 2000" is a specific moment + * in time, as is "1970-01-01, 00:00:00 UTC+0", so it can be represented as an [Instant]. + * + * `Instant` uses the UTC-SLS (smeared leap second) time scale. This time scale doesn't contain instants + * corresponding to leap seconds, but instead "smears" positive and negative leap seconds among the last 1000 seconds + * of the day when a leap second happens. + * + * ### Obtaining the current moment + * + * The [Clock] interface is the primary way to obtain the current moment: + * + * ``` + * val clock: Clock = Clock.System + * val instant = clock.now() + * ``` + * + * The [Clock.System] implementation uses the platform-specific system clock to obtain the current moment. + * Note that this clock is not guaranteed to be monotonic, and the user or the system may adjust it at any time, + * so it should not be used for measuring time intervals. + * For that, consider using [TimeSource.Monotonic] and [TimeMark] instead of [Clock.System] and [Instant]. + * + * ### Arithmetic operations + * + * The [plus] and [minus] operators can be used to add [Duration]s to and subtract them from an [Instant]: + * + * ``` + * Clock.System.now() + 5.seconds // 5 seconds from now + * ``` + * + * Also, there is a [minus] operator that returns the [Duration] representing the difference between two instants: + * + * ``` + * val kotlinRelease = Instant.parse("2016-02-15T02:00T12:00:00+03:00") + * val kotlinStableDuration = Clock.System.now() - kotlinRelease + * ``` + * + * ### Platform specifics + * + * On the JVM, there are `Instant.toJavaInstant()` and `java.time.Instant.toKotlinInstant()` + * extension functions to convert between `kotlin.time` and `java.time` objects used for the same purpose. + * Likewise, on JS, there are `Instant.toJSDate()` and `Date.toKotlinInstant()` extension functions. + * + * For technical reasons, converting [Instant] to and from Foundation's `NSDate` is provided in + * `kotlinx-datetime` via `Instant.toNSDate()` and `NSDate.toKotlinInstant()` extension functions. + * These functions will be made available in `kotlin.time` in the future. + * + * ### Construction, serialization, and deserialization + * + * [fromEpochSeconds] can be used to construct an instant from the number of seconds since + * `1970-01-01T00:00:00Z` (the Unix epoch). + * [epochSeconds] and [nanosecondsOfSecond] can be used to obtain the number of seconds and nanoseconds since the epoch. + * + * ``` + * val instant = Instant.fromEpochSeconds(1709898983, 123456789) + * instant.epochSeconds // 1709898983 + * instant.nanosecondsOfSecond // 123456789 + * ``` + * + * [fromEpochMilliseconds] allows constructing an instant from the number of milliseconds since the epoch. + * [toEpochMilliseconds] can be used to obtain the number of milliseconds since the epoch. + * Note that [Instant] supports nanosecond precision, so converting to milliseconds is a lossy operation. + * + * ``` + * val instant1 = Instant.fromEpochSeconds(1709898983, 123456789) + * instant1.nanosecondsOfSecond // 123456789 + * val milliseconds = instant1.toEpochMilliseconds() // 1709898983123 + * val instant2 = Instant.fromEpochMilliseconds(milliseconds) + * instant2.nanosecondsOfSecond // 123000000 + * ``` + * + * [parse] and [toString] methods can be used to obtain an [Instant] from and convert it to a string in the + * ISO 8601 extended format. + * + * ``` + * val instant = Instant.parse("2023-01-02T22:35:01+01:00") + * instant.toString() // 2023-01-02T21:35:01Z + * ``` + */ +public class Instant internal constructor( + /** + * The number of seconds from the epoch instant `1970-01-01T00:00:00Z` rounded down to a [Long] number. + * + * The difference between the rounded number of seconds and the actual number of seconds + * is returned by [nanosecondsOfSecond] property expressed in nanoseconds. + * + * Note that this number doesn't include leap seconds added or removed since the epoch. + * + * @see fromEpochSeconds + * @sample kotlinx.datetime.test.samples.InstantSamples.epochSeconds + */ + public val epochSeconds: Long, + /** + * The number of nanoseconds by which this instant is later than [epochSeconds] from the epoch instant. + * + * The value is always non-negative and lies in the range `0..999_999_999`. + * + * @see fromEpochSeconds + * @sample kotlinx.datetime.test.samples.InstantSamples.nanosecondsOfSecond + */ + public val nanosecondsOfSecond: Int +) : Comparable { + + init { + require(epochSeconds in MIN_SECOND..MAX_SECOND) { "Instant exceeds minimum or maximum instant" } + } + + /** + * Returns the number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. + * + * Any fractional part of a millisecond is rounded toward zero to the whole number of milliseconds. + * + * If the result does not fit in [Long], + * returns [Long.MAX_VALUE] for a positive result or [Long.MIN_VALUE] for a negative result. + * + * @see fromEpochMilliseconds + * @sample kotlinx.datetime.test.samples.InstantSamples.toEpochMilliseconds + */ + // org.threeten.bp.Instant#toEpochMilli + public fun toEpochMilliseconds(): Long = try { + if (epochSeconds >= 0) { + val millis = safeMultiply(epochSeconds, MILLIS_PER_ONE.toLong()) + safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI).toLong()) + } else { + // prevent an overflow in seconds * 1000 + // instead of going form the second farther away from 0 + // going toward 0 + // we go from the second closer to 0 away from 0 + // that way we always stay in the valid long range + // seconds + 1 can not overflow because it is negative + val millis = safeMultiply(epochSeconds + 1, MILLIS_PER_ONE.toLong()) + safeAdd(millis, (nanosecondsOfSecond / NANOS_PER_MILLI - MILLIS_PER_ONE).toLong()) + } + } catch (_: ArithmeticException) { + if (epochSeconds > 0) Long.MAX_VALUE else Long.MIN_VALUE + } + + // org.threeten.bp.Instant#plus(long, long) + /** + * @throws ArithmeticException if arithmetic overflow occurs + * @throws IllegalArgumentException if the boundaries of Instant are overflown + */ + internal fun plus(secondsToAdd: Long, nanosToAdd: Long): Instant { + if ((secondsToAdd or nanosToAdd) == 0L) { + return this + } + val newEpochSeconds: Long = safeAdd(safeAdd(epochSeconds, secondsToAdd), (nanosToAdd / NANOS_PER_ONE)) + val newNanosToAdd = nanosToAdd % NANOS_PER_ONE + val nanoAdjustment = (nanosecondsOfSecond + newNanosToAdd) // safe int+NANOS_PER_ONE + return fromEpochSecondsThrowing(newEpochSeconds, nanoAdjustment) + } + + /** + * Returns an instant that is the result of adding the specified [duration] to this instant. + * + * If the [duration] is positive, the returned instant is later than this instant. + * If the [duration] is negative, the returned instant is earlier than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours, but in some time zones, + * some days can be shorter or longer because clocks are shifted. + * Consider using `kotlinx-datetime` for arithmetic operations that take time zone transitions into account. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.plusDuration + */ + public operator fun plus(duration: Duration): Instant = duration.toComponents { secondsToAdd, nanosecondsToAdd -> + try { + plus(secondsToAdd, nanosecondsToAdd.toLong()) + } catch (_: IllegalArgumentException) { + if (duration.isPositive()) MAX else MIN + } catch (_: ArithmeticException) { + if (duration.isPositive()) MAX else MIN + } + } + + /** + * Returns an instant that is the result of subtracting the specified [duration] from this instant. + * + * If the [duration] is positive, the returned instant is earlier than this instant. + * If the [duration] is negative, the returned instant is later than this instant. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * + * **Pitfall**: [Duration.Companion.days] are multiples of 24 hours, but in some time zones, + * some days can be shorter or longer because clocks are shifted. + * Consider using `kotlinx-datetime` for arithmetic operations that take time zone transitions into account. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusDuration + */ + public operator fun minus(duration: Duration): Instant = plus(-duration) + + // questionable + /** + * Returns the [Duration] between two instants: [other] and `this`. + * + * The duration returned is positive if this instant is later than the other, + * and negative if this instant is earlier than the other. + * + * The result is never clamped, but note that for instants that are far apart, + * the value returned may represent the duration between them inexactly due to the loss of precision. + * + * Note that sources of [Instant] values (in particular, [Clock]) are not guaranteed to be in sync with each other + * or even monotonic, so the result of this operation may be negative even if the other instant was observed later + * than this one, or vice versa. + * For measuring time intervals, consider using [TimeSource.Monotonic]. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.minusInstant + */ + public operator fun minus(other: Instant): Duration = + (this.epochSeconds - other.epochSeconds).seconds + // won't overflow given the instant bounds + (this.nanosecondsOfSecond - other.nanosecondsOfSecond).nanoseconds + + /** + * Compares `this` instant with the [other] instant. + * Returns zero if this instant represents the same moment as the other (meaning they are equal to one another), + * a negative number if this instant is earlier than the other, + * and a positive number if this instant is later than the other. + */ + public override operator fun compareTo(other: Instant): Int { + val s = epochSeconds.compareTo(other.epochSeconds) + if (s != 0) { + return s + } + return nanosecondsOfSecond.compareTo(other.nanosecondsOfSecond) + } + + override fun equals(other: Any?): Boolean = + this === other || other is Instant && this.epochSeconds == other.epochSeconds + && this.nanosecondsOfSecond == other.nanosecondsOfSecond + + // org.threeten.bp.Instant#hashCode + override fun hashCode(): Int = + (epochSeconds xor (epochSeconds ushr 32)).toInt() + 51 * nanosecondsOfSecond + + /** + * Converts this instant to the ISO 8601 string representation, for example, `2023-01-02T23:40:57.120Z`. + * + * The representation uses the UTC-SLS time scale instead of UTC. + * In practice, this means that leap second handling will not be readjusted to the UTC. + * Leap seconds will not be added or skipped, so it is impossible to acquire a string + * where the component for seconds is 60, and for any day, it's possible to observe 23:59:59. + * + * @see parse + * + * @sample kotlinx.datetime.test.samples.InstantSamples.toStringSample + */ + public override fun toString(): String = formatIso(this) + + public companion object { + @Deprecated("Use Clock.System.now() instead", ReplaceWith("Clock.System.now()", "kotlinx.datetime.Clock"), level = DeprecationLevel.ERROR) + public fun now(): Instant = currentTime() + + /** + * Returns an [Instant] that is [epochMilliseconds] number of milliseconds from the epoch instant `1970-01-01T00:00:00Z`. + * + * Every value of [epochMilliseconds] is guaranteed to be representable as an [Instant]. + * + * Note that [Instant] also supports nanosecond precision via [fromEpochSeconds]. + * + * @see Instant.toEpochMilliseconds + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochMilliseconds + */ + // org.threeten.bp.Instant#ofEpochMilli + public fun fromEpochMilliseconds(epochMilliseconds: Long): Instant { + val epochSeconds = epochMilliseconds.floorDiv(MILLIS_PER_ONE.toLong()) + val nanosecondsOfSecond = (epochMilliseconds.mod(MILLIS_PER_ONE.toLong()) * NANOS_PER_MILLI).toInt() + return when { + epochSeconds < MIN_SECOND -> MIN + epochSeconds > MAX_SECOND -> MAX + else -> fromEpochSeconds(epochSeconds, nanosecondsOfSecond) + } + } + + /** + * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` + * and the [nanosecondAdjustment] number of nanoseconds from the whole second. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. + * + * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. + * + * @see Instant.epochSeconds + * @see Instant.nanosecondsOfSecond + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSeconds + */ + // org.threeten.bp.Instant#ofEpochSecond(long, long) + public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Long = 0): Instant = + try { + fromEpochSecondsThrowing(epochSeconds, nanosecondAdjustment) + } catch (_: ArithmeticException) { + if (epochSeconds > 0) MAX else MIN + } catch (_: IllegalArgumentException) { + if (epochSeconds > 0) MAX else MIN + } + + /** + * Returns an [Instant] that is the [epochSeconds] number of seconds from the epoch instant `1970-01-01T00:00:00Z` + * and the [nanosecondAdjustment] number of nanoseconds from the whole second. + * + * The return value is clamped to the boundaries of [Instant] if the result exceeds them. + * In any case, it is guaranteed that instants between [DISTANT_PAST] and [DISTANT_FUTURE] can be represented. + * + * [fromEpochMilliseconds] is a similar function for when input data only has millisecond precision. + * + * @see Instant.epochSeconds + * @see Instant.nanosecondsOfSecond + * @sample kotlinx.datetime.test.samples.InstantSamples.fromEpochSecondsIntNanos + */ + public fun fromEpochSeconds(epochSeconds: Long, nanosecondAdjustment: Int): Instant = + fromEpochSeconds(epochSeconds, nanosecondAdjustment.toLong()) + + /** + * Parses an ISO 8601 string that represents an instant (for example, `2020-08-30T18:43:00Z`). + * + * Guaranteed to parse all strings that [Instant.toString] produces. + * + * Examples of instants in the ISO 8601 format: + * - `2020-08-30T18:43:00Z` + * - `2020-08-30T18:43:00.50Z` + * - `2020-08-30T18:43:00.123456789Z` + * - `2020-08-30T18:40:00+03:00` + * - `2020-08-30T18:40:00+03:30:20` + * * `2020-01-01T23:59:59.123456789+01` + * * `+12020-01-31T23:59:59Z` + * + * See ISO-8601-1:2019, 5.4.2.1b), excluding the format without the offset. + * + * The string is considered to represent time on the UTC-SLS time scale instead of UTC. + * In practice, this means that, even if there is a leap second on the given day, it will not affect how the + * time is parsed, even if it's in the last 1000 seconds of the day. + * Instead, even if there is a negative leap second on the given day, 23:59:59 is still considered a valid time. + * 23:59:60 is invalid on UTC-SLS, so parsing it will fail. + * + * @throws IllegalArgumentException if the text cannot be parsed or the boundaries of [Instant] are exceeded. + * + * @see Instant.toString for formatting. + * @sample kotlinx.datetime.test.samples.InstantSamples.parsing + */ + public fun parse(input: CharSequence): Instant = parseIso(input) + + + /** + * An instant value that is far in the past. + * + * [isDistantPast] returns true for this value and all earlier ones. + */ + public val DISTANT_PAST: Instant // -100001-12-31T23:59:59.999999999Z + get() = fromEpochSeconds(DISTANT_PAST_SECONDS, 999_999_999) + + /** + * An instant value that is far in the future. + * + * [isDistantFuture] returns true for this value and all later ones. + */ + public val DISTANT_FUTURE: Instant // +100000-01-01T00:00:00Z + get() = fromEpochSeconds(DISTANT_FUTURE_SECONDS, 0) + + /** + * @throws ArithmeticException if arithmetic overflow occurs + * @throws IllegalArgumentException if the boundaries of Instant are overflown + */ + private fun fromEpochSecondsThrowing(epochSeconds: Long, nanosecondAdjustment: Long): Instant { + val secs = safeAdd(epochSeconds, nanosecondAdjustment.floorDiv(NANOS_PER_ONE.toLong())) + val nos = nanosecondAdjustment.mod(NANOS_PER_ONE.toLong()).toInt() + return Instant(secs, nos) + } + + internal val MIN = Instant(MIN_SECOND, 0) + internal val MAX = Instant(MAX_SECOND, 999_999_999) + } +} + +/** + * Returns true if the instant is [Instant.DISTANT_PAST] or earlier. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantPast + */ +public val Instant.isDistantPast: Boolean + get() = this <= Instant.DISTANT_PAST + +/** + * Returns true if the instant is [Instant.DISTANT_FUTURE] or later. + * + * @sample kotlinx.datetime.test.samples.InstantSamples.isDistantFuture + */ +public val Instant.isDistantFuture: Boolean + get() = this >= Instant.DISTANT_FUTURE + +internal const val DISTANT_PAST_SECONDS = -3217862419201 +internal const val DISTANT_FUTURE_SECONDS = 3093527980800 + +internal expect fun currentTime(): Instant + +/** + * The minimum supported epoch second. + */ +private const val MIN_SECOND = -31557014167219200L // -1000000000-01-01T00:00:00Z + +/** + * The maximum supported epoch second. + */ +private const val MAX_SECOND = 31556889864403199L // +1000000000-12-31T23:59:59 + +private class UnboundedLocalDateTime( + val year: Int, + val month: Int, + val day: Int, + val hour: Int, + val minute: Int, + val second: Int, + val nanosecond: Int, +) { + fun toInstant(offsetSeconds: Int): Instant { + val epochSeconds = run { + // org.threeten.bp.LocalDate#toEpochDay + val epochDays = run { + val y = year.toLong() + var total = 365 * y + if (y >= 0) { + total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400 + } else { + total -= y / -4 - y / -100 + y / -400 + } + total += ((367 * month - 362) / 12) + total += day - 1 + if (month > 2) { + total-- + if (!isLeapYear(year)) { + total-- + } + } + total - DAYS_0000_TO_1970 + } + // org.threeten.bp.LocalTime#toSecondOfDay + val daySeconds = hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second + // org.threeten.bp.chrono.ChronoLocalDateTime#toEpochSecond + epochDays * 86400L + daySeconds - offsetSeconds + } + if (epochSeconds < Instant.MIN.epochSeconds || epochSeconds > Instant.MAX.epochSeconds) + throw IllegalArgumentException( + "The parsed date is outside the range representable by Instant (Unix epoch second $epochSeconds)" + ) + return Instant.fromEpochSeconds(epochSeconds, nanosecond) + } + + override fun toString(): String = "UnboundedLocalDateTime($year-$month-$day $hour:$minute:$second.$nanosecond)" + + companion object { + fun fromInstant(instant: Instant, offsetSeconds: Int): UnboundedLocalDateTime { + val localSecond: Long = instant.epochSeconds + offsetSeconds + val epochDays = localSecond.floorDiv(SECONDS_PER_DAY.toLong()) + val secsOfDay = localSecond.mod(SECONDS_PER_DAY.toLong()).toInt() + val year: Int + val month: Int + val day: Int + // org.threeten.bp.LocalDate#toEpochDay + run { + var zeroDay = epochDays + DAYS_0000_TO_1970 + // find the march-based year + zeroDay -= 60 // adjust to 0000-03-01 so leap day is at end of four year cycle + + var adjust = 0L + if (zeroDay < 0) { // adjust negative years to positive for calculation + val adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1 + adjust = adjustCycles * 400 + zeroDay += -adjustCycles * DAYS_PER_CYCLE + } + var yearEst = ((400 * zeroDay + 591) / DAYS_PER_CYCLE) + var doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400) + if (doyEst < 0) { // fix estimate + yearEst-- + doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400) + } + yearEst += adjust // reset any negative year + + val marchDoy0 = doyEst.toInt() + + // convert march-based values back to january-based + val marchMonth0 = (marchDoy0 * 5 + 2) / 153 + month = (marchMonth0 + 2) % 12 + 1 + day = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1 + year = (yearEst + marchMonth0 / 10).toInt() + } + val hours = (secsOfDay / SECONDS_PER_HOUR) + val secondWithoutHours = secsOfDay - hours * SECONDS_PER_HOUR + val minutes = (secondWithoutHours / SECONDS_PER_MINUTE) + val second = secondWithoutHours - minutes * SECONDS_PER_MINUTE + return UnboundedLocalDateTime(year, month, day, hours, minutes, second, instant.nanosecondsOfSecond) + } + } +} + +private fun parseIso(isoString: CharSequence): Instant { + fun parseFailure(error: String): Nothing { + throw IllegalArgumentException("$error when parsing an Instant from $isoString") + } + fun expect(what: String, where: Int, predicate: (Char) -> Boolean) { + val c = isoString[where] + if (!predicate(c)) { + parseFailure("Expected $what, but got $c at position $where") + } + } + val s = isoString + var i = 0 + require(s.isNotEmpty()) { "An empty string is not a valid Instant" } + val yearSign = when (val c = s[i]) { + '+', '-' -> { ++i; c } + else -> ' ' + } + val yearStart = i + var absYear = 0 + while (i < s.length && s[i] in '0'..'9') { + absYear = absYear * 10 + (s[i] - '0') + ++i + } + val year = when { + i > yearStart + 10 -> { + parseFailure("Expected at most 10 digits for the year number, got ${i - yearStart}") + } + i == yearStart + 10 && s[yearStart] >= '2' -> { + parseFailure("Expected at most 9 digits for the year number or year 1000000000, got ${i - yearStart}") + } + i - yearStart < 4 -> { + parseFailure("The year number must be padded to 4 digits, got ${i - yearStart} digits") + } + else -> { + if (yearSign == '+' && i - yearStart == 4) { + parseFailure("The '+' sign at the start is only valid for year numbers longer than 4 digits") + } + if (yearSign == ' ' && i - yearStart != 4) { + parseFailure("A '+' or '-' sign is required for year numbers longer than 4 digits") + } + if (yearSign == '-') -absYear else absYear + } + } + // reading at least -MM-DDTHH:MM:SSZ + // 0123456789012345 16 chars + if (s.length < i + 16) { + parseFailure("The input string is too short") + } + expect("'-'", i) { it == '-' } + expect("'-'", i + 3) { it == '-' } + expect("'T' or 't'", i + 6) { it == 'T' || it == 't' } + expect("':'", i + 9) { it == ':' } + expect("':'", i + 12) { it == ':' } + for (j in listOf(1, 2, 4, 5, 7, 8, 10, 11, 13, 14)) { + expect("an ASCII digit", i + j) { it in '0'..'9' } + } + fun twoDigitNumber(index: Int) = s[index].code * 10 + s[index + 1].code - '0'.code * 11 + val month = twoDigitNumber(i + 1) + val day = twoDigitNumber(i + 4) + val hour = twoDigitNumber(i + 7) + val minute = twoDigitNumber(i + 10) + val second = twoDigitNumber(i + 13) + val nanosecond = if (s[i + 15] == '.') { + val fractionStart = i + 16 + i = fractionStart + var fraction = 0 + while (i < s.length && s[i] in '0'..'9') { + fraction = fraction * 10 + (s[i] - '0') + ++i + } + if (i - fractionStart in 1..9) { + fraction * POWERS_OF_TEN[fractionStart + 9 - i] + } else { + parseFailure("1..9 digits are supported for the fraction of the second, got {i - fractionStart}") + } + } else { + i += 15 + 0 + } + val offsetSeconds = when (val sign = s.getOrNull(i)) { + null -> { + parseFailure("The UTC offset at the end of the string is missing") + } + 'z', 'Z' -> if (s.length == i + 1) { + 0 + } else { + parseFailure("Extra text after the instant at position ${i + 1}") + } + '-', '+' -> { + val offsetStrLength = s.length - i + if (offsetStrLength % 3 != 0) { parseFailure("Invalid UTC offset string '${s.substring(i)}'") } + if (offsetStrLength > 9) { parseFailure("The UTC offset string '${s.substring(i)}' is too long") } + for (j in listOf(3, 6)) { + if ((s.getOrNull(i + j) ?: break) != ':') + parseFailure("Expected ':' at index ${i + j}, got '${s[i + j]}'") + } + for (j in listOf(1, 2, 4, 5, 7, 8)) { + if ((s.getOrNull(i + j) ?: break) !in '0'..'9') + parseFailure("Expected a digit at index ${i + j}, got '${s[i + j]}'") + } + val offsetHour = twoDigitNumber(i + 1) + val offsetMinute = if (offsetStrLength > 3) { twoDigitNumber(i + 4) } else { 0 } + val offsetSecond = if (offsetStrLength > 6) { twoDigitNumber(i + 7) } else { 0 } + if (offsetMinute > 59) { parseFailure("Expected offset-minute-of-hour in 0..59, got $offsetMinute") } + if (offsetSecond > 59) { parseFailure("Expected offset-second-of-minute in 0..59, got $offsetSecond") } + if (offsetHour > 17 && !(offsetHour == 18 && offsetMinute == 0 && offsetSecond == 0)) { + parseFailure("Expected an offset in -18:00..+18:00, got $sign$offsetHour:$offsetMinute:$offsetSecond") + } + (offsetHour * 3600 + offsetMinute * 60 + offsetSecond) * if (sign == '-') -1 else 1 + } + else -> { + parseFailure("Expected the UTC offset at position $i, got '$sign'") + } + } + if (month !in 1..12) { parseFailure("Expected a month number in 1..12, got $month") } + if (day !in 1..month.monthLength(isLeapYear(year))) { + parseFailure("Expected a valid day-of-month for $year-$month, got $day") + } + if (hour > 23) { parseFailure("Expected hour in 0..23, got $hour") } + if (minute > 59) { parseFailure("Expected minute-of-hour in 0..59, got $minute") } + if (second > 59) { parseFailure("Expected second-of-minute in 0..59, got $second") } + return UnboundedLocalDateTime(year, month, day, hour, minute, second, nanosecond).toInstant(offsetSeconds) +} + +private fun formatIso(instant: Instant): String = buildString { + val ldt = UnboundedLocalDateTime.fromInstant(instant, 0) + fun Appendable.appendTwoDigits(number: Int) { + if (number < 10) append('0') + append(number) + } + run { + val number = ldt.year + when { + number.absoluteValue < 1_000 -> { + val innerBuilder = StringBuilder() + if (number >= 0) { + innerBuilder.append((number + 10_000)).deleteAt(0) + } else { + innerBuilder.append((number - 10_000)).deleteAt(1) + } + append(innerBuilder) + } + else -> { + if (number >= 10_000) append('+') + append(number) + } + } + } + append('-') + appendTwoDigits(ldt.month) + append('-') + appendTwoDigits(ldt.day) + append('T') + appendTwoDigits(ldt.hour) + append(':') + appendTwoDigits(ldt.minute) + append(':') + appendTwoDigits(ldt.second) + if (ldt.nanosecond != 0) { + append('.') + var zerosToStrip = 0 + while (ldt.nanosecond % POWERS_OF_TEN[zerosToStrip + 1] == 0) { + ++zerosToStrip + } + zerosToStrip -= (zerosToStrip.mod(3)) // rounding down to a multiple of 3 + val numberToOutput = ldt.nanosecond / POWERS_OF_TEN[zerosToStrip] + append((numberToOutput + POWERS_OF_TEN[9 - zerosToStrip]).toString().substring(1)) + } + append('Z') +} + +/** + * All code below was taken from various places of https://github.com/ThreeTen/threetenbp with few changes + */ + +/** + * The number of days in a 400 year cycle. + */ +private const val DAYS_PER_CYCLE = 146097 + +/** + * The number of days from year zero to year 1970. + * There are five 400 year cycles from year zero to 2000. + * There are 7 leap years from 1970 to 2000. + */ +private const val DAYS_0000_TO_1970 = DAYS_PER_CYCLE * 5 - (30 * 365 + 7) + +/** + * Safely adds two long values. + * throws [ArithmeticException] if the result overflows a long + */ +private fun safeAdd(a: Long, b: Long): Long { + val sum = a + b + // check for a change of sign in the result when the inputs have the same sign + if ((a xor sum) < 0 && (a xor b) >= 0) { + throw ArithmeticException("Addition overflows a long: $a + $b") + } + return sum +} + +/** + * Safely multiply a long by a long. + * + * @param a the first value + * @param b the second value + * @return the new total + * @throws ArithmeticException if the result overflows a long + */ +private fun safeMultiply(a: Long, b: Long): Long { + if (b == 1L) { + return a + } + if (a == 1L) { + return b + } + if (a == 0L || b == 0L) { + return 0 + } + val total = a * b + if (total / b != a || a == Long.MIN_VALUE && b == -1L || b == Long.MIN_VALUE && a == -1L) { + throw ArithmeticException("Multiplication overflows a long: $a * $b") + } + return total +} + +private const val SECONDS_PER_HOUR = 60 * 60 + +private const val SECONDS_PER_MINUTE = 60 + +private const val HOURS_PER_DAY = 24 + +private const val SECONDS_PER_DAY: Int = SECONDS_PER_HOUR * HOURS_PER_DAY + +internal const val NANOS_PER_ONE = 1_000_000_000 +private const val NANOS_PER_MILLI = 1_000_000 +private const val MILLIS_PER_ONE = 1_000 + +// org.threeten.bp.chrono.IsoChronology#isLeapYear +internal fun isLeapYear(year: Int): Boolean { + val prolepticYear: Long = year.toLong() + return prolepticYear and 3 == 0L && (prolepticYear % 100 != 0L || prolepticYear % 400 == 0L) +} + +private fun Int.monthLength(isLeapYear: Boolean): Int = + when (this) { + 2 -> if (isLeapYear) 29 else 28 + 4, 6, 9, 11 -> 30 + else -> 31 + } + +private val POWERS_OF_TEN = intArrayOf( + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 +) diff --git a/core/commonKotlin/test/InstantIsoStringsTest.kt b/fake-kotlinx-time/common/test/InstantTest.kt similarity index 68% rename from core/commonKotlin/test/InstantIsoStringsTest.kt rename to fake-kotlinx-time/common/test/InstantTest.kt index 6b9390e37..c42fa9e2a 100644 --- a/core/commonKotlin/test/InstantIsoStringsTest.kt +++ b/fake-kotlinx-time/common/test/InstantTest.kt @@ -1,13 +1,217 @@ /* - * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Copyright 2019-2020 JetBrains s.r.o. * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ -package kotlinx.datetime +package kotlinx.time.test +import kotlinx.time.* import kotlin.math.absoluteValue -import kotlin.time.Duration.Companion.seconds +import kotlin.random.* import kotlin.test.* +import kotlin.time.* +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.nanoseconds +import kotlin.time.Duration.Companion.seconds + +class InstantTest { + + @Test + fun testNow() { + val instant = Clock.System.now() + val millis = instant.toEpochMilliseconds() + + assertTrue(millis > 1_500_000_000_000L) + + println(instant) + println(instant.toEpochMilliseconds()) + + val millisInstant = Instant.fromEpochMilliseconds(millis) + + assertEquals(millis, millisInstant.toEpochMilliseconds()) + + val notEqualInstant = Instant.fromEpochMilliseconds(millis + 1) + assertNotEquals(notEqualInstant, instant) + } + + @Test + fun instantArithmetic() { + val instant = Clock.System.now().toEpochMilliseconds().let { Instant.fromEpochMilliseconds(it) } // round to millis + val diffMillis = Random.nextLong(1000, 1_000_000_000) + val diff = diffMillis.milliseconds + + val nextInstant = (instant.toEpochMilliseconds() + diffMillis).let { Instant.fromEpochMilliseconds(it) } + + assertEquals(diff, nextInstant - instant) + assertEquals(nextInstant, instant + diff) + assertEquals(instant, nextInstant - diff) + + println("this: $instant, next: $nextInstant, diff: ${diff.toIsoString()}") + } + + @Test + fun addingMultiplesOf2_32() { + val pow2_32 = 1L shl 32 + val instant1 = Instant.fromEpochSeconds(0) + val instant2 = instant1.plus(pow2_32.nanoseconds) + assertEquals(pow2_32 / NANOS_PER_ONE, instant2.epochSeconds) + assertEquals(pow2_32 % NANOS_PER_ONE, instant2.nanosecondsOfSecond.toLong()) + + val instant3 = instant1.plus(pow2_32.seconds) + assertEquals(pow2_32, instant3.epochSeconds) + } + + /* Based on the ThreeTenBp project. + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + */ + @Test + fun nanosecondAdjustment() { + for (i in -2..2L) { + for (j in 0..9) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i, t.epochSeconds) + assertEquals(j, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + for (j in -10..-1) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i - 1, t.epochSeconds) + assertEquals(j + 1000000000, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + for (j in 999_999_990..999_999_999) { + val t: Instant = Instant.fromEpochSeconds(i, j) + val t2: Instant = Instant.fromEpochSeconds(i, j.toLong()) + assertEquals(i, t.epochSeconds) + assertEquals(j, t.nanosecondsOfSecond) + assertEquals(t, t2) + } + } + val t = Instant.fromEpochSeconds(0, Int.MAX_VALUE) + assertEquals((Int.MAX_VALUE / 1_000_000_000).toLong(), t.epochSeconds) + assertEquals(Int.MAX_VALUE % 1_000_000_000, t.nanosecondsOfSecond) + val t2 = Instant.fromEpochSeconds(0, Long.MAX_VALUE) + assertEquals(Long.MAX_VALUE / 1_000_000_000, t2.epochSeconds) + assertEquals((Long.MAX_VALUE % 1_000_000_000).toInt(), t2.nanosecondsOfSecond) + } + + @Test + fun distantPastAndFuture() { + val distantFutureString = "+100000-01-01T00:00:00Z" + val distantPastString = "-100001-12-31T23:59:59.999999999Z" + assertEquals(distantFutureString, Instant.DISTANT_FUTURE.toString()) + assertEquals(Instant.DISTANT_FUTURE, Instant.parse(distantFutureString)) + assertEquals(distantPastString, Instant.DISTANT_PAST.toString()) + assertEquals(Instant.DISTANT_PAST, Instant.parse(distantPastString)) + assertTrue(Instant.DISTANT_PAST.isDistantPast) + assertTrue(Instant.DISTANT_FUTURE.isDistantFuture) + assertFalse(Instant.DISTANT_PAST.isDistantFuture) + assertFalse(Instant.DISTANT_FUTURE.isDistantPast) + assertFalse((Instant.DISTANT_PAST + 1.nanoseconds).isDistantPast) + assertFalse((Instant.DISTANT_FUTURE - 1.nanoseconds).isDistantFuture) + assertTrue((Instant.DISTANT_PAST - 1.nanoseconds).isDistantPast) + assertTrue((Instant.DISTANT_FUTURE + 1.nanoseconds).isDistantFuture) + assertTrue(Instant.MAX.isDistantFuture) + assertFalse(Instant.MAX.isDistantPast) + assertTrue(Instant.MIN.isDistantPast) + assertFalse(Instant.MIN.isDistantFuture) + } + +} + +class InstantRangeTest { + private val largePositiveLongs = listOf(Long.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE - 50) + private val largeNegativeLongs = listOf(Long.MIN_VALUE, Long.MIN_VALUE + 1, Long.MIN_VALUE + 50) + + private val largePositiveInstants = listOf(Instant.MAX, Instant.MAX - 1.seconds, Instant.MAX - 50.seconds) + private val largeNegativeInstants = listOf(Instant.MIN, Instant.MIN + 1.seconds, Instant.MIN + 50.seconds) + + private val smallInstants = listOf( + Instant.fromEpochMilliseconds(0), + Instant.fromEpochMilliseconds(1003), + Instant.fromEpochMilliseconds(253112) + ) + + + @Test + fun epochMillisecondsClamping() { + /* Any number of milliseconds in Long is representable as an Instant */ + for (instant in largePositiveInstants) { + assertEquals(Long.MAX_VALUE, instant.toEpochMilliseconds(), "$instant") + } + for (instant in largeNegativeInstants) { + assertEquals(Long.MIN_VALUE, instant.toEpochMilliseconds(), "$instant") + } + for (milliseconds in largePositiveLongs + largeNegativeLongs) { + assertEquals(milliseconds, Instant.fromEpochMilliseconds(milliseconds).toEpochMilliseconds(), + "$milliseconds") + } + } + + @Test + fun epochSecondsClamping() { + // fromEpochSeconds + // On all platforms Long.MAX_VALUE of seconds is not a valid instant. + for (seconds in largePositiveLongs) { + assertEquals(Instant.MAX, Instant.fromEpochSeconds(seconds, 35)) + } + for (seconds in largeNegativeLongs) { + assertEquals(Instant.MIN, Instant.fromEpochSeconds(seconds, 35)) + } + for (instant in largePositiveInstants + smallInstants + largeNegativeInstants) { + assertEquals(instant, Instant.fromEpochSeconds(instant.epochSeconds, instant.nanosecondsOfSecond.toLong())) + } + } + + @Test + fun durationArithmeticClamping() { + val longDurations = listOf(Duration.INFINITE) + + for (duration in longDurations) { + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant + duration) + } + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MIN, instant - duration) + } + } + assertEquals(Instant.MAX, (Instant.MAX - 4.seconds) + 5.seconds) + assertEquals(Instant.MIN, (Instant.MIN + 10.seconds) - 12.seconds) + } + + @Test + fun timeBasedUnitArithmeticOutOfRange() { + // Instant.plus(Long, DateTimeUnit.TimeBased) + // Arithmetic overflow + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant.plus(Long.MAX_VALUE.seconds)) + assertEquals(Instant.MIN, instant.plus(Long.MIN_VALUE.seconds)) + } + // Overflow of Instant boundaries + for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) { + assertEquals(Instant.MAX, instant.plus((Instant.MAX.epochSeconds - instant.epochSeconds + 1).seconds)) + assertEquals(Instant.MIN, instant.plus((Instant.MIN.epochSeconds - instant.epochSeconds - 1).seconds)) + } + } + + // https://github.com/Kotlin/kotlinx-datetime/issues/263 + @Test + fun addSmallDurationsToLargeInstants() { + for (smallDuration in listOf(1.nanoseconds, 999_999.nanoseconds, 1.seconds - 1.nanoseconds)) { + assertEquals(expected = Instant.MAX, actual = Instant.MAX + smallDuration) + assertEquals(expected = Instant.MIN, actual = Instant.MIN - smallDuration) + } + } + + @Test + fun subtractInstants() { + val max = Instant.fromEpochSeconds(31494816403199L) + val min = Instant.fromEpochSeconds(-31619119219200L) + assertEquals(max.epochSeconds - min.epochSeconds, (max - min).inWholeSeconds) + } +} class InstantIsoStringsTest { @@ -17,15 +221,18 @@ class InstantIsoStringsTest { this >= 0 -> toString().padStart(digits, '0') else -> "-${absoluteValue.toString().padStart(digits, '0')}" } + fun localDateToString(year: Int, month: Int, day: Int) = "${year.zeroPadded(4)}-${month.zeroPadded(2)}-${day.zeroPadded(2)}" + // only works for 1-4-digit years fun assertMonthBoundariesAreCorrect(year: Int, month: Int, lastDayOfMonth: Int) { val validString = "${localDateToString(year, month, lastDayOfMonth)}T23:59:59Z" val invalidString = "${localDateToString(year, month, lastDayOfMonth + 1)}T23:59:59Z" - parseInstant(validString) // shouldn't throw - assertInvalidFormat(invalidString) { parseInstant(invalidString) } + Instant.parse(validString) // shouldn't throw + assertInvalidFormat(invalidString) { Instant.parse(invalidString) } } + val nonLeapYears = listOf( 1970, 1971, 1973, 1974, 1975, 2021, 2022, 2023, 2100, 1100, 1, 2, 3, 5, -1, -2, -1971, 100, -100 ) @@ -195,12 +402,12 @@ class InstantIsoStringsTest { Triple("+673467211-06-05T02:15:40.712392732Z", 21252510297310540, 712392732), Triple("+982441727-04-13T12:12:06.776817565Z", 31002804263391126, 776817565), )) { - val instant = parseInstant(str) + val instant = Instant.parse(str) assertEquals( Instant.fromEpochSeconds(seconds, nanos), instant, "Parsed $instant from $str, with Unix time = `$seconds + 10^-9 * $nanos`" ) - assertEquals(str, displayInstant(instant)) + assertEquals(str, instant.toString()) } // non-canonical strings are parsed as well, but formatted differently for ((str, seconds, nanos) in arrayOf( @@ -210,7 +417,7 @@ class InstantIsoStringsTest { // current time Triple("2024-07-15T16:06:29.461245691+02:00", 1721052389, 461245691), )) { - val instant = parseInstant(str) + val instant = Instant.parse(str) assertEquals( seconds.toLong() * 1000 + nanos / 1000000, instant.toEpochMilliseconds(), "Parsed $instant from $str, with Unix time = `$seconds + 10^-9 * $nanos`" @@ -341,10 +548,10 @@ class InstantIsoStringsTest { "1970-02-03T04:05:06.123456789+01:2:60", "1970-02-03T04:05:06.123456789+01:12:6", )) { - assertInvalidFormat(nonIsoString) { parseInstant(nonIsoString) } + assertInvalidFormat(nonIsoString) { Instant.parse(nonIsoString) } } // this string represents an Instant that is currently larger than Instant.MAX any of the implementations: - assertInvalidFormat { parseInstant ("+1000000001-12-31T23:59:59.000000000Z") } + assertInvalidFormat { Instant.parse("+1000000001-12-31T23:59:59.000000000Z") } } @Test @@ -357,22 +564,22 @@ class InstantIsoStringsTest { Pair("2020-01-01T00:01:01+00", "2020-01-01T00:01:01Z"), ) strings.forEach { (str, strInZ) -> - val instant = parseInstant(str) - assertEquals(parseInstant(strInZ), instant, str) - assertEquals(strInZ, displayInstant(instant), str) + val instant = Instant.parse(str) + assertEquals(Instant.parse(strInZ), instant, str) + assertEquals(strInZ, instant.toString(), str) } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01+18:01") } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01+1801") } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01+0") } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01+") } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01") } - assertInvalidFormat { parseInstant("2020-01-01T00:01:01+000000") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+18:01") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+1801") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+0") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01") } + assertInvalidFormat { Instant.parse("2020-01-01T00:01:01+000000") } val instants = listOf( Instant.DISTANT_FUTURE, Instant.DISTANT_PAST, Instant.fromEpochSeconds(0, 0), - parseInstant("2020-01-02T03:04:05.6789Z"), + Instant.parse("2020-01-02T03:04:05.6789Z"), Instant.MAX, Instant.MIN, ) @@ -392,29 +599,10 @@ class InstantIsoStringsTest { if (instant == Instant.MAX && offsetSeconds < 0 || instant == Instant.MIN && offsetSeconds > 0 ) continue - val newInstant = parseInstant("${instant.toString().dropLast(1)}$offsetString") + val newInstant = Instant.parse("${instant.toString().dropLast(1)}$offsetString") assertEquals(newInstant, instant.minus(offsetSeconds.seconds)) } } } - private fun parseInstant(isoString: String): Instant { - // return Instant.parse(isoString) - return parseIso(isoString) - } - - private fun displayInstant(instant: Instant): String { - // return instant.toString() - return formatIso(instant) - } -} - - -@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") -@kotlin.internal.InlineOnly -private fun assertInvalidFormat(message: String? = null, f: () -> T) { - assertFailsWith(message) { - val result = f() - fail(result.toString()) - } } diff --git a/core/commonKotlin/test/ThreeTenBpInstantTest.kt b/fake-kotlinx-time/common/test/ThreeTenBpInstantTest.kt similarity index 98% rename from core/commonKotlin/test/ThreeTenBpInstantTest.kt rename to fake-kotlinx-time/common/test/ThreeTenBpInstantTest.kt index baf538cef..b56e18152 100644 --- a/core/commonKotlin/test/ThreeTenBpInstantTest.kt +++ b/fake-kotlinx-time/common/test/ThreeTenBpInstantTest.kt @@ -6,9 +6,9 @@ * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos */ -package kotlinx.datetime.test +package kotlinx.time.test -import kotlinx.datetime.* +import kotlinx.time.* import kotlin.test.* class ThreeTenBpInstantTest { diff --git a/fake-kotlinx-time/common/test/ThreeTenBpUtilTest.kt b/fake-kotlinx-time/common/test/ThreeTenBpUtilTest.kt new file mode 100644 index 000000000..a698f88df --- /dev/null +++ b/fake-kotlinx-time/common/test/ThreeTenBpUtilTest.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ +/* Based on the ThreeTenBp project. + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos + */ + +package kotlinx.time.test + +import kotlinx.time.* +import kotlin.test.* + +class ThreeTenBpUtilTest { + @Test + fun isLeap() { + assertEquals(false, isLeapYear(1999)) + assertEquals(true, isLeapYear(2000)) + assertEquals(false, isLeapYear(2001)) + assertEquals(false, isLeapYear(2007)) + assertEquals(true, isLeapYear(2008)) + assertEquals(false, isLeapYear(2009)) + assertEquals(false, isLeapYear(2010)) + assertEquals(false, isLeapYear(2011)) + assertEquals(true, isLeapYear(2012)) + assertEquals(false, isLeapYear(2095)) + assertEquals(true, isLeapYear(2096)) + assertEquals(false, isLeapYear(2097)) + assertEquals(false, isLeapYear(2098)) + assertEquals(false, isLeapYear(2099)) + assertEquals(false, isLeapYear(2100)) + assertEquals(false, isLeapYear(2101)) + assertEquals(false, isLeapYear(2102)) + assertEquals(false, isLeapYear(2103)) + assertEquals(true, isLeapYear(2104)) + assertEquals(false, isLeapYear(2105)) + assertEquals(false, isLeapYear(-500)) + assertEquals(true, isLeapYear(-400)) + assertEquals(false, isLeapYear(-300)) + assertEquals(false, isLeapYear(-200)) + assertEquals(false, isLeapYear(-100)) + assertEquals(true, isLeapYear(0)) + assertEquals(false, isLeapYear(100)) + assertEquals(false, isLeapYear(200)) + assertEquals(false, isLeapYear(300)) + assertEquals(true, isLeapYear(400)) + assertEquals(false, isLeapYear(500)) + } +} diff --git a/fake-kotlinx-time/common/test/assertions.kt b/fake-kotlinx-time/common/test/assertions.kt new file mode 100644 index 000000000..368f4c6b4 --- /dev/null +++ b/fake-kotlinx-time/common/test/assertions.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2021 JetBrains s.r.o. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ +package kotlinx.time.test + +import kotlin.test.assertFailsWith +import kotlin.test.fail + +inline fun assertInvalidFormat(message: String? = null, f: () -> T) { + assertFailsWith(message) { + val result = f() + fail(result.toString()) + } +} + +/** + * The number of iterations to perform in nondeterministic tests. + */ +const val STRESS_TEST_ITERATIONS = 1000 diff --git a/fake-kotlinx-time/common/test/samples/ClockSamples.kt b/fake-kotlinx-time/common/test/samples/ClockSamples.kt new file mode 100644 index 000000000..d799e6bf1 --- /dev/null +++ b/fake-kotlinx-time/common/test/samples/ClockSamples.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.datetime.test.samples + +import kotlinx.time.* +import kotlin.test.* + +class ClockSamples { + @Test + fun system() { + // Getting the current date and time + val currentInstant = Clock.System.now() + currentInstant.toEpochMilliseconds() // the number of milliseconds since the Unix epoch + } + + @Test + fun dependencyInjection() { + fun formatCurrentTime(clock: Clock): String = + clock.now().toString() + + // In the production code: + val currentTimeInProduction = formatCurrentTime(Clock.System) + // Testing this value is tricky because it changes all the time. + + // In the test code: + val testClock = object: Clock { + override fun now(): Instant = Instant.parse("2023-01-02T22:35:01Z") + } + // Then, one can write a completely deterministic test: + val currentTimeForTests = formatCurrentTime(testClock) + check(currentTimeForTests == "2023-01-02T22:35:01Z") + } +} diff --git a/fake-kotlinx-time/common/test/samples/InstantSamples.kt b/fake-kotlinx-time/common/test/samples/InstantSamples.kt new file mode 100644 index 000000000..af141866e --- /dev/null +++ b/fake-kotlinx-time/common/test/samples/InstantSamples.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.datetime.test.samples + +import kotlinx.time.* +import kotlin.random.* +import kotlin.test.* +import kotlin.time.Duration.Companion.hours + +class InstantSamples { + + @Test + fun epochSeconds() { + // Getting the number of whole seconds that passed since the Unix epoch + val instant1 = Instant.fromEpochSeconds(999_999, nanosecondAdjustment = 123_456_789) + check(instant1.epochSeconds == 999_999L) + val instant2 = Instant.fromEpochSeconds(1_000_000, nanosecondAdjustment = 100_123_456_789) + check(instant2.epochSeconds == 1_000_000 + 100L) + val instant3 = Instant.fromEpochSeconds(1_000_000, nanosecondAdjustment = -100_876_543_211) + check(instant3.epochSeconds == 1_000_000 - 101L) + } + + @Test + fun nanosecondsOfSecond() { + // Getting the number of nanoseconds that passed since the start of the second + val instant1 = Instant.fromEpochSeconds(999_999, nanosecondAdjustment = 123_456_789) + check(instant1.nanosecondsOfSecond == 123_456_789) + val instant2 = Instant.fromEpochSeconds(1_000_000, nanosecondAdjustment = 100_123_456_789) + check(instant2.nanosecondsOfSecond == 123_456_789) + val instant3 = Instant.fromEpochSeconds(1_000_000, nanosecondAdjustment = -100_876_543_211) + check(instant3.nanosecondsOfSecond == 123_456_789) + } + + @Test + fun toEpochMilliseconds() { + // Converting an Instant to the number of milliseconds since the Unix epoch + check(Instant.fromEpochMilliseconds(0).toEpochMilliseconds() == 0L) + check(Instant.fromEpochMilliseconds(1_000_000_000_123).toEpochMilliseconds() == 1_000_000_000_123L) + check(Instant.fromEpochSeconds(1_000_000_000, nanosecondAdjustment = 123_999_999) + .toEpochMilliseconds() == 1_000_000_000_123L) + } + + @Test + fun plusDuration() { + // Finding a moment that's later than the starting point by the given amount of real time + val instant = Instant.fromEpochSeconds(7 * 60 * 60, nanosecondAdjustment = 123_456_789) + val fiveHoursLater = instant + 5.hours + check(fiveHoursLater.epochSeconds == 12 * 60 * 60L) + check(fiveHoursLater.nanosecondsOfSecond == 123_456_789) + } + + @Test + fun minusDuration() { + // Finding a moment that's earlier than the starting point by the given amount of real time + val instant = Instant.fromEpochSeconds(7 * 60 * 60, nanosecondAdjustment = 123_456_789) + val fiveHoursEarlier = instant - 5.hours + check(fiveHoursEarlier.epochSeconds == 2 * 60 * 60L) + check(fiveHoursEarlier.nanosecondsOfSecond == 123_456_789) + } + + @Test + fun minusInstant() { + // Finding the difference between two instants in terms of elapsed time + check(Instant.fromEpochSeconds(0) - Instant.fromEpochSeconds(epochSeconds = 7 * 60 * 60) == (-7).hours) + } + + @Test + fun toStringSample() { + // Converting an Instant to a string + check(Instant.fromEpochSeconds(0).toString() == "1970-01-01T00:00:00Z") + } + + @Test + fun fromEpochMilliseconds() { + // Constructing an Instant from the number of milliseconds since the Unix epoch + check(Instant.fromEpochMilliseconds(epochMilliseconds = 0) == Instant.parse("1970-01-01T00:00:00Z")) + check(Instant.fromEpochMilliseconds(epochMilliseconds = 1_000_000_000_123) + == Instant.parse("2001-09-09T01:46:40.123Z")) + } + + @Test + fun fromEpochSeconds() { + // Constructing an Instant from the number of seconds and nanoseconds since the Unix epoch + check(Instant.fromEpochSeconds(epochSeconds = 0) == Instant.parse("1970-01-01T00:00:00Z")) + check(Instant.fromEpochSeconds(epochSeconds = 1_000_001_234, nanosecondAdjustment = -1_234_000_000_001) + == Instant.parse("2001-09-09T01:46:39.999999999Z")) + } + + @Test + fun fromEpochSecondsIntNanos() { + // Constructing an Instant from the number of seconds and nanoseconds since the Unix epoch + check(Instant.fromEpochSeconds(epochSeconds = 0) == Instant.parse("1970-01-01T00:00:00Z")) + check(Instant.fromEpochSeconds(epochSeconds = 1_000_000_000, nanosecondAdjustment = -1) == Instant.parse("2001-09-09T01:46:39.999999999Z")) + } + + @Test + fun parsing() { + // Parsing an Instant from a string + check(Instant.parse("1970-01-01T00:00:00Z") == Instant.fromEpochSeconds(0)) + } + + @Test + fun isDistantPast() { + // Checking if an instant is so far in the past that it's probably irrelevant + val currentInstant = Clock.System.now() + val tenThousandYearsAgo = currentInstant.minus(24.hours * 365 * 1_000) + check(!tenThousandYearsAgo.isDistantPast) + check(Instant.DISTANT_PAST.isDistantPast) + } + + @Test + fun isDistantFuture() { + // Checking if an instant is so far in the future that it's probably irrelevant + val currentInstant = Clock.System.now() + val tenThousandYearsLater = currentInstant.plus(24.hours * 365 * 10_000) + check(!tenThousandYearsLater.isDistantFuture) + check(Instant.DISTANT_FUTURE.isDistantFuture) + } +} diff --git a/core/js/src/Converters.kt b/fake-kotlinx-time/js/src/Converters.kt similarity index 96% rename from core/js/src/Converters.kt rename to fake-kotlinx-time/js/src/Converters.kt index a4a8c9df9..5e74ab188 100644 --- a/core/js/src/Converters.kt +++ b/fake-kotlinx-time/js/src/Converters.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ -package kotlinx.datetime +package kotlinx.time import kotlin.js.* diff --git a/fake-kotlinx-time/js/src/Platform.kt b/fake-kotlinx-time/js/src/Platform.kt new file mode 100644 index 000000000..52a3cbd31 --- /dev/null +++ b/fake-kotlinx-time/js/src/Platform.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +import kotlin.js.Date + +internal actual fun currentTime(): Instant = Instant.fromEpochMilliseconds(Date().getTime().toLong()) diff --git a/fake-kotlinx-time/js/test/ConvertersTest.kt b/fake-kotlinx-time/js/test/ConvertersTest.kt new file mode 100644 index 000000000..2d067b258 --- /dev/null +++ b/fake-kotlinx-time/js/test/ConvertersTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2019-2022 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time.test + +import kotlinx.time.* +import kotlin.js.Date +import kotlin.test.* + +class ConvertersTest { + @Test + fun toJSDateTest() { + val releaseInstant = Instant.parse("2016-02-15T00:00:00Z") + val releaseDate = releaseInstant.toJSDate() + assertEquals(2016, releaseDate.getUTCFullYear()) + assertEquals(1, releaseDate.getUTCMonth()) + assertEquals(15, releaseDate.getUTCDate()) + } + + @Test + fun toInstantTest() { + val kotlinReleaseEpochMilliseconds = 1455494400000 + val releaseDate = Date(milliseconds = kotlinReleaseEpochMilliseconds) + val releaseInstant = Instant.parse("2016-02-15T00:00:00Z") + assertEquals(releaseInstant, releaseDate.toKotlinInstant()) + } +} diff --git a/fake-kotlinx-time/jvm/src/Converters.kt b/fake-kotlinx-time/jvm/src/Converters.kt new file mode 100644 index 000000000..3774d4b37 --- /dev/null +++ b/fake-kotlinx-time/jvm/src/Converters.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2019-2022 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +/** + * Converts this [kotlin.time.Instant][Instant] value to a [java.time.Instant][java.time.Instant] value. + */ +public fun Instant.toJavaInstant(): java.time.Instant = + java.time.Instant.ofEpochSecond(epochSeconds, nanosecondsOfSecond.toLong()) + +/** + * Converts this [java.time.Instant][java.time.Instant] value to a [kotlin.time.Instant][Instant] value. + */ +public fun java.time.Instant.toKotlinInstant(): Instant = Instant.fromEpochSeconds(epochSecond, nano) diff --git a/fake-kotlinx-time/jvm/src/Platform.kt b/fake-kotlinx-time/jvm/src/Platform.kt new file mode 100644 index 000000000..96031eab0 --- /dev/null +++ b/fake-kotlinx-time/jvm/src/Platform.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +internal actual fun currentTime(): Instant = if (javaTimeAvailable) { + java.time.Instant.now().toKotlinInstant() +} else { + /* After experimenting in Android Studio, it seems like on Android with API < 24, only millisecond precision + is available in `Instant.now()` with core library desugaring enabled. Because of that, `currentTimeMillis` + is good enough + suggesting that our users enable core library desugaring isn't going to bring any benefits, + so the KDoc for [Clock] does not mention any of this. */ + Instant.fromEpochMilliseconds(System.currentTimeMillis()) +} + +/** + * `false` for Android devices with API level < 24, where java.time is not available. + */ +private val javaTimeAvailable = try { + java.time.Instant.now() + true +} catch (e: NoClassDefFoundError) { + false +} diff --git a/fake-kotlinx-time/jvm/test/ConvertersTest.kt b/fake-kotlinx-time/jvm/test/ConvertersTest.kt new file mode 100644 index 000000000..33b3018b7 --- /dev/null +++ b/fake-kotlinx-time/jvm/test/ConvertersTest.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2022 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ +package kotlinx.time.test + +import kotlinx.time.* +import kotlin.test.* +import kotlin.random.* +import java.time.Instant as JTInstant + +class ConvertersTest { + + @Test + fun instant() { + fun test(seconds: Long, nanosecond: Int) { + val ktInstant = Instant.fromEpochSeconds(seconds, nanosecond.toLong()) + val jtInstant = JTInstant.ofEpochSecond(seconds, nanosecond.toLong()) + + assertEquals(ktInstant, jtInstant.toKotlinInstant()) + assertEquals(jtInstant, ktInstant.toJavaInstant()) + + assertEquals(ktInstant, jtInstant.toString().let(Instant::parse)) + assertEquals(jtInstant, ktInstant.toString().let(JTInstant::parse)) + } + + repeat(STRESS_TEST_ITERATIONS) { + val seconds = Random.nextLong(1_000_000_000_000) + val nanos = Random.nextInt() + test(seconds, nanos) + } + } + +} diff --git a/core/native/src/internal/Platform.kt b/fake-kotlinx-time/native/src/Platform.kt similarity index 92% rename from core/native/src/internal/Platform.kt rename to fake-kotlinx-time/native/src/Platform.kt index 63b890610..8e036c159 100644 --- a/core/native/src/internal/Platform.kt +++ b/fake-kotlinx-time/native/src/Platform.kt @@ -3,10 +3,8 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ -package kotlinx.datetime.internal - +package kotlinx.time import kotlinx.cinterop.* -import kotlinx.datetime.Instant import platform.posix.* @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) @@ -20,4 +18,4 @@ internal actual fun currentTime(): Instant = memScoped { } catch (e: IllegalArgumentException) { throw IllegalStateException("The readings from the system clock (${tm.tv_sec} seconds, ${tm.tv_nsec} nanoseconds) are not representable as an Instant") } -} \ No newline at end of file +} diff --git a/fake-kotlinx-time/wasmJs/src/Platform.kt b/fake-kotlinx-time/wasmJs/src/Platform.kt new file mode 100644 index 000000000..f8c26688b --- /dev/null +++ b/fake-kotlinx-time/wasmJs/src/Platform.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2019-2024 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.time + +internal actual fun currentTime(): Instant = Instant.fromEpochMilliseconds(Date().getTime().toLong()) + +private external class Date { + fun getTime(): Double +} diff --git a/core/wasmWasi/src/internal/Platform.kt b/fake-kotlinx-time/wasmWasi/src/Platform.kt similarity index 95% rename from core/wasmWasi/src/internal/Platform.kt rename to fake-kotlinx-time/wasmWasi/src/Platform.kt index 1403cae7d..012e08c18 100644 --- a/core/wasmWasi/src/internal/Platform.kt +++ b/fake-kotlinx-time/wasmWasi/src/Platform.kt @@ -3,9 +3,8 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ -package kotlinx.datetime.internal +package kotlinx.time -import kotlinx.datetime.Instant import kotlin.wasm.WasmImport import kotlin.wasm.unsafe.UnsafeWasmMemoryApi import kotlin.wasm.unsafe.withScopedMemoryAllocator diff --git a/js-without-timezones/api/kotlinx-datetime-js-test-without-timezones.klib.api b/js-without-timezones/api/kotlinx-datetime-js-test-without-timezones.klib.api new file mode 100644 index 000000000..e69de29bb diff --git a/js-without-timezones/api/kotlinx-datetime-js-without-timezones.klib.api b/js-without-timezones/api/kotlinx-datetime-js-without-timezones.klib.api new file mode 100644 index 000000000..e69de29bb diff --git a/js-without-timezones/common/test/TimezonesWithoutDatabaseTest.kt b/js-without-timezones/common/test/TimezonesWithoutDatabaseTest.kt index 4fd7aef51..8924bf52d 100644 --- a/js-without-timezones/common/test/TimezonesWithoutDatabaseTest.kt +++ b/js-without-timezones/common/test/TimezonesWithoutDatabaseTest.kt @@ -9,6 +9,8 @@ import kotlinx.datetime.* import kotlin.test.* import kotlinx.datetime.test.JSJoda.ZoneId as jtZoneId import kotlinx.datetime.test.JSJoda.Instant as jtInstant +import kotlinx.time.Instant +import kotlinx.time.Clock class TimezonesWithoutDatabaseTest { @Test diff --git a/serialization/api/kotlinx-datetime-serialization.api b/serialization/api/kotlinx-datetime-serialization.api new file mode 100644 index 000000000..e69de29bb diff --git a/serialization/api/kotlinx-datetime-serialization.klib.api b/serialization/api/kotlinx-datetime-serialization.klib.api new file mode 100644 index 000000000..e69de29bb diff --git a/serialization/common/test/InstantSerializationTest.kt b/serialization/common/test/DeprecatedInstantSerializationTest.kt similarity index 97% rename from serialization/common/test/InstantSerializationTest.kt rename to serialization/common/test/DeprecatedInstantSerializationTest.kt index dea5c2dbd..74686eae7 100644 --- a/serialization/common/test/InstantSerializationTest.kt +++ b/serialization/common/test/DeprecatedInstantSerializationTest.kt @@ -2,6 +2,8 @@ * Copyright 2019-2020 JetBrains s.r.o. * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ + +@file:Suppress("DEPRECATION_ERROR") package kotlinx.datetime.serialization.test import kotlinx.datetime.* @@ -10,7 +12,7 @@ import kotlinx.serialization.* import kotlinx.serialization.json.* import kotlin.test.* -class InstantSerializationTest { +class DeprecatedInstantSerializationTest { private fun iso8601Serialization(serializer: KSerializer) { for ((instant, json) in listOf( diff --git a/serialization/common/test/IntegrationTest.kt b/serialization/common/test/IntegrationTest.kt index 0452a10fd..c721e1bd6 100644 --- a/serialization/common/test/IntegrationTest.kt +++ b/serialization/common/test/IntegrationTest.kt @@ -3,13 +3,13 @@ * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. */ +@file:Suppress("DEPRECATION_ERROR") package kotlinx.datetime.serialization.test import kotlinx.datetime.* import kotlinx.datetime.serializers.* import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule @@ -127,4 +127,4 @@ class IntegrationTest { assertEquals(dummyValue, format.decodeFromString(json)) assertEquals(json, format.encodeToString(dummyValue)) } -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index a342b81fd..84e43653b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,3 +23,5 @@ project(":serialization").name = "kotlinx-datetime-serialization" include(":js-without-timezones") project(":js-without-timezones").name = "kotlinx-datetime-js-test-without-timezones" include(":benchmarks") + +include(":fake-kotlinx-time") diff --git a/timezones/full/api/kotlinx-datetime-zoneinfo.klib.api b/timezones/full/api/kotlinx-datetime-zoneinfo.klib.api new file mode 100644 index 000000000..47db68f89 --- /dev/null +++ b/timezones/full/api/kotlinx-datetime-zoneinfo.klib.api @@ -0,0 +1,8 @@ +// Klib ABI Dump +// Targets: [wasmWasi] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: