【C#】GPS信号を使用して現在の時刻を取得する


なんでそんなことするの?

端末がインターネットに接続できない場合、サーバから現在時刻を取得できません。
GPS信号(NMEAフォーマットデータ)には、UTC時刻が含まれているため、
インターネットには繋がらないけどGPSは拾えるという特殊な環境である場合、選択肢となるかもしれません。

Microsoft.WindowsAPICodePack.Sensors を使う

.Net標準であるGeoCoordinateWatcherで取得できる情報は、緯度・経度に限られているので、
Microsoft.WindowsAPICodePack.Sensors名前空間のSensorクラスを使用します。

GPSセンサを用意

Sensorクラスを使うためには、GPSセンサが必要です。
イマドキのWindows端末には基本的にGPSセンサが搭載されていないので、用意する必要があります。

とりあえず動作を試すだけであれば、amazon格安センサ( https://www.amazon.co.jp/gp/product/B01MA21TSX/ )で十分です。
ソースを動かすには、デバイスマネージャーのセンサーにGPSセンサーが追加されていれば問題ありません。

ソースコード

using Microsoft.WindowsAPICodePack.Sensors;

// 位置情報GUID
// 参考:https://docs.microsoft.com/en-us/windows/desktop/sensorsapi/sensor-category-location
private static Guid SENSOR_DATA_TYPE_LOCATION_GUID = new Guid("055C74D8-CA6F-47D6-95C6-1ED3637A0FF4");

// GPSセンサの取得
Sensor GeolocationSensor = SensorManager.GetSensorsByTypeId(SensorTypes.LocationGps)[0];

// GPS信号を取得する度に、イベント実行
GeolocationSensor.DataReportChanged += DataReportChanged;

        // GPS信号受信時の処理
        private void DataReportChanged(Sensor sender, EventArgs e)
        {
            // NMEAフォーマットデータ
            string[] gpsData = sender.DataReport.Values[SENSOR_DATA_TYPE_LOCATION_GUID][25].ToString().Split(',');

            // gpsData[1]:HHmmss.00 gpsData[9]:yyMMdd
            // NMEAフォーマットデータに含まれる時刻は、UTC時刻となる
            DateTimeOffset dto = new DateTimeOffset(
                DateTime.ParseExact(string.Format("{0}{1}", gpsData[9], gpsData[1].Substring(0, 6)), "yyMMddHHmmss", null), TimeSpan.Zero);
        }

GPS信号データは、DataReportChangedイベントのsenderを通じて取得します。

上記のGPSセンサを使用した環境では、
sender.DataReport.Values[SENSOR_DATA_TYPE_LOCATION_GUID]は、[0]:経度、[1]:緯度と続いていき、[25]にNMEAフォーマットの生データ(\$GPRMC,\$GPVTG,\$GPGNS...)が格納されています。