An RFC 5905 compliant Simple Network Time Protocol (SNTP) client library for Rust.
rsntp
provides an API to synchronize time with SNTPv4 time servers with the following features:
- Provides both a synchronous (blocking) and an (optional) asynchronous,
tokio
based API - Optional support for time and date crates
chrono
andtime
(chrono
is enabled by default) - IPv6 support
Add this to your Cargo.toml
:
[dependencies]
rsntp = "4.0.0"
Obtain the current local time with the blocking API:
use rsntp::SntpClient;
use chrono::{DateTime, Local};
let client = SntpClient::new();
let result = client.synchronize("pool.ntp.org").unwrap();
let local_time: DateTime<Local> =
DateTime::from(result.datetime().into_chrono_datetime().unwrap());
println!("Current time is: {}", local_time);
You can also use the asynchronous API to do the same:
use rsntp::AsyncSntpClient;
use chrono::{DateTime, Local, Utc};
async fn local_time() -> DateTime<Local> {
let client = AsyncSntpClient::new();
let result = client.synchronize("pool.ntp.org").await.unwrap();
DateTime::from(result.datetime().into_chrono_datetime().unwrap())
}
Version 3.0 made core code independent of time and date crates and added support for the time
crate.
This led to some breaking API changes, SynchronizationResult
methods will return with wrappers
struct instead of chrono
ones. Those wrapper structs has TryInto
implementation and helper
methods to convert them to chrono
format.
To convert old code, replace
let datetime = result.datetime();
with
let datetime = result.datetime().into_chrono_datetime().unwrap();
or with
let datetime: chrono::DateTime<Utc> = result.datetime().try_into().unwrap();
The same applies to Duration
s returned by SynchronizationResult
.
rsntp
supports returning time and date data in different formats. Currently the format of
the two most popular time and date handling crates supported: chrono
and time
.
By default, chrono
is enabled, but you can add time
support with a feature:
use rsntp::SntpClient;
let client = SntpClient::new();
let result = client.synchronize("pool.ntp.org").unwrap();
let utc_time = result
.datetime()
.into_offset_date_time()
.unwrap();
println!("UTC time is: {}", utc_time);
Support for both crates can be enabled independently; you can even enable both at the same time.
The asynchronous API is enabled by default, but you can disable it. Disabling it
has the advantage that it removes the dependency to tokio
, which reduces
the amount of dependencies significantly.
[dependencies]
rsntp = { version = "4.0.0", default-features = false, features = ["chrono"] }
rsntp
assumes that system clock is monotonic and stable. This is especially important
with the SynchronizationResult::datetime()
method, as SynchronizationResult
stores just
an offset to the system clock. If the system clock is changed between synchronization
and the call to this method, then offset will not be valid anymore and some undefined result
will be returned.
rsntp
supports IPv6, but for compatibility reasons, it binds its UDP socket to an
IPv4 address (0.0.0.0) by default. That might prevent synchronization with IPv6 servers.
To use IPv6, you need to set an IPv6 bind address:
use rsntp::{Config, SntpClient};
use std::net::Ipv6Addr;
let config = Config::default().bind_address((Ipv6Addr::UNSPECIFIED, 0).into());
let client = SntpClient::with_config(config);
let result = client.synchronize("2.pool.ntp.org").unwrap();
let unix_timestamp_utc = result.datetime().unix_timestamp();