程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#開發系統服務時用的定時器組件,

C#開發系統服務時用的定時器組件,

編輯:C#入門知識

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 + " \r\n堆棧:" + 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. }  

C語言中 ^怎使用

a1 = 0x01; //0000 0001
a2 = 0x00; //0000 0000
a3 = 0x03; //0000 0011
a4 = 0x02; //0000 0010

b1 = a1 ^ a2; //0000 0001
b2 = a1 ^ a3; //0000 0010
b3 = a1 ^ a4; //0000 0011

^異或運算符,位值相同為0,不同為1,見上示例.

//
簡單實際問題舉例:
======\=======\=======
======a=======b=======
上面是2條電路,2個開關分別為a和b,打開狀態:\[1],關閉狀態:/[0].
若同時打開或者關閉,兩條電路均不通.
若a打開[1],b關閉[0],電路1通電
======\=======/=======
若a關閉[0],b打開[1],電路2通電
======/=======\=======
綜上,電路在a,b狀態相同時不通[0],在a,b不同時通電[1].
 

C語言中 ^怎使用

a1 = 0x01; //0000 0001
a2 = 0x00; //0000 0000
a3 = 0x03; //0000 0011
a4 = 0x02; //0000 0010

b1 = a1 ^ a2; //0000 0001
b2 = a1 ^ a3; //0000 0010
b3 = a1 ^ a4; //0000 0011

^異或運算符,位值相同為0,不同為1,見上示例.

//
簡單實際問題舉例:
======\=======\=======
======a=======b=======
上面是2條電路,2個開關分別為a和b,打開狀態:\[1],關閉狀態:/[0].
若同時打開或者關閉,兩條電路均不通.
若a打開[1],b關閉[0],電路1通電
======\=======/=======
若a關閉[0],b打開[1],電路2通電
======/=======\=======
綜上,電路在a,b狀態相同時不通[0],在a,b不同時通電[1].
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved