C#实现的客户端同步服务器时间管理工具类

今天做项目的时候遇到了一个问题,即客户端程序通过一个接口从后台获取到一个服务器时间后,需要在客户端的右下角实时展示服务器时间,并且要提供函数供客户端内的功能随时获取当前的服务器时间。

在这种情况下,每次都调用前后台接口获取服务器时间显然是不显示的,为此我想出了一个方法。

先定义几个概念:

1、历史本地时间(LocalDateTimeHis),即向后台请求服务器时间时获取到的本地时间

2、历史服务器时间(SysDateTimeHis),即向后台请求服务器时间时获取到的服务器时间

3、时间偏移量(Offset),时间偏移量=历史服务器时间-历史本地时间

4、手工校正值(Correct),可根据自身程序运行情况设置,我设置为1秒,以抵消网络延迟导致的时间差

5、当前服务器时间(SysDateTime),DateTime结构类型变量,系统时间=本地当前时间+偏移量+手工校正值

上面五项中,只要知道了(1)和(2),后面的(3)、(4)、(5)都可以计算出来,(1)可以通过DateTime.Now获取,(2)通过调用前后台接口获取。

下面是管理类的C#代码,需要说明:本工具类并未实现客户端获取服务器时间部分的代码,本工具类的功能是在客户端一次性获取服务器时间后,对外提供当前的服务器时间。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SystemDateTimeTest
{
    /// 
    /// 系统时间同步工具类
    /// 
    public static class SystemDateTimeHelper
    {
        /// 
        /// 工具类是否初始化
        /// 
        private static bool _isInit = false;
        /// 
        /// 工具类是否初始化 - 只有初始化后才能获取系统时间
        /// 
        public static bool IsInit
        {
            get
            {
                return _isInit;
            }
            private set
            {
                _isInit = value;
            }
        }

        /// 
        /// 更新时系统时间
        /// 
        private static DateTime _sysDateTimeHis;
        /// 
        /// 更新时系统时间
        /// 
        public static DateTime SysDateTimeHis
        {
            get
            {
                if (!IsInit)
                {
                    throw new Exception("时间同步功能未初始化");
                }
                return _sysDateTimeHis;
            }
            private set
            {
                _sysDateTimeHis = value;
            }
        }

        /// 
        /// 更新时本地时间
        /// 
        private static DateTime _localDateTimeHis;
        /// 
        /// 更新时本地时间
        /// 
        public static DateTime LocalDateTimeHis
        {
            get
            {
                if (!IsInit)
                {
                    throw new Exception("时间同步功能未初始化");
                }
                return _localDateTimeHis;
            }
            private set
            {
                _localDateTimeHis = value;
            }
        }

        /// 
        /// 偏移量
        /// 
        public static TimeSpan Offset
        {
            get
            {
                if (!IsInit)
                {
                    throw new Exception("时间同步功能未初始化");
                }
                return SysDateTimeHis - LocalDateTimeHis;
            }
        }

        /// 
        /// 手工校正值 - 由程序编写人员根据情况定义,这里采用1s作为偏移量
        /// 
        public static TimeSpan Correct
        {
            get
            {
                return new TimeSpan(hours: 0, minutes: 0, seconds: 1);
            }
        }

        /// 
        /// 获取系统时间:本地时间+偏移量+校正值
        /// 
        /// 
        public static DateTime SysDateTime
        {
            get
            {
                if (!IsInit)
                {
                    throw new Exception("时间同步功能未初始化");
                }
                DateTime dateTimeNow = DateTime.Now;
                DateTime dateTimeWithoutMill = new DateTime(
                    dateTimeNow.Year, dateTimeNow.Month, dateTimeNow.Day,
                    dateTimeNow.Hour, dateTimeNow.Minute, dateTimeNow.Second);
                return dateTimeWithoutMill + Offset + Correct;
            }
        }

        /// 
        /// 更新系统时间 yyyyMMddHHmmss
        /// 
        /// 
        public static void RefreshDateTime(string sysDateTime)
        {
            RefreshDateTime(sysDateTime, DateTime.Now.ToString("yyyyMMddHHmmss"));
        }

        /// 
        /// 更新系统时间 yyyyMMddHHmmss
        /// 
        /// 
        /// 
        public static void RefreshDateTime(string sysDateTime, string localDateTime)
        {
            //将系统时间与本地时间转换为DateTime
            DateTime SysDateTimeHisTmp = ConvertToDateTime(sysDateTime);
            DateTime LocalDateTimeHisTmp = ConvertToDateTime(localDateTime);
            //最后统一赋值,防止前面的代码发生异常后同步类计算结果错误
            SysDateTimeHis = SysDateTimeHisTmp;
            LocalDateTimeHis = LocalDateTimeHisTmp;
            IsInit = true;
        }

        /// 
        /// 将 yyyyMMddHHmmss 格式的字符串转换为 DateTime 结构
        /// 
        /// 
        /// 
        private static DateTime ConvertToDateTime(string sDateTime)
        {
            sDateTime = sDateTime.Trim();
            if (sDateTime.Length != 14)
            {
                throw new Exception("输入参数必须是格式为 yyyyMMddHHmmss 的14位字符串");
            }
            foreach (char ch in sDateTime)
            {
                if (ch < '0' || ch > '9')
                {
                    throw new Exception("输入参数必须是格式为 yyyyMMddHHmmss 的14位字符串");
                }
            }
            int year = int.Parse(sDateTime.Substring(0, 4));
            int month = int.Parse(sDateTime.Substring(4, 2));
            int day = int.Parse(sDateTime.Substring(6, 2));
            int hour = int.Parse(sDateTime.Substring(8, 2));
            int minute = int.Parse(sDateTime.Substring(10, 2));
            int second = int.Parse(sDateTime.Substring(12, 2));
            DateTime dateTimeResult = new DateTime(year, month, day, hour, minute, second);
            return dateTimeResult;
        }
    }
}

这个类的调用方法为:

1、客户端登录后,调用一次 SystemDateTimeHelper.RefreshDateTime 函数初始化该功能类,传入的时间必须是格式为“yyyyMMddHHmmss”的字符串。

2、功能类初始化后,可随时调用 SystemDateTimeHelper.SysDateTime 获取当前的服务器时间

3、建议每隔30分钟重新同步一次服务器时间,方法为在一个Interval为1秒的计时器中实现以下逻辑:

if (DateTime.Now - SystemDateTimeHelper.LocalDateTimeHis > new TimeSpan(0, 30, 0))
{
    //TODO:重新同步
}

END

转载于:https://my.oschina.net/Tsybius2014/blog/670611

你可能感兴趣的:(C#实现的客户端同步服务器时间管理工具类)