文档章节

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

北风其凉
 北风其凉
发布于 2016/05/05 23:04
字数 1104
阅读 275
收藏 4

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

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

先定义几个概念:

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

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

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

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

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

        /// <summary>
        /// 获取系统时间:本地时间+偏移量+校正值
        /// </summary>
        /// <returns></returns>
        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;
            }
        }

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

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

        /// <summary>
        /// 将 yyyyMMddHHmmss 格式的字符串转换为 DateTime 结构
        /// </summary>
        /// <param name="sDateTime"></param>
        /// <returns></returns>
        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

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 115
博文 498
码字总数 463468
作品 4
朝阳
程序员
私信 提问
C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编...

zhujunxxxxx
2015/03/16
0
0
C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编...

zhujunxxxxx
2015/03/15
0
0
C#网络编程系列文章(一)之Socket实现异步TCP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编...

zhujunxxxxx
2015/03/14
0
0
C#网络编程系列文章(二)之Socket实现同步TCP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编...

zhujunxxxxx
2015/03/14
0
0
C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系列文章(一)之Socket实现异步TCP服务器 C#网络编...

zhujunxxxxx
2015/03/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SpringBoot整合Mybatis扫描不到Mapper的问题

参考资料 1、SpringBoot整合Mybatis扫描不到Mapper的问题

哎小艾
10分钟前
3
0
网络相关.md

https://github.com/acBool/Blogs/blob/master/%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3/%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3.md URL URL: 全称Uniform Resource Location,统一资源定位符,......

壹峰
10分钟前
0
0
Ubuntu虚拟机无法连接到网络

查看本机中控制面板---管理工具---服务 找到服务(本地) 确保 VMware DHCP Service 和VMware NAT Service 服务已经启动 查看Ubuntu的ip地址 显示ip则连接成功...

唐十三郎
16分钟前
0
0
MyEclipse开发教程:REST Web Service(二)

MyEclipse 在线订购年终抄底促销!火爆开抢>> MyEclipse最新版下载 使用MyEclipse开发RESTWeb服务来放大您的Web应用程序。在本教程示例中,您将创建一个简单的Web服务来维护客户列表。你将学...

电池盒
17分钟前
0
0
线程sleep和yield的区别

1.sleep()方法暂停当前线程后,会给其他线程执行机会,线程优先级对此没有影响。yield()方法会给优先级相同或更高的线程更高的执行机会。 2.sleep()方法会将线程转入阻塞状态,直到阻塞时间结...

勇敢的飞石
17分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部