Repository: thunderbird/thunderbird-android (language: kotlin)

Issue:
Updated Kotlinx Datetime to 0.7.0
Kotlinx Datetime needs to be updated to 0.7.0. There are some breaking changes listed in the Release notes that could affect our project.

See also: 
- https://github.com/Kotlin/kotlinx-datetime/releases/tag/v0.7.0
- [Deprecation of Instant](https://github.com/Kotlin/kotlinx-datetime?tab=readme-ov-file#deprecation-of-instant)


Discussion hints:
nan

Pull request: chore(dependency): upgrade kotlinx.datetime to 0.7.0
Resolves #9397.


Test command: ./gradlew :legacy:ui:legacy:testDebugUnitTest --tests "com.fsck.k9.ui.helper.RelativeDateTimeFormatterTest" --tests "com.fsck.k9.ui.messagelist.MessageListAdapterTest" :core:common:testDebugUnitTest --tests "net.thunderbird.core.common.cache.ExpiringCacheTest" --tests "net.thunderbird.core.common.cache.CacheTest" :core:testing:testDebugUnitTest --tests "net.thunderbird.core.testing.TestClockTest" :legacy:core:testDebugUnitTest --tests "com.fsck.k9.notification.SummaryNotificationDataCreatorTest" --tests "com.fsck.k9.notification.NewMailNotificationManagerTest" --tests "com.fsck.k9.QuietTimeCheckerTest" :feature:funding:googleplay:testDebugUnitTest --tests "app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminderTest" --tests "app.k9mail.feature.funding.googleplay.ui.reminder.ActivityLifecycleObserverTest" :core:logging:api:testDebugUnitTest --tests "net.thunderbird.core.logging.DefaultLoggerTest"

Fix patch:
diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt
index f53aa9a9777..92e1c60d6b3 100644
--- a/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt
+++ b/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt
@@ -1,6 +1,7 @@
 package net.thunderbird.app.common.core
 
 import android.content.Context
+import kotlin.time.ExperimentalTime
 import net.thunderbird.app.common.BuildConfig
 import net.thunderbird.core.logging.DefaultLogger
 import net.thunderbird.core.logging.LogLevel
@@ -35,6 +36,7 @@ val appCommonCoreModule: Module = module {
     }
 
     single<Logger> {
+        @OptIn(ExperimentalTime::class)
         DefaultLogger(
             sink = get<CompositeLogSink>(),
         )
@@ -57,6 +59,7 @@ val appCommonCoreModule: Module = module {
     }
 
     single<Logger> (named(SYNC_DEBUG_LOG)) {
+        @OptIn(ExperimentalTime::class)
         DefaultLogger(
             sink = get<CompositeLogSink>(named(SYNC_DEBUG_LOG)),
         )
diff --git a/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt b/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt
index 06576d9ae59..2fb021c48f7 100644
--- a/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt
+++ b/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt
@@ -262,8 +262,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt b/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt
index 8ce56ac10a6..2f0f6e66590 100644
--- a/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt
+++ b/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt
@@ -276,8 +276,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt b/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt
index 3779b618d81..3d2667bc6af 100644
--- a/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt
@@ -269,8 +269,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt b/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt
index 3779b618d81..3d2667bc6af 100644
--- a/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt
@@ -269,8 +269,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt b/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt
index 3779b618d81..3d2667bc6af 100644
--- a/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt
@@ -269,8 +269,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt b/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt
index f94268c81d3..d0c664bbe71 100644
--- a/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt
@@ -283,8 +283,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt b/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt
index f94268c81d3..d0c664bbe71 100644
--- a/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt
@@ -283,8 +283,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt b/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt
index f94268c81d3..d0c664bbe71 100644
--- a/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt
+++ b/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt
@@ -283,8 +283,8 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.2
 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
-org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.2
-org.jetbrains.kotlinx:kotlinx-datetime:0.6.2
+org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.7.0
+org.jetbrains.kotlinx:kotlinx-datetime:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-bytestring:0.7.0
 org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.7.0
diff --git a/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactKoinModule.kt b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactKoinModule.kt
index df8c2e93abb..abcf1a0f15b 100644
--- a/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactKoinModule.kt
+++ b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactKoinModule.kt
@@ -1,6 +1,7 @@
 package app.k9mail.core.android.common.contact
 
 import android.content.Context
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.common.cache.Cache
 import net.thunderbird.core.common.cache.ExpiringCache
 import net.thunderbird.core.common.cache.SynchronizedCache
@@ -10,6 +11,7 @@ import org.koin.dsl.module
 
 internal val contactModule = module {
     single<Cache<EmailAddress, Contact?>>(named(CACHE_NAME)) {
+        @OptIn(ExperimentalTime::class)
         SynchronizedCache(
             delegateCache = ExpiringCache(clock = get()),
         )
diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/CoreCommonModule.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/CoreCommonModule.kt
index e2717ddc1e9..a85d7f83336 100644
--- a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/CoreCommonModule.kt
+++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/CoreCommonModule.kt
@@ -1,12 +1,14 @@
 package net.thunderbird.core.common
 
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.common.oauth.InMemoryOAuthConfigurationProvider
 import net.thunderbird.core.common.oauth.OAuthConfigurationProvider
 import org.koin.core.module.Module
 import org.koin.dsl.module
 
 val coreCommonModule: Module = module {
+    @OptIn(ExperimentalTime::class)
     single<Clock> { Clock.System }
 
     single<OAuthConfigurationProvider> {
diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/cache/ExpiringCache.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/cache/ExpiringCache.kt
index b60728744be..38dfd52619d 100644
--- a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/cache/ExpiringCache.kt
+++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/cache/ExpiringCache.kt
@@ -1,9 +1,12 @@
 package net.thunderbird.core.common.cache
 
-import kotlinx.datetime.Clock
-import kotlinx.datetime.Instant
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 
-class ExpiringCache<KEY : Any, VALUE : Any?>(
+class ExpiringCache<KEY : Any, VALUE : Any?>
+@OptIn(ExperimentalTime::class)
+constructor(
     private val clock: Clock,
     private val delegateCache: Cache<KEY, VALUE> = InMemoryCache(),
     private var lastClearTime: Instant = clock.now(),
@@ -26,6 +29,7 @@ class ExpiringCache<KEY : Any, VALUE : Any?>(
     }
 
     override fun clear() {
+        @OptIn(ExperimentalTime::class)
         lastClearTime = clock.now()
         delegateCache.clear()
     }
@@ -37,6 +41,7 @@ class ExpiringCache<KEY : Any, VALUE : Any?>(
     }
 
     private fun isExpired(): Boolean {
+        @OptIn(ExperimentalTime::class)
         return (clock.now() - lastClearTime).inWholeMilliseconds >= cacheTimeValidity
     }
 
diff --git a/core/logging/api/src/commonMain/kotlin/net/thunderbird/core/logging/DefaultLogger.kt b/core/logging/api/src/commonMain/kotlin/net/thunderbird/core/logging/DefaultLogger.kt
index 40561d92935..2a7f1eb9091 100644
--- a/core/logging/api/src/commonMain/kotlin/net/thunderbird/core/logging/DefaultLogger.kt
+++ b/core/logging/api/src/commonMain/kotlin/net/thunderbird/core/logging/DefaultLogger.kt
@@ -1,6 +1,7 @@
 package net.thunderbird.core.logging
 
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 
 /**
  * Default implementation of [Logger] that logs messages to a [LogSink].
@@ -8,7 +9,9 @@ import kotlinx.datetime.Clock
  * @param sink The [LogSink] to which log events will be sent.
  * @param clock The [Clock] used to get the current time for log events. Defaults to the system clock.
  */
-class DefaultLogger(
+class DefaultLogger
+@OptIn(ExperimentalTime::class)
+constructor(
     private val sink: LogSink,
     private val clock: Clock = Clock.System,
 ) : Logger {
@@ -21,13 +24,15 @@ class DefaultLogger(
     ) {
         sink.let { currentSink ->
             if (currentSink.canLog(level)) {
+                @OptIn(ExperimentalTime::class)
+                val timestamp = clock.now().toEpochMilliseconds()
                 currentSink.log(
                     event = LogEvent(
                         level = level,
                         tag = tag,
                         message = message(),
                         throwable = throwable,
-                        timestamp = clock.now().toEpochMilliseconds(),
+                        timestamp = timestamp,
                     ),
                 )
             }
diff --git a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt
index a0a157fee5f..954e2ff8018 100644
--- a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt
+++ b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt
@@ -5,13 +5,14 @@ import java.io.FileInputStream
 import java.io.FileOutputStream
 import java.io.IOException
 import kotlin.coroutines.CoroutineContext
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
-import kotlinx.datetime.Instant
 import kotlinx.datetime.LocalDateTime
 import kotlinx.datetime.TimeZone
 import kotlinx.datetime.toLocalDateTime
@@ -63,6 +64,7 @@ open class AndroidFileLogSink(
         }
     }
 
+    @OptIn(ExperimentalTime::class)
     private fun convertLongToTime(long: Long): String {
         val instant = Instant.fromEpochMilliseconds(long)
         val dateTime = instant.toLocalDateTime(TimeZone.currentSystemDefault())
diff --git a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/domain/usecase/FormatServerCertificateError.kt b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/domain/usecase/FormatServerCertificateError.kt
index de89a6b6a41..7274dccada4 100644
--- a/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/domain/usecase/FormatServerCertificateError.kt
+++ b/feature/account/server/certificate/src/main/kotlin/app/k9mail/feature/account/server/certificate/domain/usecase/FormatServerCertificateError.kt
@@ -7,12 +7,14 @@ import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertifi
 import java.security.cert.X509Certificate
 import java.text.DateFormat
 import java.util.Date
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import okio.ByteString
 import okio.HashingSink
 import okio.blackholeSink
 import okio.buffer
 
+@OptIn(ExperimentalTime::class)
 class FormatServerCertificateError(
     private val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT),
 ) : UseCase.FormatServerCertificateError {
diff --git a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/FeatureFundingModule.kt b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/FeatureFundingModule.kt
index cc0d7360ea6..a42ac6fbded 100644
--- a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/FeatureFundingModule.kt
+++ b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/FeatureFundingModule.kt
@@ -21,6 +21,7 @@ import app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminder
 import app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminderContract
 import app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminderDialog
 import com.android.billingclient.api.ProductDetails
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.common.cache.Cache
 import net.thunderbird.core.common.cache.InMemoryCache
 import org.koin.core.module.dsl.viewModel
@@ -38,12 +39,14 @@ val featureFundingModule = module {
     }
 
     single<FundingReminderContract.ActivityLifecycleObserver> {
+        @OptIn(ExperimentalTime::class)
         ActivityLifecycleObserver(
             settings = get(),
         )
     }
 
     single<FundingReminderContract.Reminder> {
+        @OptIn(ExperimentalTime::class)
         FundingReminder(
             settings = get(),
             fragmentObserver = get(),
diff --git a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserver.kt b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserver.kt
index 8607731e394..bee4d62e96c 100644
--- a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserver.kt
+++ b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserver.kt
@@ -5,9 +5,12 @@ import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleObserver
 import androidx.lifecycle.LifecycleOwner
 import app.k9mail.feature.funding.api.FundingSettings
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 
-class ActivityLifecycleObserver(
+class ActivityLifecycleObserver
+@OptIn(ExperimentalTime::class)
+constructor(
     private val settings: FundingSettings,
     private val clock: Clock = Clock.System,
 ) : FundingReminderContract.ActivityLifecycleObserver {
@@ -35,12 +38,14 @@ class ActivityLifecycleObserver(
 
             override fun onResume(owner: LifecycleOwner) {
                 super.onResume(owner)
+                @OptIn(ExperimentalTime::class)
                 startTime = clock.now().toEpochMilliseconds()
             }
 
             override fun onPause(owner: LifecycleOwner) {
                 super.onPause(owner)
 
+                @OptIn(ExperimentalTime::class)
                 val endTime = clock.now().toEpochMilliseconds()
                 val newActiveTime = endTime - startTime
                 val oldActiveTime = settings.getActivityCounterInMillis()
diff --git a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminder.kt b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminder.kt
index 2ea743c87d7..9581d3fa301 100644
--- a/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminder.kt
+++ b/feature/funding/googleplay/src/main/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminder.kt
@@ -7,9 +7,12 @@ import androidx.fragment.app.FragmentManager
 import app.k9mail.feature.funding.api.FundingSettings
 import app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminderContract.ActivityLifecycleObserver
 import app.k9mail.feature.funding.googleplay.ui.reminder.FundingReminderContract.FragmentLifecycleObserver
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 
-class FundingReminder(
+class FundingReminder
+@OptIn(ExperimentalTime::class)
+constructor(
     private val settings: FundingSettings,
     private val fragmentObserver: FragmentLifecycleObserver,
     private val activityCounterObserver: ActivityLifecycleObserver,
@@ -66,6 +69,7 @@ class FundingReminder(
     }
 
     private fun shouldShowReminder(): Boolean {
+        @OptIn(ExperimentalTime::class)
         val currentTime = clock.now().toEpochMilliseconds()
 
         return settings.getReminderShownTimestamp() == 0L &&
@@ -79,6 +83,7 @@ class FundingReminder(
             val installTime = context.packageManager.getPackageInfo(context.packageName, 0).firstInstallTime
             settings.setReminderReferenceTimestamp(installTime)
         } catch (exception: NameNotFoundException) {
+            @OptIn(ExperimentalTime::class)
             settings.setReminderReferenceTimestamp(clock.now().toEpochMilliseconds())
         }
     }
@@ -86,6 +91,7 @@ class FundingReminder(
     private fun showFundingReminderDialog(fragmentManager: FragmentManager) {
         // We're about to show the funding reminder dialog. So mark it as being shown. This way, if there's an error,
         // we err on the side of the dialog not being shown rather than it being shown more than once.
+        @OptIn(ExperimentalTime::class)
         settings.setReminderShownTimestamp(clock.now().toEpochMilliseconds())
 
         dialog.show(fragmentManager)
diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt
index 887d0bf5bca..85b119853b8 100644
--- a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt
+++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt
@@ -1,6 +1,7 @@
 package net.thunderbird.feature.notification.api.content
 
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import kotlinx.datetime.LocalDateTime
 import kotlinx.datetime.TimeZone
 import kotlinx.datetime.toLocalDateTime
@@ -57,6 +58,8 @@ sealed interface Notification {
  */
 sealed class AppNotification : Notification {
     override val accessibilityText: String = title
+
+    @OptIn(ExperimentalTime::class)
     override val createdAt: LocalDateTime = Clock.System.now().toLocalDateTime(timeZone = TimeZone.UTC)
     override val actions: Set<NotificationAction> = emptySet()
     override val authenticationRequired: Boolean = false
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0a70937fb81..e5651069071 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -81,7 +81,7 @@ kotlinGradleBom = "2.0.21"
 kotlinKsp = "2.1.21-2.0.2"
 kotlinxCoroutines = "1.10.2"
 kotlinxCollectionsImmutable = "0.4.0"
-kotlinxDateTime = "0.6.2"
+kotlinxDateTime = "0.7.0"
 kotlinxIoCore = "0.7.0"
 kotlinxSerialization = "1.8.1"
 ktlint = "1.5.0"
diff --git a/legacy/core/src/main/java/com/fsck/k9/QuietTimeChecker.kt b/legacy/core/src/main/java/com/fsck/k9/QuietTimeChecker.kt
index 5627e3ec72a..43e17c2dfea 100644
--- a/legacy/core/src/main/java/com/fsck/k9/QuietTimeChecker.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/QuietTimeChecker.kt
@@ -1,10 +1,17 @@
 package com.fsck.k9
 
 import java.util.Calendar
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 
 private const val MINUTES_PER_HOUR = 60
-class QuietTimeChecker(private val clock: Clock, quietTimeStart: String, quietTimeEnd: String) {
+class QuietTimeChecker
+@OptIn(ExperimentalTime::class)
+constructor(
+    private val clock: Clock,
+    quietTimeStart: String,
+    quietTimeEnd: String,
+) {
     private val quietTimeStart: Int = parseTime(quietTimeStart)
     private val quietTimeEnd: Int = parseTime(quietTimeEnd)
 
@@ -16,6 +23,7 @@ class QuietTimeChecker(private val clock: Clock, quietTimeStart: String, quietTi
             }
 
             val calendar = Calendar.getInstance()
+            @OptIn(ExperimentalTime::class)
             calendar.timeInMillis = clock.now().toEpochMilliseconds()
 
             val minutesSinceMidnight =
diff --git a/legacy/core/src/main/java/com/fsck/k9/job/KoinModule.kt b/legacy/core/src/main/java/com/fsck/k9/job/KoinModule.kt
index e238f2779b9..8378d7723ba 100644
--- a/legacy/core/src/main/java/com/fsck/k9/job/KoinModule.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/job/KoinModule.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import androidx.work.WorkManager
 import androidx.work.WorkerFactory
 import androidx.work.WorkerParameters
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.logging.Logger
 import org.koin.core.qualifier.named
 import org.koin.dsl.module
@@ -20,7 +21,12 @@ val jobModule = module {
         )
     }
     factory {
-        MailSyncWorkerManager(workManager = get(), clock = get(), syncDebugLogger = get<Logger>(named("syncDebug")))
+        @OptIn(ExperimentalTime::class)
+        MailSyncWorkerManager(
+            workManager = get(),
+            clock = get(),
+            syncDebugLogger = get<Logger>(named("syncDebug")),
+        )
     }
     factory { (parameters: WorkerParameters) ->
         MailSyncWorker(messagingController = get(), preferences = get(), context = get(), parameters)
diff --git a/legacy/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/legacy/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt
index 75dd645aad9..73c0253388d 100644
--- a/legacy/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt
@@ -9,12 +9,15 @@ import androidx.work.WorkManager
 import androidx.work.workDataOf
 import com.fsck.k9.K9
 import java.util.concurrent.TimeUnit
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.android.account.LegacyAccount
 import net.thunderbird.core.logging.Logger
 import net.thunderbird.core.logging.legacy.Log
 
-class MailSyncWorkerManager(
+class MailSyncWorkerManager
+@OptIn(ExperimentalTime::class)
+constructor(
     private val workManager: WorkManager,
     val clock: Clock,
     val syncDebugLogger: Logger,
@@ -79,6 +82,7 @@ class MailSyncWorkerManager(
     }
 
     private fun calculateInitialDelay(lastSyncTime: Long, syncIntervalMinutes: Long): Long {
+        @OptIn(ExperimentalTime::class)
         val now = clock.now().toEpochMilliseconds()
         val nextSyncTime = lastSyncTime + (syncIntervalMinutes * 60L * 1000L)
 
diff --git a/legacy/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/legacy/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index ece8a4d5c74..da93913cc64 100644
--- a/legacy/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/legacy/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -46,7 +46,7 @@
 import com.fsck.k9.mailstore.LockableDatabase.SchemaDefinition;
 import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
 import net.thunderbird.feature.search.sql.SqlWhereClause;
-import kotlinx.datetime.Clock;
+import kotlin.time.Clock;
 import net.thunderbird.core.android.account.LegacyAccount;
 import net.thunderbird.feature.search.LocalMessageSearch;
 import net.thunderbird.feature.search.api.SearchAttribute;
diff --git a/legacy/core/src/main/java/com/fsck/k9/mailstore/OutboxStateRepository.kt b/legacy/core/src/main/java/com/fsck/k9/mailstore/OutboxStateRepository.kt
index b819854ad9e..a5075327886 100644
--- a/legacy/core/src/main/java/com/fsck/k9/mailstore/OutboxStateRepository.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/mailstore/OutboxStateRepository.kt
@@ -5,9 +5,12 @@ import app.k9mail.core.android.common.database.getIntOrThrow
 import app.k9mail.core.android.common.database.getLongOrThrow
 import app.k9mail.core.android.common.database.getStringOrNull
 import app.k9mail.core.android.common.database.getStringOrThrow
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 
-class OutboxStateRepository(
+class OutboxStateRepository
+@OptIn(ExperimentalTime::class)
+constructor(
     private val database: LockableDatabase,
     private val clock: Clock,
 ) {
@@ -79,6 +82,7 @@ class OutboxStateRepository(
     }
 
     fun setSendAttemptError(messageId: Long, errorMessage: String) {
+        @OptIn(ExperimentalTime::class)
         val sendErrorTimestamp = clock.now().toEpochMilliseconds()
 
         database.execute(false) { db ->
@@ -93,6 +97,7 @@ class OutboxStateRepository(
     }
 
     fun setSendAttemptsExceeded(messageId: Long) {
+        @OptIn(ExperimentalTime::class)
         val sendErrorTimestamp = clock.now().toEpochMilliseconds()
 
         database.execute(false) { db ->
diff --git a/legacy/core/src/main/java/com/fsck/k9/notification/CoreNotificationKoinModule.kt b/legacy/core/src/main/java/com/fsck/k9/notification/CoreNotificationKoinModule.kt
index d13f8ff1d9f..82b9857ddfa 100644
--- a/legacy/core/src/main/java/com/fsck/k9/notification/CoreNotificationKoinModule.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/notification/CoreNotificationKoinModule.kt
@@ -4,6 +4,7 @@ import android.app.NotificationManager
 import android.content.Context
 import androidx.core.app.NotificationManagerCompat
 import java.util.concurrent.Executors
+import kotlin.time.ExperimentalTime
 import org.koin.dsl.module
 
 val coreNotificationModule = module {
@@ -71,6 +72,7 @@ val coreNotificationModule = module {
         )
     }
     single {
+        @OptIn(ExperimentalTime::class)
         NewMailNotificationManager(
             contentCreator = get(),
             notificationRepository = get(),
diff --git a/legacy/core/src/main/java/com/fsck/k9/notification/NewMailNotificationManager.kt b/legacy/core/src/main/java/com/fsck/k9/notification/NewMailNotificationManager.kt
index 17f934eb385..5514d24edc5 100644
--- a/legacy/core/src/main/java/com/fsck/k9/notification/NewMailNotificationManager.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/notification/NewMailNotificationManager.kt
@@ -2,13 +2,16 @@ package com.fsck.k9.notification
 
 import app.k9mail.legacy.message.controller.MessageReference
 import com.fsck.k9.mailstore.LocalMessage
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.android.account.LegacyAccount
 
 /**
  * Manages notifications for new messages
  */
-internal class NewMailNotificationManager(
+internal class NewMailNotificationManager
+@OptIn(ExperimentalTime::class)
+constructor(
     private val contentCreator: NotificationContentCreator,
     private val notificationRepository: NotificationRepository,
     private val baseNotificationDataCreator: BaseNotificationDataCreator,
@@ -134,5 +137,6 @@ internal class NewMailNotificationManager(
         }
     }
 
+    @OptIn(ExperimentalTime::class)
     private fun now(): Long = clock.now().toEpochMilliseconds()
 }
diff --git a/legacy/core/src/main/java/com/fsck/k9/preferences/AccountSettingsWriter.kt b/legacy/core/src/main/java/com/fsck/k9/preferences/AccountSettingsWriter.kt
index 8ba1e6d63d1..7b2c1c561f1 100644
--- a/legacy/core/src/main/java/com/fsck/k9/preferences/AccountSettingsWriter.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/preferences/AccountSettingsWriter.kt
@@ -5,7 +5,8 @@ import com.fsck.k9.Core
 import com.fsck.k9.Preferences
 import com.fsck.k9.mailstore.SpecialLocalFoldersCreator
 import java.util.UUID
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.android.account.LegacyAccount
 import net.thunderbird.core.preference.storage.StorageEditor
 import net.thunderbird.feature.account.storage.legacy.LegacyAccountStorageHandler.Companion.ACCOUNT_DESCRIPTION_KEY
@@ -13,7 +14,9 @@ import net.thunderbird.feature.account.storage.legacy.LegacyAccountStorageHandle
 import net.thunderbird.feature.account.storage.legacy.LegacyAccountStorageHandler.Companion.OUTGOING_SERVER_SETTINGS_KEY
 import net.thunderbird.feature.account.storage.legacy.serializer.ServerSettingsDtoSerializer
 
-internal class AccountSettingsWriter(
+internal class AccountSettingsWriter
+@OptIn(ExperimentalTime::class)
+constructor(
     private val preferences: Preferences,
     private val localFoldersCreator: SpecialLocalFoldersCreator,
     private val clock: Clock,
@@ -50,6 +53,7 @@ internal class AccountSettingsWriter(
         // When deleting an account and then restoring it using settings import, the same account UUID will be used.
         // To avoid reusing a previously existing notification channel ID, we need to make sure to use a unique value
         // for `messagesNotificationChannelVersion`.
+        @OptIn(ExperimentalTime::class)
         val messageNotificationChannelVersion = clock.now().epochSeconds.toString()
         editor.putStringWithLogging(
             key = "$accountUuid.messagesNotificationChannelVersion",
diff --git a/legacy/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt b/legacy/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
index 27455af0fe1..0e268394ee9 100644
--- a/legacy/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
@@ -1,6 +1,7 @@
 package com.fsck.k9.preferences
 
 import com.fsck.k9.Preferences
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.preference.DefaultPreferenceChangeBroker
 import net.thunderbird.core.preference.GeneralSettingsManager
 import net.thunderbird.core.preference.PreferenceChangeBroker
@@ -76,6 +77,7 @@ val preferencesModule = module {
     }
 
     factory {
+        @OptIn(ExperimentalTime::class)
         AccountSettingsWriter(
             preferences = get(),
             localFoldersCreator = get(),
diff --git a/legacy/core/src/main/java/com/fsck/k9/preferences/RealGeneralSettingsManager.kt b/legacy/core/src/main/java/com/fsck/k9/preferences/RealGeneralSettingsManager.kt
index e1313f65287..604f5d2ee75 100644
--- a/legacy/core/src/main/java/com/fsck/k9/preferences/RealGeneralSettingsManager.kt
+++ b/legacy/core/src/main/java/com/fsck/k9/preferences/RealGeneralSettingsManager.kt
@@ -6,6 +6,8 @@ import app.k9mail.legacy.di.DI
 import com.fsck.k9.K9
 import com.fsck.k9.Preferences
 import com.fsck.k9.QuietTimeChecker
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -13,7 +15,6 @@ import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
-import kotlinx.datetime.Clock
 import net.thunderbird.core.logging.legacy.Log
 import net.thunderbird.core.preference.AppTheme
 import net.thunderbird.core.preference.BackgroundSync
@@ -59,7 +60,6 @@ internal class RealGeneralSettingsManager(
 ) : GeneralSettingsManager, PrivacySettingsManager by privacySettingsManager {
     private val settingsFlow = MutableSharedFlow<GeneralSettings>(replay = 1)
     private var generalSettings: GeneralSettings? = null
-    val clock = DI.get<Clock>()
 
     @Deprecated("This only exists for collaboration with the K9 class")
     val storage: Storage
@@ -339,7 +339,13 @@ internal class RealGeneralSettingsManager(
         if (isQuietTimeEnabled) {
             return false
         }
-        val quietTimeChecker = QuietTimeChecker(clock, quietTimeStarts, quietTimeEnds)
+
+        @OptIn(ExperimentalTime::class)
+        val quietTimeChecker = QuietTimeChecker(
+            clock = DI.get<Clock>(),
+            quietTimeStart = quietTimeStarts,
+            quietTimeEnd = quietTimeEnds,
+        )
         return quietTimeChecker.isQuietTime
     }
 }
diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatter.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatter.kt
index 14911766be4..dacd4857a21 100644
--- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatter.kt
+++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatter.kt
@@ -12,18 +12,22 @@ import android.text.format.DateUtils.FORMAT_SHOW_YEAR
 import java.util.Calendar
 import java.util.Calendar.DAY_OF_WEEK
 import java.util.Calendar.YEAR
-import kotlinx.datetime.Clock
-import kotlinx.datetime.Instant
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 
 /**
  * Formatter to describe timestamps as a time relative to now.
  */
-class RelativeDateTimeFormatter(
+class RelativeDateTimeFormatter
+@OptIn(ExperimentalTime::class)
+constructor(
     private val context: Context,
     private val clock: Clock,
 ) {
 
     fun formatDate(timestamp: Long): String {
+        @OptIn(ExperimentalTime::class)
         val now = clock.now().toCalendar()
         val date = timestamp.toCalendar()
         val format = when {
@@ -42,6 +46,7 @@ private fun Long.toCalendar(): Calendar {
     return calendar
 }
 
+@OptIn(ExperimentalTime::class)
 private fun Instant.toCalendar(): Calendar {
     val calendar = Calendar.getInstance()
     calendar.timeInMillis = this.toEpochMilliseconds()
diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt
index 03ce092fb17..97237f62079 100644
--- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt
+++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt
@@ -63,12 +63,13 @@ import com.google.android.material.snackbar.BaseTransientBottomBar.BaseCallback
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.textview.MaterialTextView
 import java.util.concurrent.Future
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
-import kotlinx.datetime.Clock
 import net.jcip.annotations.GuardedBy
 import net.thunderbird.core.android.account.AccountManager
 import net.thunderbird.core.android.account.Expunge
@@ -107,6 +108,8 @@ class MessageListFragment :
     private val messagingController: MessagingController by inject()
     private val accountManager: AccountManager by inject()
     private val connectivityManager: ConnectivityManager by inject()
+
+    @OptIn(ExperimentalTime::class)
     private val clock: Clock by inject()
     private val setupArchiveFolderDialogFragmentFactory: SetupArchiveFolderDialogFragmentFactory by inject()
     private val legacyAccountWrapperDataMapper: DataMapper<
@@ -304,6 +307,7 @@ class MessageListFragment :
     }
 
     private fun createMessageListAdapter(): MessageListAdapter {
+        @OptIn(ExperimentalTime::class)
         return MessageListAdapter(
             theme = requireActivity().theme,
             res = resources,
diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/view/KoinModule.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/view/KoinModule.kt
index bd9ef5f5961..6f34a2d0882 100644
--- a/legacy/ui/legacy/src/main/java/com/fsck/k9/view/KoinModule.kt
+++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/view/KoinModule.kt
@@ -5,11 +5,15 @@ import com.fsck.k9.mailstore.AttachmentResolver
 import com.fsck.k9.message.ReplyActionStrategy
 import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
 import com.fsck.k9.view.MessageWebView.OnPageFinishedListener
+import kotlin.time.ExperimentalTime
 import org.koin.dsl.module
 
 val viewModule = module {
     single { WebViewConfigProvider(themeManager = get(), generalSettingsManager = get()) }
-    factory { RelativeDateTimeFormatter(context = get(), clock = get()) }
+    factory {
+        @OptIn(ExperimentalTime::class)
+        RelativeDateTimeFormatter(context = get(), clock = get())
+    }
     factory { ReplyToParser() }
     factory { ReplyActionStrategy(replyRoParser = get()) }
     factory { (attachmentResolver: AttachmentResolver?, onPageFinishedListener: OnPageFinishedListener?) ->


Test patch:
diff --git a/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/CacheTest.kt b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/CacheTest.kt
index 8409e3ce9ec..ff0ea54c86e 100644
--- a/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/CacheTest.kt
+++ b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/CacheTest.kt
@@ -6,6 +6,7 @@ import assertk.assertions.isFalse
 import assertk.assertions.isNull
 import assertk.assertions.isTrue
 import kotlin.test.Test
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.testing.TestClock
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -28,7 +29,10 @@ class CacheTest(data: CacheTestData<Any, Any?>) {
         fun data(): Collection<CacheTestData<Any, Any?>> {
             return listOf(
                 CacheTestData("InMemoryCache") { InMemoryCache() },
-                CacheTestData("ExpiringCache") { ExpiringCache(TestClock(), InMemoryCache()) },
+                CacheTestData("ExpiringCache") {
+                    @OptIn(ExperimentalTime::class)
+                    ExpiringCache(TestClock(), InMemoryCache())
+                },
                 CacheTestData("SynchronizedCache") { SynchronizedCache(InMemoryCache()) },
             )
         }
diff --git a/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/ExpiringCacheTest.kt b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/ExpiringCacheTest.kt
index 31aaab2332f..108a544db29 100644
--- a/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/ExpiringCacheTest.kt
+++ b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/cache/ExpiringCacheTest.kt
@@ -6,6 +6,7 @@ import assertk.assertions.isFalse
 import assertk.assertions.isNull
 import kotlin.test.Test
 import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.common.cache.Cache
 import net.thunderbird.core.common.cache.ExpiringCache
 import net.thunderbird.core.common.cache.InMemoryCache
@@ -13,8 +14,10 @@ import net.thunderbird.core.testing.TestClock
 
 class ExpiringCacheTest {
 
+    @OptIn(ExperimentalTime::class)
     private val clock = TestClock()
 
+    @OptIn(ExperimentalTime::class)
     private val testSubject: Cache<String, String> = ExpiringCache(clock, InMemoryCache())
 
     @Test
diff --git a/core/logging/api/src/commonTest/kotlin/net/thunderbird/core/logging/DefaultLoggerTest.kt b/core/logging/api/src/commonTest/kotlin/net/thunderbird/core/logging/DefaultLoggerTest.kt
index c84ffe38cfa..2f8d44f142e 100644
--- a/core/logging/api/src/commonTest/kotlin/net/thunderbird/core/logging/DefaultLoggerTest.kt
+++ b/core/logging/api/src/commonTest/kotlin/net/thunderbird/core/logging/DefaultLoggerTest.kt
@@ -5,9 +5,11 @@ import assertk.assertions.hasSize
 import assertk.assertions.isEqualTo
 import kotlin.test.Test
 import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import net.thunderbird.core.testing.TestClock
 
+@OptIn(ExperimentalTime::class)
 class DefaultLoggerTest {
 
     @Test
diff --git a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt
index 7c17148d403..10449459f34 100644
--- a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt
+++ b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt
@@ -5,10 +5,11 @@ import assertk.assertions.isEqualTo
 import assertk.assertions.isNotNull
 import java.io.File
 import kotlin.test.Test
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.datetime.Instant
 import kotlinx.datetime.LocalDateTime
 import kotlinx.datetime.TimeZone
 import kotlinx.datetime.toLocalDateTime
@@ -44,6 +45,8 @@ class AndroidFileLogSinkTest {
             coroutineContext = UnconfinedTestDispatcher(),
         )
     }
+
+    @OptIn(ExperimentalTime::class)
     fun timeSetup(timeStamp: Long): String {
         val instant = Instant.fromEpochMilliseconds(timeStamp)
         val dateTime = instant.toLocalDateTime(TimeZone.currentSystemDefault())
diff --git a/core/testing/src/commonMain/kotlin/net/thunderbird/core/testing/TestClock.kt b/core/testing/src/commonMain/kotlin/net/thunderbird/core/testing/TestClock.kt
index 5acd77b0912..6ddb19ca19f 100644
--- a/core/testing/src/commonMain/kotlin/net/thunderbird/core/testing/TestClock.kt
+++ b/core/testing/src/commonMain/kotlin/net/thunderbird/core/testing/TestClock.kt
@@ -1,9 +1,11 @@
 package net.thunderbird.core.testing
 
+import kotlin.time.Clock
 import kotlin.time.Duration
-import kotlinx.datetime.Clock
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 
+@OptIn(ExperimentalTime::class)
 class TestClock(
     private var currentTime: Instant = Clock.System.now(),
 ) : Clock {
diff --git a/core/testing/src/commonTest/kotlin/net/thunderbird/core/testing/TestClockTest.kt b/core/testing/src/commonTest/kotlin/net/thunderbird/core/testing/TestClockTest.kt
index 4922c09eaa1..651ea477a3e 100644
--- a/core/testing/src/commonTest/kotlin/net/thunderbird/core/testing/TestClockTest.kt
+++ b/core/testing/src/commonTest/kotlin/net/thunderbird/core/testing/TestClockTest.kt
@@ -4,8 +4,10 @@ import assertk.assertThat
 import assertk.assertions.isEqualTo
 import kotlin.test.Test
 import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 
+@OptIn(ExperimentalTime::class)
 internal class TestClockTest {
 
     @Test
diff --git a/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserverTest.kt b/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserverTest.kt
index 7382ea3f141..2f8583c423c 100644
--- a/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserverTest.kt
+++ b/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/ActivityLifecycleObserverTest.kt
@@ -5,12 +5,14 @@ import androidx.lifecycle.testing.TestLifecycleOwner
 import assertk.assertThat
 import assertk.assertions.isEqualTo
 import kotlin.test.Test
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import kotlinx.coroutines.test.runTest
-import kotlinx.datetime.Instant
 import net.thunderbird.core.testing.TestClock
 import net.thunderbird.core.testing.coroutines.MainDispatcherRule
 import org.junit.Rule
 
+@OptIn(ExperimentalTime::class)
 class ActivityLifecycleObserverTest {
 
     @get:Rule
diff --git a/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminderTest.kt b/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminderTest.kt
index 8c96b0c4a96..3a6bb1e4b39 100644
--- a/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminderTest.kt
+++ b/feature/funding/googleplay/src/test/kotlin/app/k9mail/feature/funding/googleplay/ui/reminder/FundingReminderTest.kt
@@ -14,13 +14,15 @@ import assertk.assertions.isEqualTo
 import assertk.assertions.isFalse
 import assertk.assertions.isTrue
 import kotlin.test.Test
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import net.thunderbird.core.testing.TestClock
 import net.thunderbird.core.testing.coroutines.MainDispatcherRule
 import org.junit.Rule
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 
+@OptIn(ExperimentalTime::class)
 class FundingReminderTest {
 
     @get:Rule
diff --git a/legacy/core/src/test/java/com/fsck/k9/QuietTimeCheckerTest.kt b/legacy/core/src/test/java/com/fsck/k9/QuietTimeCheckerTest.kt
index 8a93a45d97c..a2c856ee0a8 100644
--- a/legacy/core/src/test/java/com/fsck/k9/QuietTimeCheckerTest.kt
+++ b/legacy/core/src/test/java/com/fsck/k9/QuietTimeCheckerTest.kt
@@ -4,10 +4,12 @@ import assertk.assertThat
 import assertk.assertions.isFalse
 import assertk.assertions.isTrue
 import java.util.Calendar
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import net.thunderbird.core.testing.TestClock
 import org.junit.Test
 
+@OptIn(ExperimentalTime::class)
 class QuietTimeCheckerTest {
     private val clock = TestClock()
 
diff --git a/legacy/core/src/test/java/com/fsck/k9/notification/NewMailNotificationManagerTest.kt b/legacy/core/src/test/java/com/fsck/k9/notification/NewMailNotificationManagerTest.kt
index 294ec651e99..66fa5632bb4 100644
--- a/legacy/core/src/test/java/com/fsck/k9/notification/NewMailNotificationManagerTest.kt
+++ b/legacy/core/src/test/java/com/fsck/k9/notification/NewMailNotificationManagerTest.kt
@@ -18,7 +18,8 @@ import com.fsck.k9.mailstore.LocalStore
 import com.fsck.k9.mailstore.LocalStoreProvider
 import com.fsck.k9.mailstore.NotificationMessage
 import kotlin.test.assertNotNull
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import net.thunderbird.core.android.account.LegacyAccount
 import net.thunderbird.core.preference.AppTheme
 import net.thunderbird.core.preference.BackgroundSync
@@ -38,6 +39,7 @@ private const val ACCOUNT_COLOR = 0xFF112233L.toInt()
 private const val FOLDER_ID = 42L
 private const val TIMESTAMP = 23L
 
+@OptIn(ExperimentalTime::class)
 class NewMailNotificationManagerTest {
     private val mockedNotificationMessages = mutableListOf<NotificationMessage>()
     private val account = createAccount()
diff --git a/legacy/core/src/test/java/com/fsck/k9/notification/SummaryNotificationDataCreatorTest.kt b/legacy/core/src/test/java/com/fsck/k9/notification/SummaryNotificationDataCreatorTest.kt
index 0588f75a633..40c1a3188bc 100644
--- a/legacy/core/src/test/java/com/fsck/k9/notification/SummaryNotificationDataCreatorTest.kt
+++ b/legacy/core/src/test/java/com/fsck/k9/notification/SummaryNotificationDataCreatorTest.kt
@@ -9,7 +9,8 @@ import assertk.assertions.isFalse
 import assertk.assertions.isInstanceOf
 import assertk.assertions.isTrue
 import com.fsck.k9.K9
-import kotlinx.datetime.Clock
+import kotlin.time.Clock
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.android.account.LegacyAccount
 import net.thunderbird.core.preference.AppTheme
 import net.thunderbird.core.preference.BackgroundSync
@@ -29,6 +30,7 @@ import org.mockito.kotlin.mock
 
 private val TIMESTAMP = 0L
 
+@OptIn(ExperimentalTime::class)
 class SummaryNotificationDataCreatorTest {
     private val account = createAccount()
     private var generalSettings = GeneralSettings(
diff --git a/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatterTest.kt b/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatterTest.kt
index ed7a7a89a80..1a6e970a2ea 100644
--- a/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatterTest.kt
+++ b/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/helper/RelativeDateTimeFormatterTest.kt
@@ -8,7 +8,8 @@ import java.time.LocalDate
 import java.time.LocalDateTime
 import java.time.ZoneId
 import java.util.TimeZone
-import kotlinx.datetime.Instant
+import kotlin.time.ExperimentalTime
+import kotlin.time.Instant
 import net.thunderbird.core.android.testing.RobolectricTest
 import net.thunderbird.core.testing.TestClock
 import org.junit.Before
@@ -16,6 +17,7 @@ import org.junit.Test
 import org.robolectric.RuntimeEnvironment
 import org.robolectric.annotation.Config
 
+@OptIn(ExperimentalTime::class)
 @Config(
     qualifiers = "en",
     sdk = [Build.VERSION_CODES.S],
diff --git a/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt b/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt
index b60b330f2dd..dac4817955d 100644
--- a/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt
+++ b/legacy/ui/legacy/src/test/java/com/fsck/k9/ui/messagelist/MessageListAdapterTest.kt
@@ -24,6 +24,7 @@ import com.fsck.k9.mail.Address
 import com.fsck.k9.ui.R
 import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
 import com.google.android.material.textview.MaterialTextView
+import kotlin.time.ExperimentalTime
 import net.thunderbird.core.android.account.LegacyAccount
 import net.thunderbird.core.android.testing.RobolectricTest
 import net.thunderbird.core.testing.TestClock
@@ -413,6 +414,7 @@ class MessageListAdapterTest : RobolectricTest() {
             density,
         )
 
+        @OptIn(ExperimentalTime::class)
         return MessageListAdapter(
             theme = context.theme,
             res = context.resources,