ntpサーバを使って,デバイス間の時刻修正

カウントダウンアプリをつくっていますが,各自のスマホの時間がバラバラなので,ntpから差分とった時刻で正確な時間を出すようにしてみました.

修正中ですが,概ねこれで作動します.

元ネタはこれ→ http://ftvoid.com/blog/post/847

HTML5ならもう少し簡単だったのですが,,

using UnityEngine;
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using UnityEngine.UI;//use unity gui

// NTP同期時刻を管理するクラス
public class NtpDate : MonoBehaviour {
	private DateTime ntpDate;   // NTP同期時刻
	private float rcvAppDate;   // NTP通信時のアプリ時刻

	private IPEndPoint ipAny;
	private UdpClient sock;
	private Thread thread;
	private volatile bool threadRunning = false;
	private byte[] rcvData;

	public string myString; //for time display
	private DateTime endDate; //for end date
	public Transform myButton; //get button object
	public Text countText; //Text用変数
	private TimeSpan zure; 

	// 初期化
	void Start() {
		// リクエスト実行
		SyncDate();
		// 時刻表示(デバッグ用)
		StartCoroutine(ShowSyncDate());

		//Debug.Log (System.DateTime.Now);
	}

	// 同期時刻の表示
	private IEnumerator ShowSyncDate() {
		while ( true ) {
			yield return new WaitForSeconds(0.1f);//0.5f

			timeCheck ();// do timeCheck() every 1 second

			//if ( Date == false ) {
			if ( Date == null ) {
				Debug.Log("Time is not received.");
			} else {
			//Debug.Log("Receive date : " + Date.ToString());
				//	Debug.Log (DateTime.Now);//  DateTime.Now is confiured time
			}
		}
	}


	/// for GUI my add
	public void timeCheck(){

	endDate = new DateTime(2016, 4, 2, 18,30,00); //本番用

	//	endDate = new DateTime(2016, 2, 4, 12,30,00);//for test
		TimeSpan sabun = endDate - DateTime.Now; //compare now time and end time

//		Debug.Log ("before" + sabun);
//		Debug.Log ("after" + (sabun - zure));


		//int result = TimeSpan.Compare(endDate, DateTime.Now);// cant use
		sabun = sabun - zure;//zure naosu
		if (sabun.Days <= 0 && sabun.Hours <= 0 && sabun.Minutes <= 0 && sabun.Seconds <= 0) { //sabun is all zero and minus
			myString = "Light It Up Blue!"; //message of button
			countText.text = myString; //put text to GUItext
			myButton.GetComponent<Toggle>().interactable = true; //unlock the button
		} else {
			myString = string.Format ("{0:00}D{1:00}H{2:00}M{3:00}S", sabun.Days, sabun.Hours, sabun.Minutes, sabun.Seconds);//string format
			countText.text = myString; //time remaining
			myButton.GetComponent<Toggle>().interactable = false; //lock button before last time
		}



	}

	public void Update(){
	//	timeCheck ();

	}


	// アプリケーション終了時処理
	void OnApplicationQuit() {
		if ( thread != null ) {
			thread.Abort();
		}
		if ( sock != null ) {
			sock.Close();
		}
	}



	// 時刻同期を行う
	public void SyncDate() {
		// リクエスト実行
		threadRunning = true;
		thread = new Thread(new ThreadStart(Request));
		thread.Start();

		// リクエスト待機コルーチン実行
		StartCoroutine(WaitForRequest());

		Debug.Log("Thread is started.");
	}

	// NTPサーバに対してリクエストを実行する
	private void Request() {
		// ソケットを開く
		ipAny = new IPEndPoint(IPAddress.Any, 123);
	//	sock = new UdpClient(ipAny);
		sock = new UdpClient();

		// リクエスト送信
		byte[] sndData = new byte[48];
		sndData[0] = 0xB;
		sock.Send(sndData, sndData.Length, "ntp.jst.mfeed.ad.jp", 123);

		// データ受信
		rcvData = sock.Receive(ref ipAny);
		// 実行中フラグクリア
		threadRunning = false;
	}

	// リクエスト待機コルーチン
	private IEnumerator WaitForRequest() {
		// リクエスト終了まで待機
		while ( threadRunning ) {
			yield return 0;
		}

		// アプリ時刻保存
		rcvAppDate = Time.realtimeSinceStartup;
		Debug.Log (rcvAppDate);
		// 受信したバイナリデータをDateTime型に変換
		ntpDate = new DateTime(1900, 1, 1);
		var high = (double)BitConverter.ToUInt32(new byte[] { rcvData[43], rcvData[42], rcvData[41], rcvData[40] }, 0);
		var low = (double)BitConverter.ToUInt32(new byte[] { rcvData[47], rcvData[46], rcvData[45], rcvData[44] }, 0);
		ntpDate = ntpDate.AddSeconds(high + low / UInt32.MaxValue);

		// UTC→ローカル日時に変換
		ntpDate = ntpDate.ToLocalTime();
		zure = Date - DateTime.Now;
			Debug.Log ("zure" + zure);
	}

	// NTP同期時刻
	public DateTime Date {
		get {
			
			return ntpDate.AddSeconds(Time.realtimeSinceStartup - rcvAppDate);
		}
	}
}