SunCalcを使ってJavaScriptで日の出・日の入りや月の出・月の入りを計算する

# はじめに

日の出・日の入りや月の出・月の入りなどの天文計算は複雑で、自分で実装するとなると面倒である。そこで[SunCalc](https://github.com/mourner/suncalc)というライブラリを用いて、JavaScriptで計算してみることにした。また、計算結果を[国立天文台ウェブサイト](https://eco.mtk.nao.ac.jp/cgi-bin/koyomi/koyomix.cgi)のものと比較した。

SunCalcはnpmを用いてインストールし、node.jsで実行した。用いたバージョンは以下の通りである。SunCalc自体は他のパッケージへの依存性はなくDateオブジェクトで入出力を行うが、ここでは日時計算ライブラリの[Moment.js](https://momentjs.com/)を用いている。

```package.json
    "dependencies": {
        "moment": "^2.29.1",
        "suncalc": "^1.8.0"
    }
```

# コード例
以下に日の出・日の入りの時刻と方位、南中時刻と高度、月の出・月の入りの時刻と方位、月齢を求めるコード例を示す。

- SunCalc自体はDateオブジェクトで入出力を行うが、日時計算のため[Moment.js](https://momentjs.com/)を用いてラップしている。
- SunCalcでは方位角は南から西回りで表現されるが、北から東回りで表現するために180°を加えている。
- 135°E以西で00JSTのdateを`SunCalc.getTimes`に渡すと前日の日の出・南中・日の入りが返ってくることがあるので、12JSTのdateを渡している。
- 月齢(phase)は日数では無く、0から1までの浮動小数点数で返される。もし日数に直す場合は、月の満ち欠け周期(29.3-29.8日で可変)を用いて計算する必要がある
- 月齢(phase)の計算は、正午月齢と比較するために12JSTの値を出力している。

```sun.js
import moment from "moment";
import SunCalc from "suncalc";

const RADTODEG = 180 / Math.PI;

function calcSun(datem, longitude, latitude) {
    const { sunrise, sunset, solarNoon } = SunCalc.getTimes(
        datem
            .clone()
            .hour(12)
            .toDate(),
        latitude,
        longitude
    );
    let sunriseAzimuth, sunsetAzimuth, noonElevation;
    if (sunrise) {
        const { azimuth } = SunCalc.getPosition(sunrise, latitude, longitude);
        sunriseAzimuth = azimuth * RADTODEG + 180;
    } else {
        sunriseAzimuth = null;
    }
    if (sunset) {
        const { azimuth } = SunCalc.getPosition(sunset, latitude, longitude);
        sunsetAzimuth = azimuth * RADTODEG + 180;
    } else {
        sunsetAzimuth = null;
    }
    if (solarNoon) {
        const { altitude } = SunCalc.getPosition(
            solarNoon,
            latitude,
            longitude
        );
        noonElevation = altitude * RADTODEG;
    } else {
        noonElevation = null;
    }
    return {
        sunrise: sunrise ? moment(sunrise) : null,
        sunriseAzimuth,
        noon: solarNoon ? moment(solarNoon) : null,
        noonElevation,
        sunset: sunset ? moment(sunset) : null,
        sunsetAzimuth
    };
}

function calcMoon(datem, longitude, latitude) {
    const date = datem.toDate();
    const times = SunCalc.getMoonTimes(date, latitude, longitude);
    const date12 = datem
        .clone()
        .hour(12)
        .toDate();
    const { phase } = SunCalc.getMoonIllumination(date12);
    let moonriseAzimuth, moonsetAzimuth;
    if (times.rise) {
        const { azimuth } = SunCalc.getMoonPosition(
            times.rise,
            latitude,
            longitude
        );
        moonriseAzimuth = azimuth * RADTODEG + 180;
    } else {
        moonriseAzimuth = null;
    }
    if (times.set) {
        const { azimuth } = SunCalc.getMoonPosition(
            times.set,
            latitude,
            longitude
        );
        moonsetAzimuth = azimuth * RADTODEG + 180;
    } else {
        moonsetAzimuth = null;
    }
    return {
        moonrise: times.rise ? moment(times.rise) : null,
        moonset: times.set ? moment(times.set) : null,
        moonriseAzimuth,
        moonsetAzimuth,
        phase
    };
}
```


# 比較結果

2020年12月の東京(35.6581N, 139.7414E)について、[国立天文台ウェブサイトのこよみの計算](https://eco.mtk.nao.ac.jp/cgi-bin/koyomi/koyomix.cgi)と [SunCalc](https://github.com/mourner/suncalc)の計算結果を比較した。

日の出・日の入り・南中時刻については1分程度の差があった。方位や高度については0.1°程度の差があった。

月の出・月の入りについては最大8分程度の差があった。方位については1°程度の差があった。月齢については直接比較できないが、30倍すると概ね一致することは確認できる。

## 太陽

国立天文台

年月日 | 出 | 方位[°] | 南中 | 高度[°] | 入り | 方位[°]
---------- | ---- | ----- | -------- | ---- | ----- | -----
2020/12/01 | 6:32 | 116.5 | 11:30:04 | 32.5 | 16:28 | 243.4
2020/12/02 | 6:33 | 116.7 | 11:30:27 | 32.4 | 16:28 | 243.2
2020/12/03 | 6:34 | 116.9 | 11:30:50 | 32.2 | 16:28 | 243.0
2020/12/04 | 6:35 | 117.1 | 11:31:14 | 32.1 | 16:28 | 242.8
2020/12/05 | 6:36 | 117.3 | 11:31:39 | 32.0 | 16:28 | 242.7
2020/12/06 | 6:36 | 117.4 | 11:32:04 | 31.8 | 16:28 | 242.5
2020/12/07 | 6:37 | 117.6 | 11:32:30 | 31.7 | 16:28 | 242.4
2020/12/08 | 6:38 | 117.7 | 11:32:56 | 31.6 | 16:28 | 242.2
2020/12/09 | 6:39 | 117.8 | 11:33:23 | 31.5 | 16:28 | 242.1
2020/12/10 | 6:40 | 117.9 | 11:33:50 | 31.4 | 16:28 | 242.0
2020/12/11 | 6:40 | 118.1 | 11:34:17 | 31.3 | 16:28 | 241.9
2020/12/12 | 6:41 | 118.2 | 11:34:45 | 31.3 | 16:28 | 241.8
2020/12/13 | 6:42 | 118.2 | 11:35:14 | 31.2 | 16:29 | 241.7
2020/12/14 | 6:43 | 118.3 | 11:35:42 | 31.1 | 16:29 | 241.6
2020/12/15 | 6:43 | 118.4 | 11:36:11 | 31.1 | 16:29 | 241.6
2020/12/16 | 6:44 | 118.5 | 11:36:40 | 31.0 | 16:29 | 241.5
2020/12/17 | 6:44 | 118.5 | 11:37:10 | 31.0 | 16:30 | 241.5
2020/12/18 | 6:45 | 118.5 | 11:37:39 | 31.0 | 16:30 | 241.4
2020/12/19 | 6:46 | 118.6 | 11:38:09 | 31.0 | 16:31 | 241.4
2020/12/20 | 6:46 | 118.6 | 11:38:39 | 30.9 | 16:31 | 241.4
2020/12/21 | 6:47 | 118.6 | 11:39:09 | 30.9 | 16:32 | 241.4
2020/12/22 | 6:47 | 118.6 | 11:39:38 | 30.9 | 16:32 | 241.4
2020/12/23 | 6:48 | 118.6 | 11:40:08 | 30.9 | 16:33 | 241.4
2020/12/24 | 6:48 | 118.6 | 11:40:38 | 31.0 | 16:33 | 241.4
2020/12/25 | 6:49 | 118.6 | 11:41:08 | 31.0 | 16:34 | 241.5
2020/12/26 | 6:49 | 118.5 | 11:41:38 | 31.0 | 16:34 | 241.5
2020/12/27 | 6:49 | 118.5 | 11:42:07 | 31.1 | 16:35 | 241.6
2020/12/28 | 6:50 | 118.4 | 11:42:36 | 31.1 | 16:36 | 241.6
2020/12/29 | 6:50 | 118.3 | 11:43:05 | 31.2 | 16:36 | 241.7
2020/12/30 | 6:50 | 118.2 | 11:43:34 | 31.2 | 16:37 | 241.8
2020/12/31 | 6:50 | 118.2 | 11:44:03 | 31.3 | 16:38 | 241.9

SunCalc

年月日 | 出 | 方位[°] | 南中 | 高度[°] | 入り | 方位[°]
---------- | ---- | ----- | -------- | ---- | ----- | -----
2020/12/01 | 6:33 | 116.7 | 11:31:32 | 32.5 | 16:29 | 243.6
2020/12/02 | 6:34 | 116.9 | 11:31:55 | 32.4 | 16:29 | 243.4
2020/12/03 | 6:35 | 117.1 | 11:32:18 | 32.2 | 16:29 | 243.2
2020/12/04 | 6:36 | 117.2 | 11:32:42 | 32.1 | 16:29 | 243.0
2020/12/05 | 6:37 | 117.4 | 11:33:06 | 32.0 | 16:29 | 242.9
2020/12/06 | 6:38 | 117.6 | 11:33:30 | 31.9 | 16:29 | 242.7
2020/12/07 | 6:38 | 117.7 | 11:33:55 | 31.7 | 16:29 | 242.6
2020/12/08 | 6:39 | 117.8 | 11:34:21 | 31.6 | 16:29 | 242.4
2020/12/09 | 6:40 | 118.0 | 11:34:47 | 31.5 | 16:29 | 242.3
2020/12/10 | 6:41 | 118.1 | 11:35:13 | 31.4 | 16:29 | 242.2
2020/12/11 | 6:41 | 118.2 | 11:35:40 | 31.3 | 16:29 | 242.1
2020/12/12 | 6:42 | 118.3 | 11:36:07 | 31.3 | 16:29 | 241.9
2020/12/13 | 6:43 | 118.4 | 11:36:35 | 31.2 | 16:29 | 241.9
2020/12/14 | 6:44 | 118.5 | 11:37:02 | 31.1 | 16:30 | 241.8
2020/12/15 | 6:44 | 118.5 | 11:37:30 | 31.1 | 16:30 | 241.7
2020/12/16 | 6:45 | 118.6 | 11:37:58 | 31.0 | 16:30 | 241.6
2020/12/17 | 6:45 | 118.7 | 11:38:27 | 31.0 | 16:30 | 241.6
2020/12/18 | 6:46 | 118.7 | 11:38:55 | 31.0 | 16:31 | 241.5
2020/12/19 | 6:47 | 118.7 | 11:39:24 | 30.9 | 16:31 | 241.5
2020/12/20 | 6:47 | 118.8 | 11:39:53 | 30.9 | 16:32 | 241.5
2020/12/21 | 6:48 | 118.8 | 11:40:21 | 30.9 | 16:32 | 241.5
2020/12/22 | 6:48 | 118.8 | 11:40:50 | 30.9 | 16:33 | 241.5
2020/12/23 | 6:49 | 118.8 | 11:41:19 | 30.9 | 16:33 | 241.5
2020/12/24 | 6:49 | 118.7 | 11:41:48 | 30.9 | 16:34 | 241.5
2020/12/25 | 6:49 | 118.7 | 11:42:17 | 30.9 | 16:34 | 241.5
2020/12/26 | 6:50 | 118.7 | 11:42:46 | 31.0 | 16:35 | 241.6
2020/12/27 | 6:50 | 118.6 | 11:43:14 | 31.0 | 16:35 | 241.6
2020/12/28 | 6:50 | 118.6 | 11:43:43 | 31.1 | 16:36 | 241.7
2020/12/29 | 6:51 | 118.5 | 11:44:11 | 31.1 | 16:37 | 241.7
2020/12/30 | 6:51 | 118.4 | 11:44:40 | 31.2 | 16:37 | 241.8
2020/12/31 | 6:51 | 118.3 | 11:45:08 | 31.2 | 16:38 | 241.9

## 月

国立天文台

年月日 | 出 | 方位[°] | 入り | 方位[°] | 正午月齢[日]
---------- | ----- | ----- | ----- | ----- | ----
2020/12/01 | 17:06 |  61.4 |  7:01 | 297.4 | 15.9
2020/12/02 | 17:52 |  59.5 |  7:59 | 299.9 | 16.9
2020/12/03 | 18:44 |  59.2 |  8:54 | 300.9 | 17.9
2020/12/04 | 19:42 |  60.7 |  9:45 | 300.1 | 18.9
2020/12/05 | 20:44 |  63.9 | 10:31 | 297.6 | 19.9
2020/12/06 | 21:48 |  68.7 | 11:12 | 293.5 | 20.9
2020/12/07 | 22:54 |  74.8 | 11:48 | 288.0 | 21.9
2020/12/08 | --:-- | ----- | 12:22 | 281.6 | 22.9
2020/12/09 |  0:01 |  81.7 | 12:53 | 274.4 | 23.9
2020/12/10 |  1:08 |  89.3 | 13:25 | 266.9 | 24.9
2020/12/11 |  2:17 |  97.1 | 13:57 | 259.3 | 25.9
2020/12/12 |  3:29 | 104.7 | 14:33 | 252.2 | 26.9
2020/12/13 |  4:42 | 111.5 | 15:14 | 246.0 | 27.9
2020/12/14 |  5:56 | 116.9 | 16:01 | 241.4 | 28.9
2020/12/15 |  7:07 | 120.4 | 16:56 | 238.9 |  0.4
2020/12/16 |  8:13 | 121.5 | 17:57 | 238.7 |  1.4
2020/12/17 |  9:09 | 120.3 | 19:02 | 240.7 |  2.4
2020/12/18 |  9:57 | 117.2 | 20:08 | 244.6 |  3.4
2020/12/19 | 10:36 | 112.6 | 21:12 | 249.7 |  4.4
2020/12/20 | 11:10 | 107.2 | 22:13 | 255.5 |  5.4
2020/12/21 | 11:39 | 101.2 | 23:11 | 261.8 |  6.4
2020/12/22 | 12:06 |  94.9 | --:-- | ----- |  7.4
2020/12/23 | 12:31 |  88.7 |  0:08 | 268.2 |  8.4
2020/12/24 | 12:57 |  82.5 |  1:03 | 274.5 |  9.4
2020/12/25 | 13:23 |  76.6 |  1:59 | 280.7 | 10.4
2020/12/26 | 13:52 |  71.1 |  2:55 | 286.5 | 11.4
2020/12/27 | 14:25 |  66.3 |  3:53 | 291.7 | 12.4
2020/12/28 | 15:03 |  62.5 |  4:51 | 296.0 | 13.4
2020/12/29 | 15:47 |  60.0 |  5:50 | 299.1 | 14.4
2020/12/30 | 16:37 |  59.1 |  6:47 | 300.7 | 15.4
2020/12/31 | 17:34 |  60.0 |  7:41 | 300.6 | 16.4

SunCalc

年月日 | 出 | 方位[°] | 入り | 方位[°] | 正午phase
---------- | ----- | ----- | ----- | ----- | ----
2020/12/01 | 16:58 |  60.6 |  7:02 | 298.1 | 0.52
2020/12/02 | 17:45 |  58.6 |  8:01 | 300.9 | 0.55
2020/12/03 | 18:38 |  58.2 |  8:58 | 302.0 | 0.58
2020/12/04 | 19:38 |  59.8 |  9:50 | 301.1 | 0.62
2020/12/05 | 20:42 |  63.4 | 10:37 | 298.3 | 0.65
2020/12/06 | 21:50 |  68.5 | 11:18 | 293.8 | 0.69
2020/12/07 | 22:57 |  74.9 | 11:56 | 288.1 | 0.72
2020/12/08 | --:-- | ----- | 12:29 | 281.1 | 0.76
2020/12/09 |  0:06 |  82.3 | 13:02 | 273.8 | 0.79
2020/12/10 |  1:16 |  90.0 | 13:33 | 266.1 | 0.83
2020/12/11 |  2:26 |  97.9 | 14:06 | 258.7 | 0.87
2020/12/12 |  3:36 | 105.2 | 14:43 | 251.9 | 0.91
2020/12/13 |  4:48 | 111.5 | 15:24 | 246.2 | 0.95
2020/12/14 |  5:58 | 116.3 | 16:11 | 242.1 | 0.98
2020/12/15 |  7:07 | 119.4 | 17:06 | 240.0 | 0.02
2020/12/16 |  8:09 | 120.3 | 18:05 | 239.9 | 0.06
2020/12/17 |  9:04 | 119.1 | 19:08 | 241.9 | 0.09
2020/12/18 |  9:52 | 116.2 | 20:11 | 245.5 | 0.13
2020/12/19 | 10:32 | 111.9 | 21:14 | 250.3 | 0.16
2020/12/20 | 11:05 | 106.6 | 22:14 | 255.9 | 0.19
2020/12/21 | 11:36 | 100.9 | 23:13 | 262.0 | 0.22
2020/12/22 | 12:02 |  94.6 | --:-- | ----- | 0.25
2020/12/23 | 12:29 |  88.5 |  0:09 | 268.3 | 0.28
2020/12/24 | 12:53 |  82.3 |  1:05 | 274.8 | 0.31
2020/12/25 | 13:19 |  76.3 |  2:01 | 281.0 | 0.34
2020/12/26 | 13:48 |  70.8 |  2:57 | 286.9 | 0.37
2020/12/27 | 14:19 |  65.8 |  3:54 | 292.3 | 0.40
2020/12/28 | 14:55 |  61.7 |  4:53 | 296.8 | 0.43
2020/12/29 | 15:38 |  59.1 |  5:51 | 300.1 | 0.47
2020/12/30 | 16:28 |  58.0 |  6:49 | 301.9 | 0.49
2020/12/31 | 17:25 |  58.8 |  7:42 | 301.8 | 0.53