利用C#透過HTTP取得即時時間資訊並回寫至本地端時間

我們都知道,NTP透過UDP協定與Port 123來進行操作,而UDP本身機制實在是太弱了,非常容易遭受到DDoS阻斷式服務的攻擊,因此這個管道常常會被網管人員封鎖掉。這篇文章試著使用C#搭配InterOP與HTTP,來進行遠端的時間查詢(非透過NTP機制)與設定本地端的時間。

我們這次使用的機制是採用TimeAndDate TAIWAN TAIPEI所提供的資訊,解析其網頁下,發現有一個WebRequest會傳送UTC資訊的時間,這就是我們採用的基礎啦!

透過C#要求HTTP正確時間,並且寫入本地端

有了正確的來源後,一切不再是問題,因此我們所需要的只剩將UTC轉GMT,並且轉換到+8時區(TimeZone: Taipei, Taiwan),然後去設定到本地端時間即可。程式碼如下:

using System;
using System.Runtime.InteropServices;
using static System.Console;

namespace SimplyConsole
{
	class Program
	{
		[DllImport("kernel32.dll")]
		private extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);

		private struct SYSTEMTIME
		{
			public ushort wYear;
			public ushort wMonth;
			public ushort wDayOfWeek;
			public ushort wDay;
			public ushort wHour;
			public ushort wMinute;
			public ushort wSecond;
			public ushort wMilliseconds;
		}

		static void Main(string[] args)
		{
			System.Timers.Timer oTimer = new System.Timers.Timer() { Interval = 1000 };
			oTimer.Elapsed += OnRefresh;
			Console.CursorVisible = false;
			WriteLine();
			WriteLine("Press any key to exit ...");
			oTimer.Start();
			ReadKey();
			oTimer.Stop();
			oTimer = null;
		}

		static void OnRefresh(Object sender, EventArgs args)
		{
			System.DateTime oUTC = new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(getUtcTimeStamp());
			//如果年分是錯的,表示網路回應有問題,那就跳出不進行更新
			if (oUTC.Year == 1970) { return; }
			System.DateTime oGMT = System.TimeZoneInfo.ConvertTime(oUTC, System.TimeZoneInfo.FindSystemTimeZoneById("Taipei Standard Time"));
			//設定
			SYSTEMTIME oTime = new SYSTEMTIME();
			oTime.wYear = System.Convert.ToUInt16(oUTC.Year);
			oTime.wMonth = System.Convert.ToUInt16(oUTC.Month);
			oTime.wDay = System.Convert.ToUInt16(oUTC.Day);
			oTime.wHour = System.Convert.ToUInt16(oUTC.Hour);
			oTime.wMinute = System.Convert.ToUInt16(oUTC.Minute);
			oTime.wSecond = System.Convert.ToUInt16(oUTC.Second);
			oTime.wMilliseconds = System.Convert.ToUInt16(oUTC.Millisecond);
      SetSystemTime(ref oTime);
			//輸出
			Console.CursorTop = 0;
			Console.CursorLeft = 0;
			Write($"NowTime: {oGMT.ToString("yyyy-MM-dd HH:mm:ss")}");
		}

		static double getUtcTimeStamp()
		{
			System.Net.HttpWebRequest oWRq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://www.timeanddate.com/scripts/ts.php?ut=1443508040915");
			//設定網路對接逾時秒數
			oWRq.Timeout = 1000;
			try
			{
				System.Net.HttpWebResponse oWRp = (System.Net.HttpWebResponse)oWRq.GetResponse();
				using (System.IO.StreamReader oSR = new System.IO.StreamReader(oWRp.GetResponseStream(), System.Text.Encoding.UTF8))
				{
					string cUTC = oSR.ReadToEnd();
					if (cUTC.IndexOf(".") != -1    cUTC.IndexOf(" ") != -1)
					{
						return System.Convert.ToDouble(cUTC.Split(' ')[0]);
					}
					else
					{
						return 0.0;
					}
				}
			}
			catch
			{
				return 0.0;
			}
		}
	}
}

在這裡將檔案包裝成exe,放到網路上方便您使用。依存.NET Framework 4.6,執行時請使用系統管理權限(在該執行檔案上方按右鍵)。

Sync System Time via HTTP (Taiwan, Taipei)

C# SyncSystemTimeViaHTTP NTPClient NTPServer TimeSync