【Python】ntplibとAPIからNICTの時刻を取得する

# やりたいこと
デバイスのシステム時間とNICTの時刻の誤差を求めたい

日本の情報通信研究機構（NICT）には時刻取得のAPIが記載されていないため、ntplibライブラリを使用して求めたい

APIだけでも誤差を求めたい


# 環境

- Windows 11
- Python 3.11.5
- Anaconda 3
- VScode

# 方法1: NICTのAPIを使用する

#### ステップ1: 必要なライブラリのインストール


APIを使用するには、`requests`ライブラリが必要です！  

```prompt:Anaconda prompt
pip install requests
```  


#### ステップ2: APIを使って時刻を取得し、誤差を計算する
NICTからAPIを取得してきます。
`https://www.nict.go.jp/JST/JST5.html` のHTMLの中に、
`var ServerList`の項目があります。 

そこにはJSONのデータフォーマットが３つあるので、そのうちの一つを取ってきます。
（今回は`3fe5a5f690efc790d4764f1c528a4ebb89fa4168.nict.go.jp/cgi-bin/json`を使いました。）

![スクリーンショット 2024-02-18 183722.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695780/00429a23-a45b-3733-4603-5bee3369b3b7.png)


#### ステップ2: APIを使って時刻を取得し、誤差を計算する
先ほどのAPIを取得して誤差を求めていきます。
NPTサーバーから取得された時間は、UTC時間（協定世界時）です。
そのため、ローカルタイムとの誤差を求めるためには、取得した時間をJST（日本標準時）に変換する必要があります。
ここでは`timedelta`を使い、UTC時間に９時間を加えてJST時間に変換しています。

```python:Python
import requests
from datetime import datetime, timezone, timedelta
import time

api_url = "https://3fe5a5f690efc790d4764f1c528a4ebb89fa4168.nict.go.jp/cgi-bin/json"
response = requests.get(api_url)

if response.status_code == 200:
    data = response.json()
    unix_timestamp = data.get("st")
    jst_time = datetime.fromtimestamp(unix_timestamp, tz=timezone.utc) + timedelta(hours=9)
    local_time = datetime.now()
    time_diff = (local_time - jst_time).total_seconds()

    print(f"NICTの時刻 (JST): {jst_time.strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"ローカルシステム時刻: {local_time.strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"誤差（秒）: {time_diff}")
else:
    print("時刻データを取得できませんでした。")
```

### 出力
こんな感じで出力されます。
```
NICTの日本標準時: 2024-02-18 19:15:03
ローカルシステム時刻: 2024-02-18 19:15:03
誤差（秒）: 0.390158
```






# 方法2: ntplibを使用する
APIを取得するのではなく、`ntplib`ライブラリを利用して誤差を取得します。これでNTPサーバーから簡単に時刻情報が取得できます。
体感ですが、APIによる時間取得よりもこちらの方が少し早いです。

#### ステップ1: `ntplib`のインストール

```prompt:prompt
pip install ntplib
```  

#### ステップ2: NTPサーバーから時刻を取得し、誤差を計算する

```python:python
import ntplib
from datetime import datetime, timedelta
import sys

class MyNTPClient:
    def __init__(self, ntp_server_host='ntp.nict.jp'):
        self.ntp_client = ntplib.NTPClient()
        self.ntp_server_host = ntp_server_host

    def get_nowtime(self, timeformat='%Y/%m/%d %H:%M:%S'):
        try:
            response = self.ntp_client.request(self.ntp_server_host, version=3)
            nowtime = datetime.utcfromtimestamp(response.tx_time) + timedelta(hours=9)
            return nowtime.strftime(timeformat)
        except Exception as e:
            sys.exit(f"Error: {e}")

ntp_client = MyNTPClient()
ntp_time = ntp_client.get_nowtime()
local_time = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
print(f"NTPサーバー時刻 (JST): {ntp_time}")
print(f"ローカルシステム時刻: {local_time}")
```

### 出力
こんな感じです。
```
NTPサーバー時刻 (JST): 2024-02-18 19:11:34.319178
ローカルシステム時刻: 2024-02-18 19:11:34.696917
誤差（秒）: 0.377739
```
# まとめ
Pythonを使用してNICTのAPIとntplibライブラリを介して正確な時刻を取得し、Pythonのローカルシステム時刻との誤差を計算する2つの方法を紹介しました。

予約の争奪戦等の予約をPythonで実行したい場合、数秒の時刻のズレは命取りになります。各デバイス端末の時間差をできるだけ小さくしたいときに活用できると思います。

私は指定時間に予約ボタンを押すプログラムで使っています。

# 参考

https://qiita.com/komorin0521/items/63203f0c3fcea0f40a87

https://kacchanblog.com/programming/python-time-error