Skip to content

Safe Time is a highly customizable Kotlin library that can be used to get time from NTP servers. It should work on JVM-based multiplatform projects including Android.

License

Notifications You must be signed in to change notification settings

kaungkhantjc/SafeTime

Repository files navigation

Safe Time

Safe Time AI logo

Safe Time is a highly customizable Kotlin library that can be used to get time from NTP servers. It should work on JVM-based multiplatform projects including Android.

Table of Contents

Why Safe Time?

If users manually adjust their clocks, System.currentTimeMillis() may reflect these changes, leading to unreliable timestamps. Safe Time library ensures a consistent, unaffected time source for your app.

Download

Maven Central

For Android using Gradle

implementation("io.github.kaungkhantjc:safeTime-android:1.0.1")

For JVM-based multiplatform projects using Gradle

implementation("io.github.kaungkhantjc:safeTime-core:1.0.1")

SafeTime jar downloads are available from Maven Central.

Usage

Create SafeTime instance in application class and sync time once app starts.

class App : Application() {

    val safeTime by lazy {
        SafeTime.Builder()
            .setNTPHosts("time.android.com", "time.google.com")
            .elapsedTimeAPI { SystemClock.elapsedRealtime() }
            .build()
    }

    override fun onCreate() {
        super.onCreate()
        safeTime.sync()
    }

}

Then we can use like this. We can also use Hilt to inject SafeTime instance.

val safeTime = (application as? App)?.safeTime

SafeTime instance functions

  • now()

    Retrieves the current timestamp based on cached time. It throws SafeTimeException if the cached time is invalid.

    val currentTimestamp = safeTime.now()
  • nowOrSync(...)

    Retrieves the current timestamp using cached time or synchronizes with NTP servers.

    safeTime.nowOrSync(object: SafeTimeListener {
        override fun onSuccessful(safeTimeInfo: SafeTimeInfo) {
            val currentTimestamp = safeTimeInfo.timestamp
        }
    })

    We can also use lifecycle-aware coroutine scope for automatic cancellation.

    safeTime.nowOrSync(lifecycleScope, safeTimeListener)
  • nowOrElse(...)

    Retrieves the current timestamp from cached time or returns the provided default value

    val currentTimestamp = safeTime.nowOrElse { System.currentTimeMillis() }
  • nowOrDefault()

    Retrieves the current timestamp from cached time or the device's System.currentTimeMillis() if the cached time is invalid.

    val currentTimestamp = safeTime.nowOrDefault()
  • cancel()

    Cancels the synchronization job

    safeTime.cancel()
  • sync()

    Synchronizes time with NTP servers. This function checks the validity of the cached time using SafeTimeCache. If the cached time is valid, the synchronization process is skipped.

    safeTime.sync()
  • sync(listener)

    Immediately synchronizes time with NTP servers, ignoring cached time.

    safeTime.sync(object: SafeTimeListener {
        override fun onSuccessful(safeTimeInfo: SafeTimeInfo) {
            val currentTimestamp = safeTimeInfo.timestamp
        }
    })

SafeTime.Builder functions

val safeTime = SafeTime.Builder()
    .setNTPHosts("time.android.com", "time.google.com")
    .addNTPHost("time.aws.com")
    .elapsedTimeAPI { SystemClock.elapsedRealtime() }
    .syncDispatcher(Dispatchers.IO)
    .listenerDispatcher(Dispatchers.Main)
    .setListener(safeTimeListener)
    .cache(PreferenceSafeTimeCache(this))
    .connectionTimeout(3.seconds)
    .maxRetryPerHost(0)
    .maxRetryLoop(0)
    .delayBetweenRetryLoop(0.seconds)
    .rootDelayMax(100)
    .rootDispersionMax(100)
    .serverResponseDelayMax(750.milliseconds)
    .build()

How it works?

Safe Time uses NTPUDPClient from Apache Commons Net to sync time from NTP servers. More information can be found on the Apache Commons Net homepage.

For correct time calculation, Safe Time uses Clock synchronization algorithm.

correct time = response time + clock offset

Response time is calculated like this.

response time = request time + (response ticks - request ticks)

  • request time is obtained from System.currentTimeMillis() before NTPUDPClient call is made.
  • request ticks is obtained from System.currentTimeMillis() (SystemClock.elapsedRealtime() in Android) before NTPUDPClient call is made.
  • response ticks is obtained from System.currentTimeMillis() (SystemClock.elapsedRealtime() in Android) after NTPUDPClient call is made.

The extent of the clock offset θ is directly proportional to the discrepancy between real-time and response time.

To calculates the clock offset θ, we need:

  • originate time t0
  • receive time t1
  • transmit time t2
  • response time t3

t0, t1 and t2 are obtained from Apache Commons Net library.

clock offset θ

clock offset θ = ((t1 - t0) + (t2 - t3)) / 2

TODO

  • Full documentation

Used libraries

Safe Time is inspired by the awesome TrueTime for Android library. Code structure is inspired by the awesome Coil library.

Contributing

We'd love to accept your patches and contributions to this project. All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.

Please perform a quick search to check if there are already existing issues or pull requests related to your contribution.

License

Safe Time is released under the Apache 2.0 license.

Copyright 2024 Safe Time Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

About

Safe Time is a highly customizable Kotlin library that can be used to get time from NTP servers. It should work on JVM-based multiplatform projects including Android.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages