zoukankan      html  css  js  c++  java
  • C#开发系统服务时用的定时器组件

    [csharp] view plaincopy
     
    1. // 相较上一版本改进  
    2. // 1. 修改Bug  
    3. //  当设置每月一次频率时,设置的Day日期如果为31,30,29,在有些年份的有些月份会抛出异常,因为有些月份是没有31天的,改正之后,  
    4. //  如果设置了31天,则只有有31天的月份会执行。  
    5. // 2. 修正一年中某天的日期较验功能。  
    6. // 3. 新增加循环模式  
    7. //  每个月最后一天执行一次。  
    8. // 4. 支持到秒的定时  
    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Text;  
    3. using System.Windows.Forms;  
    4. using UpSoft.Framework.CommonFunction.WinService;  
    5.   
    6. namespace TestProject  
    7. {  
    8.     /// <summary>  
    9.     /// 测试服务  
    10.     /// </summary>  
    11.     public class TestServices : ServiceTimerControl  
    12.     {  
    13.         /// <summary>  
    14.         /// 服务代码  
    15.         /// </summary>  
    16.         protected override void StartService()  
    17.         {  
    18.             // 需要处理的服务代码  
    19.         }  
    20.   
    21.         /// <summary>  
    22.         /// 时间配置策略名(可不重写。默认读配置文件中的default)  
    23.         /// </summary>  
    24.         public override string ConfigName { get { return "A"; } }  
    25.     }  
    26. }  
    27.   
    28.   
    29. 要调用时,只需输入以下代码  
    30. new TestServices().Start();  
    [csharp] view plaincopy
     
    1. //时间策略配置,可选择以下两种之一,配置文件,或是重写实现基类的获取时间策略配置  
    2. //1.代码重写  
    3.         /// <summary>  
    4.         /// 时间策略配置  
    5.         /// </summary>  
    6.         /// <returns></returns>  
    7.         protected override TimerConfig GetTimerConfig()  
    8.         {  
    9.             return new TimerConfig{ TimerMode=..., ...};  
    10.         }  
    11. //2.配置文件实现  
    [html] view plaincopy
     
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <configuration>  
    3.     <configSections>  
    4.         <section name="ServiceTimerConfig" type="UpSoft.Framework.CommonFunction.WinService.ServiceTimerConfigManager,CommonFunction"></section>  
    5.     </configSections>  
    6.     <ServiceTimerConfig>  
    7.         <!--默认采用策略-->  
    8.         <Default>A</Default>  
    9.         <!--A配置项(全节点)-->  
    10.         <Config>  
    11.             <!--A策略-->  
    12.             <RefName>A</RefName>  
    13.             <TimerMode>Interval</TimerMode>  
    14.             <!--延迟开始处理(单位毫秒)可为空-->  
    15.             <Delay>10000</Delay>  
    16.             <!--文件生成时间间隔(单位毫秒,1800000=30分钟)-->  
    17.             <Interval>600000</Interval>  
    18.             <!--月份-->  
    19.             <MonthSeq></MonthSeq>  
    20.             <!--指定第几天的序号-->  
    21.             <DaySeq></DaySeq>  
    22.             <!--定时配置-->  
    23.             <Times>  
    24.                 <!--一天之中需要执行任务的时间点-->  
    25.                 <TimeValue>11:20:19</TimeValue>  
    26.                 <TimeValue>10:10:43</TimeValue>  
    27.                 <TimeValue>19:10:28</TimeValue>  
    28.             </Times>  
    29.         </Config>  
    30.         <!--B配置项(轮询策略)-->  
    31.         <Config>  
    32.             <!--B策略,每隔设置的时间执行一次-->  
    33.             <RefName>B</RefName>  
    34.             <TimerMode>Interval</TimerMode>  
    35.             <!--延迟开始处理(单位毫秒)-->  
    36.             <Delay>10000</Delay>  
    37.             <!--文件生成时间间隔(单位毫秒,1800000=30分钟)-->  
    38.             <Interval>600000</Interval>  
    39.         </Config>  
    40.         <!--C配置项(天设置)-->  
    41.         <Config>  
    42.             <!--C策略,每周4在配置的时间点上执行-->  
    43.             <RefName>C</RefName>  
    44.             <TimerMode>Week</TimerMode>  
    45.             <!--延迟开始处理(单位毫秒)-->  
    46.             <Delay>10000</Delay>  
    47.             <!--每周的星期四的以下时间执行-->  
    48.             <DaySeq>4</DaySeq>  
    49.             <!--定时配置-->  
    50.             <Times>  
    51.                 <!--一天之中需要执行任务的时间点-->  
    52.                 <TimeValue>11:20:19</TimeValue>  
    53.                 <TimeValue>10:10:43</TimeValue>  
    54.                 <TimeValue>19:10:28</TimeValue>  
    55.             </Times>  
    56.         </Config>  
    57.         <!--D配置项(月、天设置)-->  
    58.         <Config>  
    59.             <!--D策略,每年12月8号在配置的时间点上执行-->  
    60.             <RefName>D</RefName>  
    61.             <TimerMode>Month</TimerMode>  
    62.             <!--延迟开始处理(单位毫秒)-->  
    63.             <Delay>10000</Delay>  
    64.             <!--月份-->  
    65.             <MonthSeq>12</MonthSeq>  
    66.             <!--天数-->  
    67.             <DaySeq>8</DaySeq>  
    68.             <!--定时配置-->  
    69.             <Times>  
    70.                 <!--一天之中需要执行任务的时间点-->  
    71.                 <TimeValue>11:20:19</TimeValue>  
    72.                 <TimeValue>10:10:43</TimeValue>  
    73.                 <TimeValue>19:10:28</TimeValue>  
    74.             </Times>  
    75.         </Config>  
    76.     </ServiceTimerConfig>  
    77. </configuration>  
    78.   
    79. // TimerMode的定义  
    80.     public enum TimerMode  
    81.     {  
    82.         ///<summary>  
    83.         /// 轮询方式  
    84.         /// </summary>  
    85.         Interval = 0,  
    86.         /// <summary>  
    87.         /// 一个月中某个天数的指定时间  
    88.         /// </summary>  
    89.         Month = 1,  
    90.         /// <summary>  
    91.         /// 一周中的周几的指定时间  
    92.         /// </summary>  
    93.         Week = 2,  
    94.         /// <summary>  
    95.         /// 一天中的指定时间  
    96.         /// </summary>  
    97.         Day = 3,  
    98.         /// <summary>  
    99.         /// 一年中第几天的指定时间  
    100.         /// </summary>  
    101.         Year = 4,  
    102.         /// <summary>  
    103.         /// 一年中的指定日期的指定时间  
    104.         /// </summary>  
    105.         Date = 5,  
    106.         /// <summary>  
    107.         /// 每个月倒数第N天  
    108.         /// </summary>  
    109.         LastDayOfMonth  
    110.         /// <summary>  
    111.         /// 未设置  
    112.         /// </summary>  
    113.         NoSet  
    114.     }  

    以下是组件的源代码

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Configuration;  
    4. using System.Text.RegularExpressions;  
    5. using System.Threading;  
    6. using System.Xml;  
    7.   
    8. namespace UpSoft.Framework.CommonFunction.WinService  
    9. {  
    10.     /// <summary>  
    11.     /// 服务定时器管理  
    12.     /// </summary>  
    13.     public abstract class ServiceTimerControl  
    14.     {  
    15.         #region 私有成员  
    16.         /// <summary>  
    17.         /// 定时器  
    18.         /// </summary>  
    19.         private Timer SysTimer { get; set; }  
    20.         /// <summary>  
    21.         /// 是否启用定时器  
    22.         /// </summary>  
    23.         private bool _EnabledTimer = true;  
    24.         /// <summary>  
    25.         /// 服务执行状态, 0-休眠, 1-运行  
    26.         /// </summary>  
    27.         private int _serviceStatus = 0;  
    28.         #endregion  
    29.  
    30.         #region 公共属性  
    31.         /// <summary>  
    32.         /// 获取服务状态  
    33.         /// </summary>  
    34.         public int ServiceStatus { get { return _serviceStatus; } }  
    35.   
    36.         /// <summary>  
    37.         /// 定时器配置  
    38.         /// </summary>  
    39.         public TimerConfig Config { get; set; }  
    40.   
    41.         /// <summary>  
    42.         /// 时间计算类  
    43.         /// </summary>  
    44.         public TimerControl TimerControl { get; set; }  
    45.   
    46.         /// <summary>  
    47.         /// 配置名称  
    48.         /// </summary>  
    49.         public virtual string ConfigName { get { return ( ServiceTimerConfigManager.ServiceConfig == null ? "" : ServiceTimerConfigManager.ServiceConfig.Default ); } }  
    50.         #endregion  
    51.   
    52.         /// <summary>  
    53.         /// 停止  
    54.         /// </summary>  
    55.         public void Stop()  
    56.         {  
    57.             _EnabledTimer = false;  
    58.   
    59.             if ( SysTimer != null ) SysTimer.Change( Timeout.Infinite, Timeout.Infinite );  
    60.         }  
    61.   
    62.         /// <summary>  
    63.         /// 开始服务  
    64.         /// </summary>  
    65.         public void Start()  
    66.         {  
    67.             try  
    68.             {  
    69.                 _EnabledTimer = true;  
    70.                 Config = this.GetTimerConfig();  
    71.                 if ( Config.Delay == null )  
    72.                     Config.Delay = new TimeSpan( 0 );  
    73.   
    74.                 SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, Config.Delay, this.Config.Interval );  
    75.   
    76.                 this.Logger( LogLevel.INFO, "服务启动成功!" );  
    77.             }  
    78.             catch ( Exception ex )  
    79.             {  
    80.                 this.ServiceException( ex );  
    81.             }  
    82.         }  
    83.   
    84.         /// <summary>  
    85.         /// 单次执行服务程序  
    86.         /// </summary>  
    87.         public void Process()  
    88.         {  
    89.             try  
    90.             {  
    91.                 //开始处理服务  
    92.                 this.StartService();  
    93.             }  
    94.             catch ( Exception ex ) { this.ServiceException( ex ); } // 处理服务执行过程中出现的异常  
    95.         }  
    96.   
    97.         /// <summary>  
    98.         /// 处理间隔服务  
    99.         /// </summary>  
    100.         /// <param name="sender"></param>  
    101.         private void TimerProcess( object sender )  
    102.         {  
    103.             if ( !_EnabledTimer ) return;  
    104.   
    105.             bool TimeIsUp = true;  
    106.             if ( this.Config.TimerMode != TimerMode.Interval )  
    107.             {  
    108.                 // 如果定时方式不是定时轮询的话,就构造TimerControl类,该类用来计算每次执行完程序后  
    109.                 // 到下次执行服务时需要休眠的时间  
    110.                 try  
    111.                 {  
    112.                     this.TimerControl = new TimerControl( this.Config );  
    113.                     TimeIsUp = this.TimerControl.TimeIsUp;  // 获取是否到了执行服务程序的时间了  
    114.                 }  
    115.                 catch ( Exception ex )  
    116.                 {  
    117.                     // 读取配置出错且TimerControl对象已不存在,则再抛出异常  
    118.                     // 如果上一次读取配置成功,那就就算这次的配置有问题,则也不会停止程序的运行,仍用上一次的数据做为参数  
    119.                     if ( this.TimerControl == null ) throw ex;  
    120.                 }  
    121.             }  
    122.   
    123.             try  
    124.             {  
    125.                 if ( TimeIsUp )// 时间到了可以执行程序了  
    126.                 {  
    127.                     // 服务运行了  
    128.                     _serviceStatus = 1;  
    129.   
    130.                     // 设置计时器,在无穷时间后再启用(实际上就是永远不启动计时器了--停止计时器计时)  
    131.                     SysTimer.Change( Timeout.Infinite, Timeout.Infinite );  
    132.   
    133.                     //开始处理服务  
    134.                     this.StartService();  
    135.                 }  
    136.             }  
    137.             catch ( Exception ex ) { this.ServiceException( ex ); } // 处理服务执行过程中出现的异常  
    138.             finally  
    139.             {  
    140.                 // 如果计时器不为空,则重新设置休眠的时间  
    141.                 if ( SysTimer != null )  
    142.                 {  
    143.                     if ( this.Config.TimerMode == TimerMode.Interval )// 定时轮询设置  
    144.                     {  
    145.                         // 重新启用计时器  
    146.                         SysTimer.Change( this.Config.Interval, this.Config.Interval );  
    147.                     }  
    148.                     else// 定时设置  
    149.                     {  
    150.                         // 用cft类计算下一次到期的时间  
    151.                         TimeSpan Interval = this.TimerControl.GetNextTimeUp();  
    152.                         // 重新启用计时器  
    153.                         SysTimer.Change( Interval, Interval );  
    154.                     }  
    155.                 }  
    156.                 _serviceStatus = 0;  
    157.             }  
    158.         }  
    159.   
    160.         /// <summary>  
    161.         /// 开始服务  
    162.         /// </summary>  
    163.         protected abstract void StartService();  
    164.   
    165.         /// <summary>  
    166.         /// 记录日志  
    167.         /// </summary>  
    168.         /// <param name="level">错误级别</param>  
    169.         /// <param name="msg"></param>  
    170.         protected virtual void Logger( LogLevel level, string msg ) { return; }  
    171.   
    172.         /// <summary>  
    173.         /// 定时器初始化  
    174.         /// </summary>  
    175.         protected virtual TimerConfig GetTimerConfig()  
    176.         {  
    177.             var config = ServiceTimerConfigManager.ServiceConfig;  
    178.             if ( config != null && config.Config.Length > 0 )  
    179.             {  
    180.                 // 如果没有配置则默认为第1个  
    181.                 if ( String.IsNullOrEmpty( ConfigName ) )  
    182.                     return config.Config[0];  
    183.                 else// 返回配置项  
    184.                     foreach ( var c in config.Config ) if ( String.Compare( c.RefName, ConfigName, true ) == 0 ) return c;  
    185.             }  
    186.   
    187.             throw new Exception( "时间策略配置不正确!" );  
    188.         }  
    189.   
    190.         /// <summary>  
    191.         /// 系统服务错误  
    192.         /// </summary>  
    193.         /// <param name="ex"></param>  
    194.         protected virtual void ServiceException( Exception ex ) { this.Logger( LogLevel.ERROR, "服务异常:" + ex.Message + "  堆栈:" + ex.StackTrace ); }  
    195.     }  
    196.  
    197.     #region 定时服务休眠计算类  
    198.     /// <summary>  
    199.     /// 文件生成时间配置  
    200.     /// </summary>  
    201.     public class TimerControl  
    202.     {  
    203.         #region 私有成员  
    204.         private TimerConfig Config { get; set; }  
    205.         #endregion  
    206.  
    207.         #region 公共成员方法  
    208.         /// <summary>  
    209.         /// 构造函数  
    210.         /// </summary>  
    211.         /// <param name="config">配置参数</param>  
    212.         /// </param>  
    213.         public TimerControl( TimerConfig config )  
    214.         {  
    215.             Config = config;  
    216.             if ( Config == null ) throw new Exception( "定时器时间配置异常!" );  
    217.   
    218.             switch ( Config.TimerMode )  
    219.             {  
    220.                 case TimerMode.Date:  
    221.                     if ( Config.MonthSeq < 1 || Config.MonthSeq > 12 )  
    222.                         throw new Exception( "定时器时间配置异常(月份取值只能是1~12)!" );  
    223.                     var dt = new DateTime( 2012, Config.MonthSeq, 1 );  // 之所以选2012,是因为他是闰年,因此2月有29天。  
    224.                     var lastDay = GetLastDayByMonth( dt );  
    225.                     if ( Config.DaySeq < 1 || Config.DaySeq > lastDay )  
    226.                         throw new Exception( "定时器时间配置异常(" + Config.MonthSeq + "月份的天数取值只能是1~" + lastDay + ")!" );  
    227.                     break;  
    228.                 case TimerMode.Day: break;  
    229.                 case TimerMode.Month:  
    230.                     if ( Config.DaySeq < 1 || Config.DaySeq > 31 )  
    231.                         throw new Exception( "定时器时间配置异常(天数取值只能是1~31)!" );  
    232.                     break;  
    233.                 case TimerMode.Week:  
    234.                     if ( Config.DaySeq < 0 || Config.DaySeq > 6 )  
    235.                         throw new Exception( "定时器时间配置异常(星期取值只能是0~6)!" );  
    236.                     break;  
    237.                 case TimerMode.LastDayOfMonth:  
    238.                     if ( Config.DaySeq != 0 )  
    239.                     {// 如果等于0的话,表示是每个月的最后一天。  
    240.                         if ( Config.DaySeq < 1 || Config.DaySeq > 28 )  
    241.                             throw new Exception( "定时器时间配置异常(倒数的天数只能是1~28,即倒数的第1天,第2天。。。有些月份并没有29.30.31天,因此最大只允许倒数第28天)!" );  
    242.                         Config.DaySeq -= 1;  
    243.                     }  
    244.                     break;  
    245.                 case TimerMode.Year:  
    246.                     if ( Config.DaySeq < 1 || Config.DaySeq > 366 )  
    247.                         throw new Exception( "定时器时间配置异常(天数取值只能是1~366)!" );  
    248.                     break;  
    249.             }  
    250.         }  
    251.   
    252.         /// <summary>  
    253.         /// 判断时间是否到了  
    254.         /// </summary>  
    255.         /// <returns>true时间已经到了,false时间还未到</returns>  
    256.         public bool TimeIsUp  
    257.         {  
    258.             get  
    259.             {  
    260.                 DateTime dt = DateTime.Now;  
    261.                 if ( CheckTimeIsUp( dt.TimeOfDay ) )  
    262.                 {  
    263.                     switch ( Config.TimerMode )  
    264.                     {  
    265.                         case TimerMode.Day: return true;  
    266.                         case TimerMode.Date: return dt.Month == Config.MonthSeq && dt.Day == Config.DaySeq;  
    267.                         case TimerMode.Week: return ( ( int )dt.DayOfWeek ) == Config.DaySeq;  
    268.                         case TimerMode.Month: return dt.Day == Config.DaySeq;  
    269.                         case TimerMode.Year: return dt.DayOfYear == Config.DaySeq;  
    270.                         case TimerMode.LastDayOfMonth: return dt.Day == ( GetLastDayByMonth( dt ) - Config.DaySeq );  
    271.                         default: return false;  
    272.                     }  
    273.                 }  
    274.                 else  
    275.                     return false;  
    276.             }  
    277.         }  
    278.   
    279.         /// <summary>  
    280.         /// 时间是否到了  
    281.         /// </summary>  
    282.         /// <returns></returns>  
    283.         private bool CheckTimeIsUp( TimeSpan time )  
    284.         {  
    285.             var tmp = new TimeSpan( time.Hours, time.Minutes, time.Seconds );  
    286.             if ( Config.Times == null )  
    287.                 return ( tmp.Ticks == 0 );  
    288.             else  
    289.             {  
    290.                 foreach ( var t in Config.Times )  
    291.                 {  
    292.                     if ( t == tmp ) return true;  
    293.                 }  
    294.                 return false;  
    295.             }  
    296.         }  
    297.   
    298.         /// <summary>  
    299.         /// 从现在起到下次时间到还有多少时间  
    300.         /// </summary>  
    301.         /// <returns>时间间隔</returns>  
    302.         public TimeSpan GetNextTimeUp()  
    303.         {  
    304.             ///目标时间  
    305.             DateTime _NextDateTime = this.GetNextDateTime();    // 保存下一次要执行的时间  
    306.             return _NextDateTime - DateTime.Now;  
    307.         }  
    308.   
    309.         /// <summary>  
    310.         /// 获取下一次指定配置的时间是多少  
    311.         /// </summary>  
    312.         /// <returns></returns>  
    313.         public DateTime GetNextDateTime()  
    314.         {  
    315.             var time = GetNextTimeConfig();  
    316.             DateTime dt = DateTime.Now;  
    317.             DateTime now, target;  
    318.             switch ( Config.TimerMode )  
    319.             {  
    320.                 case TimerMode.Day:  
    321.                     #region 每天指定某时执行一次  
    322.                     now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );  
    323.                     target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );  
    324.                     if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 ); //如果当前时间小于指定时刻,则不需要加天  
    325.   
    326.                     dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );  
    327.                     #endregion  
    328.                     break;  
    329.                 case TimerMode.Month:  
    330.                     #region 每月指定某天某时执行一次  
    331.                     now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );  
    332.                     target = new DateTime( 1, 1, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );   // 1月有31天,所以可以接受任何合法的Day值(因为在赋值时已判断1~31)  
    333.                     if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );  
    334.   
    335.   
    336.                     // 当前月份的指定天数执行过了,因此月份加上一个月,当月份加了一个月之后,很可能当前实现的Day值可能会变小(例:3月31号,加上一个月,则日期会变成,4月30号,而不会变成5月1号),  
    337.                     // 因此需要判断指定的this.Day是不是比Day大(月份的Day变小的唯一原因是因为月份加了一个月之后,那个月并没有this.Day的天数),如果没有该this.Day的天数。则需要为该月份再加一个月。  
    338.                     // 加一个月份,则那下个月一定可以大于等于this.Day, 看看每个月的天数就可以断定了,  
    339.                     // 因为没有连着两个月的日期小于等于30的,只有连续两个月是31天。其它就是间隔的出现(this.Day最大只可能为31)  
    340.                     // 如此之后,接下来的dt=new DateTime时不为因为dt.Month的月份,因没有this.Day天数而抛异常  
    341.                     if ( Config.DaySeq > GetLastDayByMonth( dt ) ) dt = dt.AddMonths( 1 );   // 如此是为了确保dt.Month的月份一定有this.Day天(因此如果设置为每个月的31号执行的程序,就只会在1,3,5,7,8,10,12几个月份会执行)  
    342.   
    343.                     dt = new DateTime( dt.Year, dt.Month, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );  
    344.                     #endregion  
    345.                     break;  
    346.                 case TimerMode.LastDayOfMonth:  
    347.                     #region 每个月倒数第N天的某时某刻执行一次  
    348.                     var lastDaybymonth = GetLastDayByMonth( dt ) - Config.DaySeq;  
    349.                     now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );  
    350.                     target = new DateTime( 1, 1, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );  // 1月有31天,所以可以接受任何合法的Day值(因为在赋值时已判断1~31)  
    351.                     if ( now.Ticks >= target.Ticks )  
    352.                     {  
    353.                         dt = dt.AddMonths( 1 );  
    354.                         dt = new DateTime( dt.Year, dt.Month, GetLastDayByMonth( dt ) - Config.DaySeq, time.Hours, time.Minutes, time.Seconds );// 根据新月份求新月份的最后一天。  
    355.                     }  
    356.                     else  
    357.                         dt = new DateTime( dt.Year, dt.Month, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );  
    358.                     #endregion  
    359.                     break;  
    360.                 case TimerMode.Week:  
    361.                     #region 每星期指定星期某时执行一次  
    362.                     int dow = ( int )dt.DayOfWeek;  
    363.                     now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, dt.Second );  
    364.                     target = new DateTime( 1, 1, Config.DaySeq + 1, time.Hours, time.Minutes, time.Seconds );  
    365.   
    366.                     if ( now.Ticks >= target.Ticks )  
    367.                         dt = dt.AddDays( Config.DaySeq - dow + 7 );  
    368.                     else  
    369.                         dt = dt.AddDays( Config.DaySeq - dow );  
    370.   
    371.                     dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );  
    372.                     #endregion  
    373.                     break;  
    374.                 case TimerMode.Date:  
    375.                     #region 每年指定某月某日某时执行一次  
    376.                     now = new DateTime( 4, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second );  
    377.   
    378.                     // 0004年闰年,可以支持2月29.因此选了0004, 这样就不会在构造Target时异常,  
    379.                     // 因为比较的关键不在年。所以,只要Now和Target的年份一样就可以,设置成什么年份无所谓  
    380.                     target = new DateTime( 4, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );  
    381.   
    382.                     if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );  
    383.                     if ( Config.MonthSeq == 2 && Config.DaySeq == 29 )  
    384.                     {  
    385.                         // 因为闰年的最大间隔是8年,平时是4年一闰,可是0096年闰完之后,下一个闰年就是0104年,因此。。。  
    386.                         for ( int i = 0; i < 8; i++ )  
    387.                             if ( DateTime.IsLeapYear( dt.Year + i ) )  
    388.                             {  
    389.                                 dt = dt.AddYears( i );  
    390.                                 break;  
    391.                             }  
    392.                     }  
    393.   
    394.                     dt = new DateTime( dt.Year, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );  
    395.                     #endregion  
    396.                     break;  
    397.                 case TimerMode.Year:  
    398.                     #region 每年指定第N天某时执行一次  
    399.                     now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );  
    400.                     target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );  
    401.                     if ( dt.DayOfYear > Config.DaySeq || dt.DayOfYear == Config.DaySeq && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );  
    402.                     dt = dt.AddDays( Config.DaySeq - dt.DayOfYear );  
    403.   
    404.                     dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );  
    405.                     #endregion  
    406.                     break;  
    407.                 default:  
    408.                     throw new Exception( "定时器时间配置异常!" );  
    409.             }  
    410.   
    411.             return dt;  
    412.         }  
    413.   
    414.         /// <summary>  
    415.         /// 获取指定日期所在月份的最后一天  
    416.         /// </summary>  
    417.         /// <param name="dt"></param>  
    418.         /// <returns></returns>  
    419.         private int GetLastDayByMonth( DateTime dt )  
    420.         {  
    421.             switch ( dt.Month )  
    422.             {  
    423.                 case 4:  
    424.                 case 6:  
    425.                 case 9:  
    426.                 case 11:  
    427.                     return 30;  
    428.                 case 2:  
    429.                     return DateTime.IsLeapYear( dt.Year ) ? 29 : 28;  
    430.                 default:  
    431.                     return 31;  
    432.             }  
    433.         }  
    434.   
    435.         /// <summary>  
    436.         /// 获取下一个时间点  
    437.         /// </summary>  
    438.         /// <returns></returns>  
    439.         private TimeSpan GetNextTimeConfig()  
    440.         {  
    441.             if ( Config.Times == null || Config.Times.Length == 0 )  
    442.                 return new TimeSpan( 0 );  
    443.             else  
    444.             {  
    445.                 var minData = TimeSpan.MaxValue;        // 最小时间  
    446.                 var minExecData = TimeSpan.MaxValue;    // 大于当前时间的最小时间  
    447.                 foreach ( var t in Config.Times )  
    448.                 {  
    449.                     if ( DateTime.Now.TimeOfDay < t && minExecData >= t ) // 找出比当前时间大的最小时间  
    450.                         minExecData = t;  
    451.                     if ( minData > t )   // 找出最小的一个时间,当前时间不参与运算  
    452.                         minData = t;  
    453.                 }  
    454.   
    455.                 if ( minExecData == TimeSpan.MaxValue ) // 如果找不到比当前时间大的最小时间,则选择最小时间返回  
    456.                     return minData;  
    457.                 else  
    458.                     return minExecData;  
    459.             }  
    460.         }  
    461.         #endregion  
    462.     }  
    463.     #endregion  
    464.  
    465.     #region 系统配置实体类&配置读取类  
    466.     /// <summary>  
    467.     /// 时间配置类  
    468.     /// </summary>  
    469.     public class ServiceTimerConfig  
    470.     {  
    471.         /// <summary>  
    472.         /// 默认配置  
    473.         /// </summary>  
    474.         public string Default { get; set; }  
    475.         /// <summary>  
    476.         /// 配置项  
    477.         /// </summary>  
    478.         public TimerConfig[] Config { get; set; }  
    479.     }  
    480.     /// <summary>  
    481.     /// 时间配置  
    482.     /// </summary>  
    483.     public class TimerConfig  
    484.     {  
    485.         /// <summary>  
    486.         /// 配置引用名  
    487.         /// </summary>  
    488.         public string RefName { get; set; }  
    489.   
    490.         /// <summary>  
    491.         /// 时间模式  
    492.         /// timeMode取值如下:TimerMode.Month、TimerMode.Week、TimerMode.Week、TimerMode.Day、TimerMode.Date、TimerMode.Year  
    493.         /// </summary>  
    494.         public TimerMode TimerMode { get; set; }  
    495.   
    496.         /// <summary>  
    497.         /// 指定某个时间算法的第几天,第1天就为1  
    498.         /// TimerMode=TimerMode.Month           时, 该DaySeq表示每个月中的第几天  
    499.         /// TimerMode=TimerMode.Week            时, 该DaySeq表示每个星期中的星期几(0-星期天,其它用1-6表示)  
    500.         /// TimerMode=TimerMode.Day             时, 该值不需要设置  
    501.         /// TimerMode=TimerMode.Date            时, 该DaySeq表示每个日期中的天数,如:8月12号,则DaySeq为12,MonthSeq为8  
    502.         /// TimerMode=TimerMode.LastDayOfMonth  时, 该DaySeq表示每个月倒数第几天  
    503.         /// TimerMode=TimerMode.Year            时, 该DaySeq表示每年中的第几天  
    504.         /// </summary>  
    505.         public int DaySeq { get; set; }  
    506.   
    507.         /// <summary>  
    508.         /// 当指定一年中某个月的某个日期时有用到如:指定一年中8月12号,则这里的MonthSeq就应该为8  
    509.         /// </summary>  
    510.         public int MonthSeq { get; set; }  
    511.   
    512.         /// <summary>  
    513.         /// 循环处理时间间隔(单位毫秒)  
    514.         /// </summary>  
    515.         public TimeSpan Interval { get; set; }  
    516.   
    517.         /// <summary>  
    518.         /// 启动延迟时间(单位毫秒)  
    519.         /// </summary>  
    520.         public TimeSpan Delay { get; set; }  
    521.   
    522.         /// <summary>  
    523.         /// 时间设置  
    524.         /// </summary>  
    525.         public TimeSpan[] Times { get; set; }  
    526.     }  
    527.     /// <summary>  
    528.     /// 服务处理方法  
    529.     /// </summary>  
    530.     public enum TimerMode  
    531.     {  
    532.         /// <summary>  
    533.         /// 轮询方式  
    534.         /// </summary>  
    535.         Interval = 0,  
    536.         /// <summary>  
    537.         /// 一个月中某个天数的指定时间  
    538.         /// </summary>  
    539.         Month = 1,  
    540.         /// <summary>  
    541.         /// 一周中的周几的指定时间  
    542.         /// </summary>  
    543.         Week = 2,  
    544.         /// <summary>  
    545.         /// 一天中的指定时间  
    546.         /// </summary>  
    547.         Day = 3,  
    548.         /// <summary>  
    549.         /// 一年中第几天的指定时间  
    550.         /// </summary>  
    551.         Year = 4,  
    552.         /// <summary>  
    553.         /// 一年中的指定日期的指定时间  
    554.         /// </summary>  
    555.         Date = 5,  
    556.         /// <summary>  
    557.         /// 每个月倒数第N天  
    558.         /// </summary>  
    559.         LastDayOfMonth,  
    560.         /// <summary>  
    561.         /// 未设置  
    562.         /// </summary>  
    563.         NoSet  
    564.     }  
    565.     /// <summary>  
    566.     /// 读取配置数据  
    567.     /// </summary>  
    568.     public class ServiceTimerConfigManager : IConfigurationSectionHandler  
    569.     {  
    570.         private static Regex regEx = new Regex( @"^(?<h>[01]?d|2[0-3])(?:[::](?<m>[0-5]d?))?(?:[::](?<s>[0-5]d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );  
    571.   
    572.         /// <summary>  
    573.         /// 请求服务配置  
    574.         /// </summary>  
    575.         public static ServiceTimerConfig ServiceConfig { get; set; }  
    576.         /// <summary>  
    577.         /// 静态构造函数  
    578.         /// </summary>  
    579.         static ServiceTimerConfigManager()  
    580.         {  
    581.             ConfigurationManager.GetSection( "ServiceTimerConfig" );  
    582.         }  
    583.         /// <summary>  
    584.         /// 读取自定义配置节  
    585.         /// </summary>  
    586.         /// <param name="parent">父结点</param>  
    587.         /// <param name="configContext">配置上下文</param>  
    588.         /// <param name="section">配置区</param>  
    589.         /// <returns></returns>  
    590.         object IConfigurationSectionHandler.Create( object parent, object configContext, XmlNode section )  
    591.         {  
    592.             ServiceConfig = new ServiceTimerConfig();  
    593.             var config = new List<TimerConfig>();  
    594.   
    595.             foreach ( XmlNode node in section.ChildNodes )  
    596.             {  
    597.                 if ( node.NodeType == XmlNodeType.Element )  
    598.                 {  
    599.                     switch ( node.Name.ToLower() )  
    600.                     {  
    601.                         case "default":  
    602.                             ServiceConfig.Default = node.InnerText;  
    603.                             break; ;  
    604.                         case "config":  
    605.                             var tmp = new TimerConfig();  
    606.                             SetTimerConfigValue( tmp, node );  
    607.                             config.Add( tmp );  
    608.                             break; ;  
    609.                     }  
    610.                 }  
    611.             }  
    612.             ServiceConfig.Config = config.ToArray();  
    613.   
    614.             return ServiceConfig;  
    615.         }  
    616.         /// <summary>  
    617.         /// 设置定时器值  
    618.         /// </summary>  
    619.         /// <param name="Config"></param>  
    620.         /// <param name="node"></param>  
    621.         private void SetTimerConfigValue( TimerConfig Config, XmlNode node )  
    622.         {  
    623.             int tmp, h, m, s;  
    624.             long longTmp;  
    625.             var times = new List<TimeSpan>();  
    626.   
    627.             foreach ( XmlNode xn in node.ChildNodes )  
    628.             {  
    629.                 if ( xn.NodeType == XmlNodeType.Element )  
    630.                 {  
    631.                     switch ( xn.Name.ToLower() )  
    632.                     {  
    633.                         case "refname":  
    634.                             Config.RefName = xn.InnerText;  
    635.                             break;  
    636.                         case "timermode":  
    637.                             if ( xn.InnerText != null )  
    638.                                 Config.TimerMode = ( TimerMode )Enum.Parse( typeof( TimerMode ), xn.InnerText );  
    639.                             break;  
    640.                         case "delay":  
    641.                             Int64.TryParse( xn.InnerText, out longTmp );  
    642.                             Config.Delay = new TimeSpan( longTmp * 10 * 1000L );    // Delay配置值为毫秒  
    643.                             break;  
    644.                         case "interval":  
    645.                             Int64.TryParse( xn.InnerText, out longTmp );        // Interval配置值为毫秒  
    646.                             Config.Interval = new TimeSpan( longTmp * 10 * 1000L );  
    647.                             break;  
    648.                         case "monthseq":    // 月份  
    649.                             Int32.TryParse( xn.InnerText, out tmp );  
    650.                             Config.MonthSeq = tmp;  
    651.                             break;  
    652.                         case "dayseq":      // 指定第几天的序号  
    653.                             Int32.TryParse( xn.InnerText, out tmp );  
    654.                             Config.DaySeq = tmp;  
    655.                             break;  
    656.                         case "times":  
    657.                             //还是用这个函数处理下一级的配置  
    658.                             SetTimerConfigValue( Config, xn );  // 设置时间策略  
    659.                             break;  
    660.                         case "timevalue":  
    661.                             var mc = regEx.Match( xn.InnerText );  
    662.                             if ( !mc.Success ) throw new Exception( "时间配置不正确!" );  
    663.                             Int32.TryParse( mc.Groups["h"].Value, out h );  
    664.                             Int32.TryParse( mc.Groups["m"].Value, out m );  
    665.                             Int32.TryParse( mc.Groups["s"].Value, out s );  
    666.                             times.Add( new TimeSpan( h, m, s ) );  
    667.                             break;  
    668.                     }  
    669.                 }  
    670.             }  
    671.             if ( times.Count != 0 )  
    672.                 Config.Times = times.ToArray();  
    673.         }  
    674.     }  
    675.     #endregion  
    676. }  
  • 相关阅读:
    Data Mining | 二分类模型评估-ROC/AUC/K-S/GINI
    Data Mining | 二分类模型评估-混淆矩阵
    Data Mining | 数据挖掘技术基础与进阶
    Data Mining | 数据挖掘概要和方法论
    python | 模块与第三方库的安装
    SAS | 数据EDA及代码
    SAS | 数据读入思路及代码
    python | 自定义函数
    SAS | 使用SAS数据
    SAS | 逻辑库和SAS数据集
  • 原文地址:https://www.cnblogs.com/gc2013/p/3940774.html
Copyright © 2011-2022 走看看