
Enables accurate network time synchronization via async coroutine-style API, automatic server pool fallback with retries, builder-based configuration, lightweight footprint, plus offset/snapshot time access.
A Kotlin Multiplatform SNTP (Simple Network Time Protocol) client library for accurate network time synchronization.
Add the dependency to your build.gradle.kts:
// For Kotlin Multiplatform projects
kotlin {
sourceSets {
commonMain.dependencies {
implementation("in.sitharaj:kronosync:1.0.0")
}
}
}
// For Android/JVM only projects
dependencies {
implementation("in.sitharaj:kronosync:1.0.0")
}import `in`.sitharaj.kronosync.KronoSync
import `in`.sitharaj.kronosync.SyncResult
// Initialize once at app startup
KronoSync.initialize()
// Sync with NTP servers
val result = KronoSync.sync()
when (result) {
is SyncResult.Success -> {
println("Synced! Offset: ${result.offset}")
println("Server: ${result.serverAddress}")
}
is SyncResult.Failure -> {
println("Failed: ${result.error}")
}
}
// Get network-synchronized time
val networkTime = KronoSync.now()
val timeMillis = KronoSync.currentTimeMillis()import `in`.sitharaj.kronosync.NtpConfig
import kotlin.time.Duration.Companion.seconds
KronoSync.initialize(
NtpConfig.Builder()
.ntpServers(listOf(
"time.google.com",
"time.apple.com",
"time.cloudflare.com"
))
.timeout(10.seconds)
.retryCount(3)
.retryDelay(1.seconds)
.build()
)For more control, use NtpClient directly instead of the singleton:
import `in`.sitharaj.kronosync.NtpClient
import `in`.sitharaj.kronosync.NtpConfig
val client = NtpClient(NtpConfig.DEFAULT)
// Sync
val result = client.sync()
// Get time
val now = client.now() // Returns null if not synced
val nowOrSystem = client.nowOrSystem() // Falls back to system time
// Get offset
val offset = client.offset()
// Check sync status
val isSynced = client.isSynchronized()
// Get full snapshot
val snapshot = client.snapshot()Add Internet permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />Initialize in your Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
KronoSync.initialize()
// Optional: sync in background
lifecycleScope.launch {
KronoSync.sync()
}
}
}Initialize in your app delegate or SwiftUI App:
import ComposeApp
@main
struct iOSApp: App {
init() {
KronoSyncKt.doInitialize()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}Due to browser security restrictions, raw UDP sockets are not available. KronoSync uses HTTP-based time APIs as a fallback on these platforms.
| Method | Description |
|---|---|
initialize(config) |
Initialize with optional configuration |
sync() |
Sync with NTP servers (suspend) |
now() |
Get network time or null |
nowOrSystem() |
Get network time or system time |
currentTimeMillis() |
Get time in epoch milliseconds |
offset() |
Get clock offset duration |
isSynchronized() |
Check if synced |
snapshot() |
Get full time snapshot |
reset() |
Reset sync state |
| Method | Default | Description |
|---|---|---|
ntpServers(list) |
Google, Apple, Cloudflare, etc. | NTP server hostnames |
timeout(duration) |
10 seconds | Request timeout |
retryCount(count) |
3 | Retry attempts per server |
retryDelay(duration) |
1 second | Delay between retries |
syncOnInit(bool) |
true | Sync automatically |
cacheDuration(duration) |
Infinite | Cache expiration |
Run the sample application:
# Desktop
./gradlew :sample:composeApp:run
# Android
./gradlew :sample:composeApp:installDebug
# iOS
open sample/iosApp/iosApp.xcworkspace./gradlew :kronosync:publishToMavenLocal~/.gradle/gradle.properties:signing.keyId=YOUR_KEY_ID
signing.password=YOUR_KEY_PASSWORD
signing.secretKeyRingFile=/path/to/secring.gpg./gradlew :kronosync:zipBundlekronosync/build/bundle/kronosync-bundle.zip at central.sonatype.com
Copyright 2024 Sitharaj Seenivasan
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.
Contributions are welcome! Please read our Contributing Guidelines first.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)A Kotlin Multiplatform SNTP (Simple Network Time Protocol) client library for accurate network time synchronization.
Add the dependency to your build.gradle.kts:
// For Kotlin Multiplatform projects
kotlin {
sourceSets {
commonMain.dependencies {
implementation("in.sitharaj:kronosync:1.0.0")
}
}
}
// For Android/JVM only projects
dependencies {
implementation("in.sitharaj:kronosync:1.0.0")
}import `in`.sitharaj.kronosync.KronoSync
import `in`.sitharaj.kronosync.SyncResult
// Initialize once at app startup
KronoSync.initialize()
// Sync with NTP servers
val result = KronoSync.sync()
when (result) {
is SyncResult.Success -> {
println("Synced! Offset: ${result.offset}")
println("Server: ${result.serverAddress}")
}
is SyncResult.Failure -> {
println("Failed: ${result.error}")
}
}
// Get network-synchronized time
val networkTime = KronoSync.now()
val timeMillis = KronoSync.currentTimeMillis()import `in`.sitharaj.kronosync.NtpConfig
import kotlin.time.Duration.Companion.seconds
KronoSync.initialize(
NtpConfig.Builder()
.ntpServers(listOf(
"time.google.com",
"time.apple.com",
"time.cloudflare.com"
))
.timeout(10.seconds)
.retryCount(3)
.retryDelay(1.seconds)
.build()
)For more control, use NtpClient directly instead of the singleton:
import `in`.sitharaj.kronosync.NtpClient
import `in`.sitharaj.kronosync.NtpConfig
val client = NtpClient(NtpConfig.DEFAULT)
// Sync
val result = client.sync()
// Get time
val now = client.now() // Returns null if not synced
val nowOrSystem = client.nowOrSystem() // Falls back to system time
// Get offset
val offset = client.offset()
// Check sync status
val isSynced = client.isSynchronized()
// Get full snapshot
val snapshot = client.snapshot()Add Internet permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />Initialize in your Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
KronoSync.initialize()
// Optional: sync in background
lifecycleScope.launch {
KronoSync.sync()
}
}
}Initialize in your app delegate or SwiftUI App:
import ComposeApp
@main
struct iOSApp: App {
init() {
KronoSyncKt.doInitialize()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}Due to browser security restrictions, raw UDP sockets are not available. KronoSync uses HTTP-based time APIs as a fallback on these platforms.
| Method | Description |
|---|---|
initialize(config) |
Initialize with optional configuration |
sync() |
Sync with NTP servers (suspend) |
now() |
Get network time or null |
nowOrSystem() |
Get network time or system time |
currentTimeMillis() |
Get time in epoch milliseconds |
offset() |
Get clock offset duration |
isSynchronized() |
Check if synced |
snapshot() |
Get full time snapshot |
reset() |
Reset sync state |
| Method | Default | Description |
|---|---|---|
ntpServers(list) |
Google, Apple, Cloudflare, etc. | NTP server hostnames |
timeout(duration) |
10 seconds | Request timeout |
retryCount(count) |
3 | Retry attempts per server |
retryDelay(duration) |
1 second | Delay between retries |
syncOnInit(bool) |
true | Sync automatically |
cacheDuration(duration) |
Infinite | Cache expiration |
Run the sample application:
# Desktop
./gradlew :sample:composeApp:run
# Android
./gradlew :sample:composeApp:installDebug
# iOS
open sample/iosApp/iosApp.xcworkspace./gradlew :kronosync:publishToMavenLocal~/.gradle/gradle.properties:signing.keyId=YOUR_KEY_ID
signing.password=YOUR_KEY_PASSWORD
signing.secretKeyRingFile=/path/to/secring.gpg./gradlew :kronosync:zipBundlekronosync/build/bundle/kronosync-bundle.zip at central.sonatype.com
Copyright 2024 Sitharaj Seenivasan
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.
Contributions are welcome! Please read our Contributing Guidelines first.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)