文档章节

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

北风其凉
 北风其凉
发布于 2016/05/05 23:04
字数 1104
阅读 256
收藏 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

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

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

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

zhujunxxxxx
2015/03/14
0
0
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实现同步UDP服务器

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

zhujunxxxxx
2015/03/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

多线程

1. 多线程概念。并发和并行的概念。 多线程指的是一段时间内cpu同时执行多个线程。一个程序至少运行>=1个进程,进程就是运行中的程序,而一个进程至少运行>=1个线程,线程是操作系统能调度的...

鱼想吃肉
11分钟前
0
0
HBase 表修复在线方式和离线方式

一、在线修复 1.1 使用检查命令 $ ./bin/hbase hbck 该命令可完整修复 HBase 元数据信息;存在有错误信息会进行输出; 也可以通过如下命令查看详细信息: $ ./bin/hbase hbck -details 1.2 ...

Ryan-瑞恩
36分钟前
1
0
redis 系列二 -- 常用命令

1.基础命令 info ping quit save dbsize select flushdb flushall 2.键命令 2.1 set 直接赋值 set a a 2.2 get 取值 get a 2.3 exists 是否存在 exists a 2.4 expire 设置剩余时间 秒 expire......

imbiao
今天
1
0
php foreach

<?php// 数组的引用$a=array(1,2,3,4,5);foreach($a as $key=>&$value){$value=$value*2;}print_r($a);echo " $key -------------------$value\r\n";/** * ...

小张525
今天
1
0
12-利用思维导图梳理JavaSE-多线程

12-利用思维导图梳理JavaSE-多线程 主要内容 1.线程概念 2.线程开发 3.线程的状态 4.线程的同步和死锁 5.Java5.0并发库类 QQ/知识星球/个人WeChat/公众号二维码 本文为原创文章,如果对你有一...

飞鱼说编程
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部