1. 程式人生 > >C#開發系統服務時用的定時器元件(修正版)

C#開發系統服務時用的定時器元件(修正版)

// 相較上一版本改進
// 1. 修改Bug
//	當設定每月一次頻率時,設定的Day日期如果為31,30,29,在有些年份的有些月份會丟擲異常,因為有些月份是沒有31天的,改正之後,
//	如果設定了31天,則只有有31天的月份會執行。
// 2. 修正一年中某天的日期較驗功能。
// 3. 新增加迴圈模式
//	每個月最後一天執行一次。
// 4. 支援到秒的定時
using System;
using System.Text;
using System.Windows.Forms;
using UpSoft.Framework.CommonFunction.WinService;

namespace TestProject
{
	/// <summary>
	/// 測試服務
	/// </summary>
	public class TestServices : ServiceTimerControl
	{
		/// <summary>
		/// 服務程式碼
		/// </summary>
		protected override void StartService()
		{
			// 需要處理的服務程式碼
		}

		/// <summary>
		/// 時間配置策略名(可不重寫。預設讀配置檔案中的default)
		/// </summary>
		public override string ConfigName { get { return "A"; } }
	}
}


要呼叫時,只需輸入以下程式碼
new TestServices().Start();
//時間策略配置,可選擇以下兩種之一,配置檔案,或是重寫實現基類的獲取時間策略配置
//1.程式碼重寫
		/// <summary>
		/// 時間策略配置
		/// </summary>
		/// <returns></returns>
		protected override TimerConfig GetTimerConfig()
		{
			return new TimerConfig{ TimerMode=..., ...};
		}
//2.配置檔案實現
<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<configSections>
		<section name="ServiceTimerConfig" type="UpSoft.Framework.CommonFunction.WinService.ServiceTimerConfigManager,CommonFunction"></section>
	</configSections>
	<ServiceTimerConfig>
		<!--預設採用策略-->
		<Default>A</Default>
		<!--A配置項(全節點)-->
		<Config>
			<!--A策略-->
			<RefName>A</RefName>
			<TimerMode>Interval</TimerMode>
			<!--延遲開始處理(單位毫秒)可為空-->
			<Delay>10000</Delay>
			<!--檔案生成時間間隔(單位毫秒,1800000=30分鐘)-->
			<Interval>600000</Interval>
			<!--月份-->
			<MonthSeq></MonthSeq>
			<!--指定第幾天的序號-->
			<DaySeq></DaySeq>
			<!--定時配置-->
			<Times>
				<!--一天之中需要執行任務的時間點-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
		<!--B配置項(輪詢策略)-->
		<Config>
			<!--B策略,每隔設定的時間執行一次-->
			<RefName>B</RefName>
			<TimerMode>Interval</TimerMode>
			<!--延遲開始處理(單位毫秒)-->
			<Delay>10000</Delay>
			<!--檔案生成時間間隔(單位毫秒,1800000=30分鐘)-->
			<Interval>600000</Interval>
		</Config>
		<!--C配置項(天設定)-->
		<Config>
			<!--C策略,每週4在配置的時間點上執行-->
			<RefName>C</RefName>
			<TimerMode>Week</TimerMode>
			<!--延遲開始處理(單位毫秒)-->
			<Delay>10000</Delay>
			<!--每週的星期四的以下時間執行-->
			<DaySeq>4</DaySeq>
			<!--定時配置-->
			<Times>
				<!--一天之中需要執行任務的時間點-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
		<!--D配置項(月、天設定)-->
		<Config>
			<!--D策略,每年12月8號在配置的時間點上執行-->
			<RefName>D</RefName>
			<TimerMode>Month</TimerMode>
			<!--延遲開始處理(單位毫秒)-->
			<Delay>10000</Delay>
			<!--月份-->
			<MonthSeq>12</MonthSeq>
			<!--天數-->
			<DaySeq>8</DaySeq>
			<!--定時配置-->
			<Times>
				<!--一天之中需要執行任務的時間點-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
	</ServiceTimerConfig>
</configuration>

// TimerMode的定義
	public enum TimerMode
	{
		///
		/// 輪詢方式
		/// 
		Interval = 0,
		/// 
		/// 一個月中某個天數的指定時間
		/// 
		Month = 1,
		/// 
		/// 一週中的周幾的指定時間
		/// 
		Week = 2,
		/// 
		/// 一天中的指定時間
		/// 
		Day = 3,
		/// 
		/// 一年中第幾天的指定時間
		/// 
		Year = 4,
		/// 
		/// 一年中的指定日期的指定時間
		/// 
		Date = 5,
		/// 
		/// 每個月倒數第N天
		/// 
		LastDayOfMonth
		/// 
		/// 未設定
		/// 
		NoSet
	}

以下是元件的原始碼

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

namespace UpSoft.Framework.CommonFunction.WinService
{
	/// <summary>
	/// 服務定時器管理
	/// </summary>
	public abstract class ServiceTimerControl
	{
		#region 私有成員
		/// <summary>
		/// 定時器
		/// </summary>
		private Timer SysTimer { get; set; }
		/// <summary>
		/// 是否啟用定時器
		/// </summary>
		private bool _EnabledTimer = true;
		/// <summary>
		/// 服務執行狀態, 0-休眠, 1-執行
		/// </summary>
		private int _serviceStatus = 0;
		#endregion

		#region 公共屬性
		/// <summary>
		/// 獲取服務狀態
		/// </summary>
		public int ServiceStatus { get { return _serviceStatus; } }

		/// <summary>
		/// 定時器配置
		/// </summary>
		public TimerConfig Config { get; set; }

		/// <summary>
		/// 時間計算類
		/// </summary>
		public TimerControl TimerControl { get; set; }

		/// <summary>
		/// 配置名稱
		/// </summary>
		public virtual string ConfigName { get { return ( ServiceTimerConfigManager.ServiceConfig == null ? "" : ServiceTimerConfigManager.ServiceConfig.Default ); } }
		#endregion

		/// <summary>
		/// 停止
		/// </summary>
		public void Stop()
		{
			_EnabledTimer = false;

			if ( SysTimer != null ) SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
		}

		/// <summary>
		/// 開始服務
		/// </summary>
		public void Start()
		{
			try
			{
				_EnabledTimer = true;
				Config = this.GetTimerConfig();
				if ( Config.Delay == null )
					Config.Delay = new TimeSpan( 0 );

				SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, Config.Delay, this.Config.Interval );

				this.Logger( LogLevel.INFO, "服務啟動成功!" );
			}
			catch ( Exception ex )
			{
				this.ServiceException( ex );
			}
		}

		/// <summary>
		/// 單次執行服務程式
		/// </summary>
		public void Process()
		{
			try
			{
				//開始處理服務
				this.StartService();
			}
			catch ( Exception ex ) { this.ServiceException( ex ); }	// 處理服務執行過程中出現的異常
		}

		/// <summary>
		/// 處理間隔服務
		/// </summary>
		/// <param name="sender"></param>
		private void TimerProcess( object sender )
		{
			if ( !_EnabledTimer ) return;

			bool TimeIsUp = true;
			if ( this.Config.TimerMode != TimerMode.Interval )
			{
				// 如果定時方式不是定時輪詢的話,就構造TimerControl類,該類用來計算每次執行完程式後
				// 到下次執行服務時需要休眠的時間
				try
				{
					this.TimerControl = new TimerControl( this.Config );
					TimeIsUp = this.TimerControl.TimeIsUp;	// 獲取是否到了執行服務程式的時間了
				}
				catch ( Exception ex )
				{
					// 讀取配置出錯且TimerControl物件已不存在,則再丟擲異常
					// 如果上一次讀取配置成功,那就就算這次的配置有問題,則也不會停止程式的執行,仍用上一次的資料做為引數
					if ( this.TimerControl == null ) throw ex;
				}
			}

			try
			{
				if ( TimeIsUp )// 時間到了可以執行程式了
				{
					// 服務運行了
					_serviceStatus = 1;

					// 設定計時器,在無窮時間後再啟用(實際上就是永遠不啟動計時器了--停止計時器計時)
					SysTimer.Change( Timeout.Infinite, Timeout.Infinite );

					//開始處理服務
					this.StartService();
				}
			}
			catch ( Exception ex ) { this.ServiceException( ex ); }	// 處理服務執行過程中出現的異常
			finally
			{
				// 如果計時器不為空,則重新設定休眠的時間
				if ( SysTimer != null )
				{
					if ( this.Config.TimerMode == TimerMode.Interval )// 定時輪詢設定
					{
						// 重新啟用計時器
						SysTimer.Change( this.Config.Interval, this.Config.Interval );
					}
					else// 定時設定
					{
						// 用cft類計算下一次到期的時間
						TimeSpan Interval = this.TimerControl.GetNextTimeUp();
						// 重新啟用計時器
						SysTimer.Change( Interval, Interval );
					}
				}
				_serviceStatus = 0;
			}
		}

		/// <summary>
		/// 開始服務
		/// </summary>
		protected abstract void StartService();

		/// <summary>
		/// 記錄日誌
		/// </summary>
		/// <param name="level">錯誤級別</param>
		/// <param name="msg"></param>
		protected virtual void Logger( LogLevel level, string msg ) { return; }

		/// <summary>
		/// 定時器初始化
		/// </summary>
		protected virtual TimerConfig GetTimerConfig()
		{
			var config = ServiceTimerConfigManager.ServiceConfig;
			if ( config != null && config.Config.Length > 0 )
			{
				// 如果沒有配置則預設為第1個
				if ( String.IsNullOrEmpty( ConfigName ) )
					return config.Config[0];
				else// 返回配置項
					foreach ( var c in config.Config ) if ( String.Compare( c.RefName, ConfigName, true ) == 0 ) return c;
			}

			throw new Exception( "時間策略配置不正確!" );
		}

		/// <summary>
		/// 系統服務錯誤
		/// </summary>
		/// <param name="ex"></param>
		protected virtual void ServiceException( Exception ex ) { this.Logger( LogLevel.ERROR, "服務異常:" + ex.Message + " \r\n堆疊:" + ex.StackTrace ); }
	}

	#region 定時服務休眠計算類
	/// <summary>
	/// 檔案生成時間配置
	/// </summary>
	public class TimerControl
	{
		#region 私有成員
		private TimerConfig Config { get; set; }
		#endregion

		#region 公共成員方法
		/// <summary>
		/// 建構函式
		/// </summary>
		/// <param name="config">配置引數</param>
		/// </param>
		public TimerControl( TimerConfig config )
		{
			Config = config;
			if ( Config == null ) throw new Exception( "定時器時間配置異常!" );

			switch ( Config.TimerMode )
			{
				case TimerMode.Date:
					if ( Config.MonthSeq < 1 || Config.MonthSeq > 12 )
						throw new Exception( "定時器時間配置異常(月份取值只能是1~12)!" );
					var dt = new DateTime( 2012, Config.MonthSeq, 1 );	// 之所以選2012,是因為他是閏年,因此2月有29天。
					var lastDay = GetLastDayByMonth( dt );
					if ( Config.DaySeq < 1 || Config.DaySeq > lastDay )
						throw new Exception( "定時器時間配置異常(" + Config.MonthSeq + "月份的天數取值只能是1~" + lastDay + ")!" );
					break;
				case TimerMode.Day: break;
				case TimerMode.Month:
					if ( Config.DaySeq < 1 || Config.DaySeq > 31 )
						throw new Exception( "定時器時間配置異常(天數取值只能是1~31)!" );
					break;
				case TimerMode.Week:
					if ( Config.DaySeq < 0 || Config.DaySeq > 6 )
						throw new Exception( "定時器時間配置異常(星期取值只能是0~6)!" );
					break;
				case TimerMode.LastDayOfMonth:
					if ( Config.DaySeq != 0 )
					{// 如果等於0的話,表示是每個月的最後一天。
						if ( Config.DaySeq < 1 || Config.DaySeq > 28 )
							throw new Exception( "定時器時間配置異常(倒數的天數只能是1~28,即倒數的第1天,第2天。。。有些月份並沒有29.30.31天,因此最大隻允許倒數第28天)!" );
						Config.DaySeq -= 1;
					}
					break;
				case TimerMode.Year:
					if ( Config.DaySeq < 1 || Config.DaySeq > 366 )
						throw new Exception( "定時器時間配置異常(天數取值只能是1~366)!" );
					break;
			}
		}

		/// <summary>
		/// 判斷時間是否到了
		/// </summary>
		/// <returns>true時間已經到了,false時間還未到</returns>
		public bool TimeIsUp
		{
			get
			{
				DateTime dt = DateTime.Now;
				if ( CheckTimeIsUp( dt.TimeOfDay ) )
				{
					switch ( Config.TimerMode )
					{
						case TimerMode.Day: return true;
						case TimerMode.Date: return dt.Month == Config.MonthSeq && dt.Day == Config.DaySeq;
						case TimerMode.Week: return ( ( int )dt.DayOfWeek ) == Config.DaySeq;
						case TimerMode.Month: return dt.Day == Config.DaySeq;
						case TimerMode.Year: return dt.DayOfYear == Config.DaySeq;
						case TimerMode.LastDayOfMonth: return dt.Day == ( GetLastDayByMonth( dt ) - Config.DaySeq );
						default: return false;
					}
				}
				else
					return false;
			}
		}

		/// <summary>
		/// 時間是否到了
		/// </summary>
		/// <returns></returns>
		private bool CheckTimeIsUp( TimeSpan time )
		{
			var tmp = new TimeSpan( time.Hours, time.Minutes, time.Seconds );
			if ( Config.Times == null )
				return ( tmp.Ticks == 0 );
			else
			{
				foreach ( var t in Config.Times )
				{
					if ( t == tmp ) return true;
				}
				return false;
			}
		}

		/// <summary>
		/// 從現在起到下次時間到還有多少時間
		/// </summary>
		/// <returns>時間間隔</returns>
		public TimeSpan GetNextTimeUp()
		{
			///目標時間
			DateTime _NextDateTime = this.GetNextDateTime();	// 儲存下一次要執行的時間
			return _NextDateTime - DateTime.Now;
		}

		/// <summary>
		/// 獲取下一次指定配置的時間是多少
		/// </summary>
		/// <returns></returns>
		public DateTime GetNextDateTime()
		{
			var time = GetNextTimeConfig();
			DateTime dt = DateTime.Now;
			DateTime now, target;
			switch ( Config.TimerMode )
			{
				case TimerMode.Day:
					#region 每天指定某時執行一次
					now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );
					if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 );	//如果當前時間小於指定時刻,則不需要加天

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Month:
					#region 每月指定某天某時執行一次
					now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );	// 1月有31天,所以可以接受任何合法的Day值(因為在賦值時已判斷1~31)
					if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );


					// 當前月份的指定天數執行過了,因此月份加上一個月,當月份加了一個月之後,很可能當前實現的Day值可能會變小(例:3月31號,加上一個月,則日期會變成,4月30號,而不會變成5月1號),
					// 因此需要判斷指定的this.Day是不是比Day大(月份的Day變小的唯一原因是因為月份加了一個月之後,那個月並沒有this.Day的天數),如果沒有該this.Day的天數。則需要為該月份再加一個月。
					// 加一個月份,則那下個月一定可以大於等於this.Day, 看看每個月的天數就可以斷定了,
					// 因為沒有連著兩個月的日期小於等於30的,只有連續兩個月是31天。其它就是間隔的出現(this.Day最大隻可能為31)
					// 如此之後,接下來的dt=new DateTime時不為因為dt.Month的月份,因沒有this.Day天數而拋異常
					if ( Config.DaySeq > GetLastDayByMonth( dt ) ) dt = dt.AddMonths( 1 );	// 如此是為了確保dt.Month的月份一定有this.Day天(因此如果設定為每個月的31號執行的程式,就只會在1,3,5,7,8,10,12幾個月份會執行)

					dt = new DateTime( dt.Year, dt.Month, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.LastDayOfMonth:
					#region 每個月倒數第N天的某時某刻執行一次
					var lastDaybymonth = GetLastDayByMonth( dt ) - Config.DaySeq;
					now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );	// 1月有31天,所以可以接受任何合法的Day值(因為在賦值時已判斷1~31)
					if ( now.Ticks >= target.Ticks )
					{
						dt = dt.AddMonths( 1 );
						dt = new DateTime( dt.Year, dt.Month, GetLastDayByMonth( dt ) - Config.DaySeq, time.Hours, time.Minutes, time.Seconds );// 根據新月份求新月份的最後一天。
					}
					else
						dt = new DateTime( dt.Year, dt.Month, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Week:
					#region 每星期指定星期某時執行一次
					int dow = ( int )dt.DayOfWeek;
					now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, Config.DaySeq + 1, time.Hours, time.Minutes, time.Seconds );

					if ( now.Ticks >= target.Ticks )
						dt = dt.AddDays( Config.DaySeq - dow + 7 );
					else
						dt = dt.AddDays( Config.DaySeq - dow );

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Date:
					#region 每年指定某月某日某時執行一次
					now = new DateTime( 4, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second );

					// 0004年閏年,可以支援2月29.因此選了0004, 這樣就不會在構造Target時異常,
					// 因為比較的關鍵不在年。所以,只要Now和Target的年份一樣就可以,設定成什麼年份無所謂
					target = new DateTime( 4, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );

					if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
					if ( Config.MonthSeq == 2 && Config.DaySeq == 29 )
					{
						// 因為閏年的最大間隔是8年,平時是4年一閏,可是0096年閏完之後,下一個閏年就是0104年,因此。。。
						for ( int i = 0; i < 8; i++ )
							if ( DateTime.IsLeapYear( dt.Year + i ) )
							{
								dt = dt.AddYears( i );
								break;
							}
					}

					dt = new DateTime( dt.Year, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Year:
					#region 每年指定第N天某時執行一次
					now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );
					if ( dt.DayOfYear > Config.DaySeq || dt.DayOfYear == Config.DaySeq && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
					dt = dt.AddDays( Config.DaySeq - dt.DayOfYear );

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				default:
					throw new Exception( "定時器時間配置異常!" );
			}

			return dt;
		}

		/// <summary>
		/// 獲取指定日期所在月份的最後一天
		/// </summary>
		/// <param name="dt"></param>
		/// <returns></returns>
		private int GetLastDayByMonth( DateTime dt )
		{
			switch ( dt.Month )
			{
				case 4:
				case 6:
				case 9:
				case 11:
					return 30;
				case 2:
					return DateTime.IsLeapYear( dt.Year ) ? 29 : 28;
				default:
					return 31;
			}
		}

		/// <summary>
		/// 獲取下一個時間點
		/// </summary>
		/// <returns></returns>
		private TimeSpan GetNextTimeConfig()
		{
			if ( Config.Times == null || Config.Times.Length == 0 )
				return new TimeSpan( 0 );
			else
			{
				var minData = TimeSpan.MaxValue;		// 最小時間
				var minExecData = TimeSpan.MaxValue;	// 大於當前時間的最小時間
				foreach ( var t in Config.Times )
				{
					if ( DateTime.Now.TimeOfDay < t && minExecData >= t )	// 找出比當前時間大的最小時間
						minExecData = t;
					if ( minData > t )	// 找出最小的一個時間,當前時間不參與運算
						minData = t;
				}

				if ( minExecData == TimeSpan.MaxValue )	// 如果找不到比當前時間大的最小時間,則選擇最小時間返回
					return minData;
				else
					return minExecData;
			}
		}
		#endregion
	}
	#endregion

	#region 系統配置實體類&配置讀取類
	/// <summary>
	/// 時間配置類
	/// </summary>
	public class ServiceTimerConfig
	{
		/// <summary>
		/// 預設配置
		/// </summary>
		public string Default { get; set; }
		/// <summary>
		/// 配置項
		/// </summary>
		public TimerConfig[] Config { get; set; }
	}
	/// <summary>
	/// 時間配置
	/// </summary>
	public class TimerConfig
	{
		/// <summary>
		/// 配置引用名
		/// </summary>
		public string RefName { get; set; }

		/// <summary>
		/// 時間模式
		/// timeMode取值如下:TimerMode.Month、TimerMode.Week、TimerMode.Week、TimerMode.Day、TimerMode.Date、TimerMode.Year
		/// </summary>
		public TimerMode TimerMode { get; set; }

		/// <summary>
		/// 指定某個時間演算法的第幾天,第1天就為1
		/// TimerMode=TimerMode.Month			時, 該DaySeq表示每個月中的第幾天
		///	TimerMode=TimerMode.Week			時, 該DaySeq表示每個星期中的星期幾(0-星期天,其它用1-6表示)
		///	TimerMode=TimerMode.Day				時, 該值不需要設定
		///	TimerMode=TimerMode.Date			時, 該DaySeq表示每個日期中的天數,如:8月12號,則DaySeq為12,MonthSeq為8
		///	TimerMode=TimerMode.LastDayOfMonth	時, 該DaySeq表示每個月倒數第幾天
		///	TimerMode=TimerMode.Year			時, 該DaySeq表示每年中的第幾天
		/// </summary>
		public int DaySeq { get; set; }

		/// <summary>
		/// 當指定一年中某個月的某個日期時有用到如:指定一年中8月12號,則這裡的MonthSeq就應該為8
		/// </summary>
		public int MonthSeq { get; set; }

		/// <summary>
		/// 迴圈處理時間間隔(單位毫秒)
		/// </summary>
		public TimeSpan Interval { get; set; }

		/// <summary>
		/// 啟動延遲時間(單位毫秒)
		/// </summary>
		public TimeSpan Delay { get; set; }

		/// <summary>
		/// 時間設定
		/// </summary>
		public TimeSpan[] Times { get; set; }
	}
	/// <summary>
	/// 服務處理方法
	/// </summary>
	public enum TimerMode
	{
		/// <summary>
		/// 輪詢方式
		/// </summary>
		Interval = 0,
		/// <summary>
		/// 一個月中某個天數的指定時間
		/// </summary>
		Month = 1,
		/// <summary>
		/// 一週中的周幾的指定時間
		/// </summary>
		Week = 2,
		/// <summary>
		/// 一天中的指定時間
		/// </summary>
		Day = 3,
		/// <summary>
		/// 一年中第幾天的指定時間
		/// </summary>
		Year = 4,
		/// <summary>
		/// 一年中的指定日期的指定時間
		/// </summary>
		Date = 5,
		/// <summary>
		/// 每個月倒數第N天
		/// </summary>
		LastDayOfMonth,
		/// <summary>
		/// 未設定
		/// </summary>
		NoSet
	}
	/// <summary>
	/// 讀取配置資料
	/// </summary>
	public class ServiceTimerConfigManager : IConfigurationSectionHandler
	{
		private static Regex regEx = new Regex( @"^(?<h>[01]?\d|2[0-3])(?:[::](?<m>[0-5]\d?))?(?:[::](?<s>[0-5]\d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );

		/// <summary>
		/// 請求服務配置
		/// </summary>
		public static ServiceTimerConfig ServiceConfig { get; set; }
		/// <summary>
		/// 靜態建構函式
		/// </summary>
		static ServiceTimerConfigManager()
		{
			ConfigurationManager.GetSection( "ServiceTimerConfig" );
		}
		/// <summary>
		/// 讀取自定義配置節
		/// </summary>
		/// <param name="parent">父結點</param>
		/// <param name="configContext">配置上下文</param>
		/// <param name="section">配置區</param>
		/// <returns></returns>
		object IConfigurationSectionHandler.Create( object parent, object configContext, XmlNode section )
		{
			ServiceConfig = new ServiceTimerConfig();
			var config = new List<TimerConfig>();

			foreach ( XmlNode node in section.ChildNodes )
			{
				if ( node.NodeType == XmlNodeType.Element )
				{
					switch ( node.Name.ToLower() )
					{
						case "default":
							ServiceConfig.Default = node.InnerText;
							break; ;
						case "config":
							var tmp = new TimerConfig();
							SetTimerConfigValue( tmp, node );
							config.Add( tmp );
							break; ;
					}
				}
			}
			ServiceConfig.Config = config.ToArray();

			return ServiceConfig;
		}
		/// <summary>
		/// 設定定時器值
		/// </summary>
		/// <param name="Config"></param>
		/// <param name="node"></param>
		private void SetTimerConfigValue( TimerConfig Config, XmlNode node )
		{
			int tmp, h, m, s;
			long longTmp;
			var times = new List<TimeSpan>();

			foreach ( XmlNode xn in node.ChildNodes )
			{
				if ( xn.NodeType == XmlNodeType.Element )
				{
					switch ( xn.Name.ToLower() )
					{
						case "refname":
							Config.RefName = xn.InnerText;
							break;
						case "timermode":
							if ( xn.InnerText != null )
								Config.TimerMode = ( TimerMode )Enum.Parse( typeof( TimerMode ), xn.InnerText );
							break;
						case "delay":
							Int64.TryParse( xn.InnerText, out longTmp );
							Config.Delay = new TimeSpan( longTmp * 10 * 1000L );	// Delay配置值為毫秒
							break;
						case "interval":
							Int64.TryParse( xn.InnerText, out longTmp );		// Interval配置值為毫秒
							Config.Interval = new TimeSpan( longTmp * 10 * 1000L );
							break;
						case "monthseq":	// 月份
							Int32.TryParse( xn.InnerText, out tmp );
							Config.MonthSeq = tmp;
							break;
						case "dayseq":		// 指定第幾天的序號
							Int32.TryParse( xn.InnerText, out tmp );
							Config.DaySeq = tmp;
							break;
						case "times":
							//還是用這個函式處理下一級的配置
							SetTimerConfigValue( Config, xn );	// 設定時間策略
							break;
						case "timevalue":
							var mc = regEx.Match( xn.InnerText );
							if ( !mc.Success ) throw new Exception( "時間配置不正確!" );
							Int32.TryParse( mc.Groups["h"].Value, out h );
							Int32.TryParse( mc.Groups["m"].Value, out m );
							Int32.TryParse( mc.Groups["s"].Value, out s );
							times.Add( new TimeSpan( h, m, s ) );
							break;
					}
				}
			}
			if ( times.Count != 0 )
				Config.Times = times.ToArray();
		}
	}
	#endregion
}