query method
Queries the configured NTP server and returns a full NtpResponse with RFC 5905 telemetry.
When samples > 1, performs a multi-sample burst and selects the
measurement with the lowest round-trip delay (RFC 5905 clock filter).
Implementation
@override
Future<NtpResponse> query({int samples = 1}) async {
assert(samples >= 1, 'samples must be at least 1.');
final ntpAddress = await _resolveAddress();
_RawNtpSample? bestSample;
Object? lastError;
StackTrace? lastStack;
for (var i = 0; i < samples; i++) {
try {
final sample = await _querySingleSample(ntpAddress);
if (bestSample == null || sample.rttMicros < bestSample.rttMicros) {
bestSample = sample;
}
} catch (e, s) {
lastError = e;
lastStack = s;
if (samples == 1) rethrow;
}
}
if (bestSample == null) {
Error.throwWithStackTrace(
lastError ?? Exception('All $samples NTP samples failed'),
lastStack ?? StackTrace.current,
);
}
// Apply offset after all async cleanup has finished to prevent microtask/socket lag.
final correctedTime =
DateTime.now().add(Duration(microseconds: bestSample.offsetMicros));
return NtpResponse(
dateTime: isUtc ? correctedTime.toUtc() : correctedTime.toLocal(),
offset: Duration(microseconds: bestSample.offsetMicros),
roundTripDelay: Duration(microseconds: bestSample.rttMicros),
server: server,
stratum: bestSample.stratum,
leapIndicator: bestSample.leapIndicator,
referenceId: bestSample.referenceId,
rootDelay: Duration(microseconds: bestSample.rootDelayMicros),
rootDispersion: Duration(microseconds: bestSample.rootDispersionMicros),
);
}