Fortran - 各種時刻系の換算!

Updated:


暦計算や天文計算を行う際に必要な各種時刻系換算を Fortran 95 で行いました。

過去には Ruby や Python でも行いましたが。

0. 前提条件

  • LMDE 3 (Linux Mint Debian Edition 3; 64bit) での作業を想定。
  • GCC 6.3.0 (GFortran 6.3.0) でのコンパイルを想定。

1. 各種時刻系について

当ブログ過去記事を参照のこと。

また、過去に Ruby や Python で作成したスクリプトでは、ΔTの計算に DUT1 の値を加味していなかった(最大で1秒弱の誤差があった)が、今回は加味するようにした。

2. ソースコードの作成

  • 以下は実行部分。

File: conv_time.f95

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
!*******************************************************************************
! 各種時刻換算
!
!   date          name            version
!   2018.10.14    mk-mode.com     1.00 新規作成
!   2018.11.09    mk-mode.com     1.01 時刻の取扱変更(マイクロ秒 => ミリ秒)
!   2018.11.11    mk-mode.com     1.02 ΔT計算に DUT1 を加味
!
! Copyright(C) 2018 mk-mode.com All Rights Reserved.
! ---
! 引数 : JST(日本標準時)
!          YYYYMMDD[HHMMSS[MMM]]
!          無指定なら現在(システム日時)と判断。(上記最後の MMM はミリ秒)
! ---
! * 定数 DUT1 (= UT1 - UTC) の値は以下を参照。
!     [日本標準時プロジェクト Announcement of DUT1]
!     (http://jjy.nict.go.jp/QandA/data/dut1.html)
!   但し、値は 1.0 秒以下なので、精度を問わないなら 0.0 固定でもよい(?)
! * UTC - TAI(協定世界時と国際原子時の差)は、以下のとおりとする。
!   - 1972年07月01日より古い場合は一律で 10
!   - 2019年07月01日以降は一律で 37
!   - その他は、指定の値
!     [日本標準時プロジェクト Information of Leap second]
!     (http://jjy.nict.go.jp/QandA/data/leapsec.html)
! * ΔT = TT - UT1 は、以下のとおりとする。
!   - 1972-01-01 以降、うるう秒挿入済みの年+2までは、以下で算出
!       ΔT = 32.184 - (UTC - TAI) - DUT1
!     UTC - TAI は
!     [うるう秒実施日一覧](http://jjy.nict.go.jp/QandA/data/leapsec.html)
!     を参照
!   - その他の期間は NASA 提供の略算式により算出
!     [NASA - Polynomial Expressions for Delta T]
!     (http://eclipse.gsfc.nasa.gov/SEcat5/deltatpoly.html)
! * 構造型 type(t_time) は time モジュール内で定義
!*******************************************************************************
!
program conv_time
  use const, only : SP, DP, JST_UTC, FMT_DT_0
  use time
  use delta_t
  implicit none
  type(t_time) :: jst, utc, tai, ut1, tt, tcg, tcb, tdb
  integer(SP)  :: utc_tai
  real(DP)     :: jd, jd_tcb, t, dut1, dt

  ! コマンドライン引数(現在日時(JST)), UTC 取得
  call get_arg(jst, utc)
  if (jst%year == 0) stop

  ! 各種時刻換算
  call gc2jd(utc, jd)                  ! UTC -> JD
  call jd2jc(jd, t)                    ! JD  -> JC
  call utc2utc_tai(utc, utc_tai)       ! UTC -> UTC - TAI
  call utc2dut1(utc, dut1)             ! UTC -> DUT1
  call utc2dt(utc, utc_tai, dut1, dt)  ! UTC -> delta T
  call utc2tai(utc, utc_tai, tai)      ! UTC -> TAI
  call utc2ut1(utc, dut1, ut1)         ! UTC -> UT1
  call tai2tt(tai, tt)                 ! TAI -> TT
  call tt2tcg(tt, jd, tcg)             ! TT  -> TCG
  call tt2tcb(tt, jd, tcb)             ! TT  -> TCB
  call gc2jd(tcb, jd_tcb)              ! TCB -> JD(TCB)
  call tcb2tdb(tcb, jd_tcb, tdb)       ! TCB -> TDB

  ! 結果出力
  print '("      JST: ", A)',                date_fmt(jst)
  print '("      UTC: ", A)',                date_fmt(utc)
  print '("JST - UTC: ", I7, 12X,   "(hours)")',   JST_UTC
  print '("       JD: ", F18.10, X, "(days)")',         jd
  print '("        T: ", F18.10, X, "(centuries)")',     t
  print '("UTC - TAI: ", I7, 12X,   "(seconds)")', utc_tai
  print '("     DUT1: ", F9.1, 10X, "(seconds)")',    dut1
  print '("  delta T: ", F11.3, 8X, "(seconds)")',      dt
  print '("      TAI: ", A)',                date_fmt(tai)
  print '("      UT1: ", A)',                date_fmt(ut1)
  print '("       TT: ", A)',                date_fmt(tt )
  print '("      TCG: ", A)',                date_fmt(tcg)
  print '("      TCB: ", A)',                date_fmt(tcb)
  print '("   JD_TCB: ", F18.10, X, "(days)")',     jd_tcb
  print '("      TDB: ", A)',                date_fmt(tdb)

  stop
contains
  ! コマンドライン引数取得
  ! * YYYYMMDD[HHMMSS[MMM]] 形式
  ! * 17桁超入力された場合は、18桁目以降の部分は切り捨てる
  ! * コマンドライン引数がなければ、システム日付を JST とする
  ! * 日時の整合性チェックは行わない
  !
  ! :param(out) type(t_time) jst
  ! :param(out) type(t_time) utc
  subroutine get_arg(jst, utc)
    implicit none
    type(t_time), intent(out) :: jst, utc
    character(17) :: gc
    integer(SP)   :: dt(8)
    integer(SP)   :: len_gc

    if (iargc() == 0) then
      call date_and_time(values=dt)
      jst = t_time(dt(1), dt(2), dt(3), dt(5), dt(6), dt(7), dt(8))
    else
      call getarg(1, gc)
      len_gc = len(trim(gc))
      if (len_gc /= 8 .and. len_gc /= 14 .and. len_gc /= 17) then
        print *, "Format: YYYYMMDD[HHMMSS[MMM]"
        return
      end if
      read (gc, FMT_DT_0) jst
    end if
    if (jst%year /= 0) call jst2utc(jst, utc)
  end subroutine get_arg
end program conv_time

モジュールや定数ファイルを含めた全てのファイル(バイナリファイルを除く)は GitHub にアップしている。(当然ながら、モジュール部分の方が計算の本質となっている)

3. ソースコードのビルド

$ make
  • やり直す場合は、 make clean してから。

4. 準備

  • JPL 天文暦バイナリデータ JPLEPH を実行ファイルと同じディレクトリ内に配置。
    (参照「JPL 天文暦データのバイナリ化!」)
  • うるう年ファイル LEAP_SEC.txt, DUT1 ファイル DUT1.txt は適宜最新のものに更新すること。

5. 実行方法

$ ./conv_time [YYYYMMDDHHMMSSMMM]
  • JST(日本標準時)は「年・月・日・時・分・秒・ミリ秒」を17桁で指定する。
  • JST(日本標準時)を指定しない場合は、システム日時を JST とみなす。

以下、実行例。

$ ./conv_time 20181226123456123
      JST: 2018-12-26 12:34:56.123
      UTC: 2018-12-26 03:34:56.123
JST - UTC:       9            (hours)
       JD: 2458478.6492606830 (days)
        T:       0.1898329709 (centuries)
UTC - TAI:     -37            (seconds)
     DUT1:       0.0          (seconds)
  delta T:      69.184        (seconds)
      TAI: 2018-12-26 03:35:33.123
      UT1: 2018-12-26 03:34:56.123
       TT: 2018-12-26 03:36:05.307
      TCG: 2018-12-26 03:36:06.230
      TCB: 2018-12-26 03:36:25.849
   JD_TCB: 2458478.6502991784 (days)
      TDB: 2018-12-26 03:36:05.307

以上、





 

Sponsored Link

 

Comments