在要求输入邮箱的文本域,请填写真实的邮件地址。非真实邮件地址,将收不到回复信息。

使用C#通过NTP同步本地Windows系统时间

C# 清风 3753℃ 4评论

每年春节买票都成为相当重要的事情,快人一步基本能尽可能的抢占先机。使用抢票软件尽可能的减少手工操作,从而提高抢票的成功机率,由于时间误差也可会丧失先机,所以同步系统时间也是重要一步。为了可以自动的同步本地时间,所以就使用C#实现一个时间同步小工具。

只针对Windows系统的时间同步且使用抢票平台的不在此列。
使用C#通过NTP同步本地Windows系统时间-第0张图片

using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsDateTimeSynchronization
{

    public class DateTimeSynchronization
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct Systemtime
        {
            public short year;
            public short month;
            public short dayOfWeek;
            public short day;
            public short hour;
            public short minute;
            public short second;
            public short milliseconds;
        }

        [DllImport("kernel32.dll")]
        private static extern bool SetLocalTime(ref Systemtime time);

        private static uint swapEndian(ulong x)
        {
            return (uint)(((x & 0x000000ff) << 24) +
            ((x & 0x0000ff00) << 8) +
            ((x & 0x00ff0000) >> 8) +
            ((x & 0xff000000) >> 24));
        }

        /// <summary>
        /// 设置系统时间
        /// </summary>
        /// <param name="dt">需要设置的时间</param>
        /// <returns>返回系统时间设置状态,true为成功,false为失败</returns>
        private static bool SetLocalDateTime(DateTime dt)
        {
            Systemtime st;
            st.year = (short)dt.Year;
            st.month = (short)dt.Month;
            st.dayOfWeek = (short)dt.DayOfWeek;
            st.day = (short)dt.Day;
            st.hour = (short)dt.Hour;
            st.minute = (short)dt.Minute;
            st.second = (short)dt.Second;
            st.milliseconds = (short)dt.Millisecond;
            bool rt = SetLocalTime(ref st);
            return rt;
        }
        private static IPAddress iPAddress = null;
        public static bool Synchronization(string host,out DateTime syncDateTime,out string message)
        {
            syncDateTime = DateTime.Now;
            try
            {
                message = "";
                if (iPAddress == null)
                {
                    var iphostinfo = Dns.GetHostEntry(host);
                    var ntpServer = iphostinfo.AddressList[0];
                    iPAddress = ntpServer;
                }
                //NTP消息大小摘要是16字节 (RFC 2030)
                byte[] ntpData = new byte[48];
                //设置跳跃指示器、版本号和模式值
                ntpData[0] = 0x1B; // LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
                IPAddress ip = iPAddress;
                // NTP服务给UDP分配的端口号是123
                IPEndPoint ipEndPoint = new IPEndPoint(ip, 123);
                // 使用UTP进行通讯
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                DateTime dtStart = DateTime.Now;
                socket.Connect(ipEndPoint);
                socket.ReceiveTimeout = 3000;
                socket.Send(ntpData);
                socket.Receive(ntpData);
                socket?.Close();
                socket?.Dispose();
                DateTime dtEnd = DateTime.Now;
                //传输时间戳字段偏移量,以64位时间戳格式,应答离开客户端服务器的时间
                const byte serverReplyTime = 40;
                // 获得秒的部分
                ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
                //获取秒的部分
                ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
                //由big-endian 到 little-endian的转换
                intPart = swapEndian(intPart);
                fractPart = swapEndian(fractPart);
                ulong milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000UL);
                // UTC时间
                DateTime webTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
                //webTime = webTime.Subtract(-(dtEnd - dtStart));
                //本地时间
                DateTime dt = webTime.ToLocalTime();
                bool isSuccess = SetLocalDateTime(dt);
                syncDateTime = dt;

            }
            catch (Exception ex)
            {
                message = ex.Message;
                return false;
            }
            return true;

        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("ntp时间同步");
            DateTime dt = DateTime.Now;
            Console.WriteLine($"现在本地时间:{dt.ToString("yyyy-MM-dd HH:mm:ss")}");
            string errorMessage = "";
            DateTimeSynchronization.Synchronization("ntp.aliyun.com",out dt,out errorMessage);
            if (string.IsNullOrWhiteSpace(errorMessage))
            {
                Console.WriteLine($"同步时间:{dt.ToString("yyyy-MM-dd HH:mm:ss")}");
            }
            Console.Read();
        }


    }
}


示例下载

通过NTP服务器同步Windows系统时间



转载请注明:清风亦平凡 » 使用C#通过NTP同步本地Windows系统时间

喜欢 (4)or分享 (0)
支付宝扫码打赏 支付宝扫码打赏 微信打赏 微信打赏
头像
发表我的评论
取消评论

CAPTCHA Image
Reload Image
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(4)个小伙伴在吐槽
  1. 头像
    win10无法修改,尝试不让本地自动更新时间和修改一个其他时间,仍然无法更新时间
    Mark2021-01-14 15:35 回复
    • 头像
      您好,WIndows 10 同步本地时间修改失败的原因是因为权限问题。同步时间是使用C#调用Windows系统中kernel32.dllSetLocalTimeAPI方法来处理,但调用这个方法需要足够的权限,所以会修改失败。使用管理员的身份来执行就没有问题。
      清风2021-01-15 09:05 回复
  2. 头像
    除了以管理员方式运行,C# 如何获取管理员权限呢,我试过都没有成功,大神有没有获取权限的
    Mark2021-01-15 09:52 回复
    • 头像
      使用UAC权限试一下。
      清风2021-01-15 11:07 回复