Ruby - カレンダー計算 gem の作成(JPL DE430 使用の高精度版)!

Updated:


以前、 旧暦計算サンプルプログラム を参考に作成したカレンダー計算 RubyGems ライブラリを作成しました。(但し、実際には多くの部分で微調整している)

但し、微調整はしているものの、このアルゴリズムは略算式を使用しているため、当然ながら若干の誤差が発生します。

そこで、 NASA の機関 JPL(Jet Propulsion Laboratory) の提供する太陽・月・惑星の正確な位置データ DE430 などを使用して計算する RubyGems ライブラリを作成しました。

以下では、作成した RubyGems ライブラリの簡単な利用方法をご紹介します。

0. 前提条件

  • Ruby 2.3.1-p112 での作業を想定。
  • 自作した gem ライブラリの名称は “mk_cal_jpl” で、計算対象年月日は 1549-12-21 〜 2650-01-25(但し、使用する JPL DE430 バイナリデータを別途作成し直している場合は、そこで設定した期間)。
  • 但し、祝日は当記事執筆時点の「国民の祝日に関する法律」によるもの。
  • 当ライブラリの計算可能項目
    • ユリウス日(UTC), ユリウス日(JST)
    • 曜日
    • 祝日
    • 二十四節気
    • 雑節
    • 干支(日)
    • 節句
    • 視黄経(太陽)
    • 視黄経(月)
    • 月齢(正午)
    • 旧暦
      • 閏月フラグ

【2017-03-13 追記】
当初、月齢計算が正しくないこと(直近の朔でなく2回前の朔からの経過日数を計算してしまうこと)があったが、直近の朔を取得するアルゴリズムを見直し、正しく計算できるように改修した。
また、計算に時間のかかる部分をあらかじめ計算しておき、それらを定数として取り込むよう処理を変更した。それにより、計算にかかる時間は1秒程度になった。
【追記ここまで】

1. 事前準備

JPL DE430 のデータを使用するので、バイナリデータ “linux_p1550p2650.430” をこちらから取得し “JPLEPH” とリネームして適当なディレクトリに配置しておく。

ただし、このバイナリファイルはサイズが大きいので、必要な年代のテキストデータのみをマージ&バイナリ化してもよい。(参考:JPL 天文暦データのバイナリ化!

2. RubyGems ライブラリのインストール

$ sudo gem install mk_cal_jpl

3. Ruby スクリプトの作成例

File: cal_jpl.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#! /usr/local/bin/ruby
# coding: utf-8
#---------------------------------------------------------------------------------
#= カレンダー
#  : 自作 RubyGems ライブラリ MkCalJpl を使用
#  ( 高野氏のプログラムを改良した MkCalendar を、 JPL DE430 から正確な位置データを
#    取得して計算するよう改良したもの )
#
# date          name            version
# 2016.09.17    mk-mode.com     1.00 新規作成
#
# Copyright(C) 2016 mk-mode.com All Rights Reserved.
#---------------------------------------------------------------------------------
# 引数 : JST(日本標準時)
#          書式:YYYYMMDD
#          無指定なら現在(システム日時)と判断。
#---------------------------------------------------------------------------------
#++
require 'date'
require 'mk_cal_jpl'

class CalJpl
  USAGE   = "[USAGE] .cal_jpl.rb [YYYYMMDD]"
  MSG_ERR = "[ERROR] Invalid date!"
  BIN_PATH = "/path/to/JPLEPH"

  def initialize
    @date = ARGV.shift
    @date ||= Time.now.strftime("%Y%m%d")
    unless @date =~ /\d{8}/
      puts USAGE
      exit 0
    end
    unless Date.valid_date?(@date[0,4].to_i, @date[4,2].to_i, @date[6,2].to_i)
      puts MSG_ERR
      exit 0
    end
  end

  def calc
    @obj = MkCalJpl.new(BIN_PATH, @date)
    oc = @obj.oc
    str =  sprintf("%04d-%02d-%02d", @obj.year, @obj.month, @obj.day)
    str << " #{@obj.yobi}曜日"
    str << " #{@obj.holiday}" unless @obj.holiday == ""
    str << " #{@obj.jd}UTC(#{@obj.jd_jst}JST) #{@obj.kanshi} "
    str << sprintf("%04d-%02d-%02d", oc[0], oc[2], oc[3])
    str << "(閏)" if oc[1] == 1
    str << " #{oc[4]}"
    str << " #{@obj.sekki_24}" unless @obj.sekki_24 == ""
    str << " #{@obj.zassetsu}" unless @obj.zassetsu == ""
    str << " #{@obj.sekku}" unless @obj.sekku == ""
    str << " #{@obj.lambda} #{@obj.alpha} #{@obj.moonage}"
    puts str
    # ついでに、黄経(月、太陽)から月相を計算
    # diff = @obj.alpha - @obj.lambda
    # diff += 360 if diff < 0
    # moonphase = (diff / 360.0 * 28).round
    # puts "\n月相: #{moonphase}"
  rescue => e
    $stderr.puts "[#{e.class}] #{e.message}"
    e.backtrace.each { |tr| $stderr.puts "\t#{tr}"}
    exit 1
  end
end

CalJpl.new.calc if __FILE__ == $0

4. サンプルスクリプトの実行

※高精度&高コストな計算を行っているので、非力なマシンだと計算終了まで20秒くらいかかる。

$ ./cal_jpl.rb 20161001
2016-10-01 土曜日 2457662.125UTC(2457662.5JST) 丙辰 2016-09-01 先負 
187.87444572124207 183.61161088402608 29.747843803837895

(実際には1行で出力)

5. gem ライブラリ


以前作成した Ruby スクリプトを何かと応用したかったので gem ライブラリ化した次第です。

以上。





 

Sponsored Link

 

Comments