1use std::net::UdpSocket;
20use byteorder::{ BigEndian, ReadBytesExt };
21use std::io::{ Cursor, Seek, SeekFrom };
22use chrono::prelude::*;
23
24pub struct NtpClient;
25impl NtpClient {
26 pub fn new() -> NtpClient {
27 NtpClient
28 }
29 pub fn request(self, server: &str) -> Response {
30 let client = UdpSocket::bind("0.0.0.0:0").unwrap();
31 client.connect(format!("{server}:123")).unwrap();
32 let mut request_data = vec![0;48];
33 request_data[0] = 0x1b;
34 client.send(&request_data).unwrap();
35 let mut buf = [0; 48];
36 client.recv(&mut buf).unwrap();
37 let ntp_second = self.unpack_ntp_data(&buf);
38 let unix_second = ntp_second - 2208988800;
39 let response = Response {
40 unix_time: unix_second,
41 };
42 response
43 }
44 fn unpack_ntp_data(self, buffer: &[u8; 48]) -> u64 {
45 let mut reader = Cursor::new(buffer);
46 reader.seek(SeekFrom::Current(40)).unwrap();
47 let ntp_second = reader.read_u32::<BigEndian>().unwrap();
48 u64::from(ntp_second)
49 }
50}
51
52pub struct Response {
53 pub unix_time: u64,
54}
55
56impl Response {
57 pub fn format_time(self, fmt: &str) -> String {
58 let dt = DateTime::<Utc>::from_utc(
60 NaiveDateTime::from_timestamp_opt(
61 self.unix_time as i64,
62 ((self.unix_time % 1000) as u32) * 1_000_000
63 ).unwrap(),
64 Utc
65 );
66 let shanghai = FixedOffset::east_opt(8 * 3600).unwrap();
67 format!("{}", dt.with_timezone(&shanghai).format(fmt))
68 }
69}
70
71#[test]
72fn test() {
73 let client = NtpClient::new();
74 let res = client.request("ntp.aliyun.com");
75 println!("{}", res.unix_time);
76 println!("{}", res.format_time("%Y-%m-%d %H:%M:%S"));
77}