利用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