C# 消除累计误差的倒计时
使用 C# 中自带的各种 timer 计时,都会有累计误差,以下代码实现了一种消除累计误差的方法,使得每次计时的误差,空值在 100 ms 以内(可以通过修改代码提升精度。)
对于精度要求在秒级别的简单计时应用来说,误差可接受,并且消除累计误差。
以下是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace Xxx.Utils
{
    /// <summary>
    /// 带有校准功能的秒钟计时器(误差最大100ms)
    /// </summary>
    public class ClockTimer : IDisposable
    {
        private readonly Timer _driveTimer;
        private int _intervalSeconds = 1;
        private double _startMilliSeconds;
        private long _tickCount;
        private bool _enabled;
        public ClockTimer()
        {
            _driveTimer = new Timer(100);
            _driveTimer.Elapsed += DriveTimerOnElapsed;
        }
        public ClockTimer(int intervalSeconds) : this()
        {
            _intervalSeconds = intervalSeconds;
        }
        /// <summary>
        /// 获取或设置<see cref="ClockTimer"/>的触发时间间隔,单位:秒。
        /// </summary>
        public int IntervalSeconds
        {
            get => _intervalSeconds;
            set => _intervalSeconds = value < 1 ? 1 : value;
        }
        /// <summary>
        /// 获取或设置一个值,该值指示<see cref="ClockTimer"/>是否引发<see cref="Elapsed"/>事件。
        /// </summary>
        public bool Enabled
        {
            get => _enabled;
            set
            {
                if (value)
                {
                    Start();
                }
                else
                {
                    Stop();
                }
            }
        }
        /// <summary>
        /// 到达时间间隔时发生。
        /// </summary>
        public event EventHandler<ElapsedEventArgs> Elapsed;
        /// <summary>
        /// 开始计时
        /// </summary>
        public void Start()
        {
            _driveTimer.Start();
            _enabled = true;
            _startMilliSeconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
        }
        /// <summary>
        /// 结束计时
        /// </summary>
        public void Stop()
        {
            _driveTimer.Stop();
            _tickCount = 0;
            _enabled = false;
        }
        private void DriveTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            double currentMilliseconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
            // 第一个 100 ms,直接返回。
            if (_tickCount == 0 && Math.Abs(currentMilliseconds - _startMilliSeconds) < 100)
            {
                return;
            }
            if (Math.Abs(currentMilliseconds - (_startMilliSeconds + (_tickCount + 1) * 1000)) <= 100)
            {
                _tickCount++;
                if (_tickCount % IntervalSeconds == 0)
                {
                    Elapsed?.Invoke(this, elapsedEventArgs);
                }
            }
        }
        public void Dispose()
        {
            _driveTimer?.Dispose();
        }
    }
}
												
											C# 消除累计误差的倒计时的更多相关文章
- 玩转X-CTR100 l STM32F4 l 电机正交编码器
		
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器的电机正交编码器,X- ...
 - 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)
		
转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...
 - Android开发案例 – 在AbsListView中使用倒计时
		
在App中, 有多种多样的倒计时需求, 比如: 在单View上, 使用倒计时, 如(如图-1) 在ListView(或者GridView)的ItemView上, 使用倒计时(如图-2) 图-1 图-2 ...
 - JS案例之3——倒计时
		
利用简单的数字累加循环模拟倒计时的效果,逻辑比较简单.如果大牛们有更好的办法欢迎补充. 这种效果经常用于在规定的时间做某件事.比如在1分钟之后重新发送验证码等. 案例演示: 源代码如下: <!D ...
 - Linux环境下shell和vim中乱码原因及消除办法
		
shell和vim中乱码原因及消除办法 作者:Jack47 在Linux下开发,经常遇到乱码问题:shell或者vim中显示不了中文,或者能够显示,但不能输入中文.每次都是上网去搜,或者同事告诉我一些 ...
 - js倒计时-倒计输入的时间
		
计算指定时间到指定时间之间相差多少天.时.分.秒. 节日.活动.商城常用. 原理: 主要使用到时间戳,也就是从1970 年 1 月 1 日 到指定时间的毫秒数. 1. 求出毫秒差 :当两个时间直接进行 ...
 - 微信小程序定时器组件(输入时间字符串即可倒计时)
		
昨天写了代码,今天发现要重用,干脆就抽出来做个组件得了,顺便还改善了一下代码通用性. 昨天的代码在这里 github下载地址 用法: 引入: var timer = require('../../pl ...
 - Linq to sql 有什么办法可以实现消除列重复?
		
比如数据库里有一表,有两个字段:ID User1 小白2 小红3 小白 过滤User列为小白的重复项后,我想要得到:ID User1 小白2 小红 如果写db.linq.customer.Distin ...
 - jQuery获取短信验证码+倒计时实现
		
jQuery 短信验证码倒计时 <script type="text/javascript" charset="utf-8"> $(function ...
 
随机推荐
- ZooKeeper在线迁移
			
在至少有一个Leader存在的前提下,进行Zookeeper的在线增量.在线减量.在线迁移 在全过程中ZooKeeper不停止服务 注意事项 首先,当我们要从3台扩充到5台时,应保证集群不停止服务. ...
 - debian自动挂载ntfs硬盘
			
首先下载安装ntfs-3g apt-get install ntfs-3g 然后查看分区信息 fdisk -l Device Boot Start End Blocks Id System /dev/ ...
 - web项目中的 log4net的配置
			
最近用log4net,网上查了很多资料,照着网上的配置大多都不管用,可能我还是有什么地方配置的不对.看出来的朋友平指出.下面是我自己亲测的,可以用! 1.web项目中的web.config 配置log ...
 - 为什么 .NET 会被叫做 .NET?
			
微软开发.NET Framework是在20世纪90年代后期,最初是叫做“下一代Windows服务”(Next Generation Windows Services 简称 NGWS). 那么为什么微 ...
 - DHTML Object Model&DHTML&DOM
			
DHTML Object Model:DHTML对象模型,利用DHTML Object Model可以单独操作页面上的对象,每个HTML标记通过它的ID和NAME属性被操纵,每个对象都具有自己的属性. ...
 - Use JPath but not recursively loop a JObject to modify the values.
			
I am dealing with a Json file, I parsed it into jObject, I have another list which flattened the pro ...
 - oozie的简易安装
			
1. 解压 tar -zxvf oozie-4.0.0-cdh5.3.6.tar.gz 2.配置hadoop的集群,添加一个代理用户(给oozie运行mapreduce的权限) 在hadoop的co ...
 - ubuntu16.04中启动anaconda图形化界面
			
$ source ~/anaconda3/bin/activate root $ anaconda-navigator
 - elk系列7之通过grok分析apache日志【转】
			
preface 说道分析日志,我们知道的采集方式有2种: 通过grok在logstash的filter里面过滤匹配. logstash --> redis --> python(py脚本过 ...
 - Java Web Project Problems
			
A: 项目红叉 1. 检验 Java Builder Path 2. 检查 Projects Facets 3. 查看 Targets Runtimes B:项目红感叹号 1. 查看问题栏 Prob ...