文档章节

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

北风其凉
 北风其凉
发布于 2016/05/05 23:04
字数 1104
阅读 244
收藏 4
点赞 1
评论 0

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

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

先定义几个概念:

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

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 114
博文 493
码字总数 462457
作品 4
朝阳
程序员
C#网络编程系列文章(一)之Socket实现异步TCP服务器

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

zhujunxxxxx ⋅ 2015/03/14 ⋅ 0

C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

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

zhujunxxxxx ⋅ 2015/03/15 ⋅ 0

C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

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

zhujunxxxxx ⋅ 2015/03/16 ⋅ 0

C#网络编程系列文章(二)之Socket实现同步TCP服务器

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

zhujunxxxxx ⋅ 2015/03/14 ⋅ 0

C#网络编程系列文章(六)之Socket实现同步UDP服务器

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

zhujunxxxxx ⋅ 2015/03/16 ⋅ 0

C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

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

zhujunxxxxx ⋅ 2015/03/14 ⋅ 0

C#网络编程系列文章(五)之Socket实现异步UDP服务器

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

zhujunxxxxx ⋅ 2015/03/15 ⋅ 0

C# WinForm开发系列 - Socket/WCF/Rometing/Web Services

当今社会是一个信息化社会, 网络越来越多地影响人民的生活, 带来巨大的便利性; 而网络通信在软件开发中占据相当大的比重. Socket/WCF/Rometing/Web Services 各种技术纷至踏来, 应用广泛; 而...

长征2号 ⋅ 2017/08/11 ⋅ 0

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

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

zhujunxxxxx ⋅ 2015/03/16 ⋅ 0

Thrift 简易入门与实战

简介 thrift是一个软件框架, 用来进行可扩展且跨语言的服务的开发. 它结合了功能强大的软件堆栈和代码生成引擎, 以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Co...

永顺 ⋅ 2017/03/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从零开始搭建Risc-v Rocket环境---(1)

为了搭建Rocke环境,我买了一个2T的移动硬盘,安装的ubuntu-16.04 LTS版。没有java8,gcc是5.4.0 joe@joe-Inspiron-7460:~$ java -version程序 'java' 已包含在下列软件包中: * default-...

whoisliang ⋅ 19分钟前 ⋅ 0

大数据学习路线(自己制定的,从零开始学习大数据)

大数据已经火了很久了,一直想了解它学习它结果没时间,过年后终于有时间了,了解了一些资料,结合我自己的情况,初步整理了一个学习路线,有问题的希望大神指点。 学习路线 Linux(shell,高并...

董黎明 ⋅ 25分钟前 ⋅ 0

systemd编写服务

一、开机启动 对于那些支持 Systemd 的软件,安装的时候,会自动在/usr/lib/systemd/system目录添加一个配置文件。 如果你想让该软件开机启动,就执行下面的命令(以httpd.service为例)。 ...

勇敢的飞石 ⋅ 27分钟前 ⋅ 0

mysql 基本sql

CREATE TABLE `BBB_build_info` ( `community_id` varchar(50) NOT NULL COMMENT '小区ID', `layer` int(11) NOT NULL COMMENT '地址层数', `id` int(11) NOT NULL COMMENT '地址id', `full_......

zaolonglei ⋅ 36分钟前 ⋅ 0

安装chrome的vue插件

参看文档:https://www.cnblogs.com/yulingjia/p/7904138.html

xiaoge2016 ⋅ 39分钟前 ⋅ 0

用SQL命令查看Mysql数据库大小

要想知道每个数据库的大小的话,步骤如下: 1、进入information_schema 数据库(存放了其他的数据库的信息) use information_schema; 2、查询所有数据的大小: select concat(round(sum(da...

源哥L ⋅ 今天 ⋅ 0

两个小实验简单介绍@Scope("prototype")

实验一 首先有如下代码(其中@RestController的作用相当于@Controller+@Responsebody,可忽略) @RestController//@Scope("prototype")public class TestController { @RequestMap...

kalnkaya ⋅ 今天 ⋅ 0

php-fpm的pool&php-fpm慢执行日志&open_basedir&php-fpm进程管理

12.21 php-fpm的pool pool是PHP-fpm的资源池,如果多个站点共用一个pool,则可能造成资源池中的资源耗尽,最终访问网站时出现502。 为了解决上述问题,我们可以配置多个pool,不同的站点使用...

影夜Linux ⋅ 今天 ⋅ 0

微服务 WildFly Swarm 管理

Expose Application Metrics and Information 要公开关于我们的微服务的有用信息,我们需要做的就是将监视器模块添加到我们的pom.xml中: 这将使在管理和监视功能得到实现。从监控角度来看,...

woshixin ⋅ 今天 ⋅ 0

java连接 mongo伪集群部署遇到的坑

部署mongo伪集群 #创建mongo数据存放文件地址mkdir -p /usr/local/config1/datamkdir -p /usr/local/config2/data mkdir -p /usr/local/config3/data mkdir -p /usr/local/config1/l......

努力爬坑人 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部