【UTC⇔TAIの計算】
UTC⇔TTの計算式は単純です。

・UTCからTAI


・TAIからUTC


値。
TAI-UTCの表は、下記サイトが良さそうです。
RELATIONSHIP BETWEEN TAI AND UTC

※注意)
ここで扱うUTC(協定世界時)は、うるう秒の考えが導入された1972年1月1日以後です。それ以前に使われていたUTCとは計算が異なります。


(TAI - UTC)テーブル】
プログラムの前にのをテーブル作ります。このテーブルは、TAI→UTC変換でも使います。

実施日とTAI-UTC値がわかれば、秒単位でも日の小数でも、各自の好きな様に作ってください。

今後も、うるう秒が実施される毎に、このテーブルの更新が必要になるので、なるべく外部テキストファイルが良い。

テーブルサンプル
2457754.5    37.0        // 2017 1 1
2457204.5    36.0        // 2015 7 1
2456109.5    35.0        // 2012 7 1
2454832.5    34.0        // 2009 1 1
実施日は午前0時UTCのユリウス日です。

※テーブルの最後は1972年1月1日です。これよりも前はこの計算ではできません。

【UTCからTAIのプログラム】
プログラムではうるう秒の問題に書いた60秒の存在が面倒です。

そこで、テーブル参照は日付のみで行い、その後で時間を加える様にしました。UTCの引数は年月日時分秒と多いので構造体のポインター渡しとします。
#define        DAYSEC        86400.0
#define        DAYMIN        1440.0
#define        DAYHOUR        24.0
/*
-----------------------------------------
        DATE & TIME
-----------------------------------------
*/
typedef struct tag_dt{
    int    nYear;
    int nMonth;
    int nDay;
    int nHour;
    int nMin;
    double dSec;
} DATETIME;

/*
-----------------------------------------
        Reap second
-----------------------------------------
*/
typedef struct tag_reap{
    double dJD;
    double dTime;
} REAPSEC;

/*
-----------------------------------------
        Reap second table
-----------------------------------------
*/
REAPSEC tDAT[] = {
    {2457754.5, 37.0/DAYSEC},    // 2017 1 1
    {2457204.5, 36.0/DAYSEC},    // 2015 7 1
    {2456109.5, 35.0/DAYSEC},    // 2012 7 1
    {2454832.5, 34.0/DAYSEC},    // 2009 1 1
    {2453736.5, 33.0/DAYSEC},    // 2006 1 1
    {-999999.9, 32.0/DAYSEC}
};

/*
=============================================
=                        UTC to TAI                             =
=                                                                    =
= Entry: DATETIME *pUTC = UTC date & time       =
=          double *pdJD_tai = TAI store address        =
=                                                                    =
= exit;    return TAI-UTC sec. unti                        =
=           pdJD_tai in JD_TAI                                =
=============================================
*/
double utc_tai(DATETIME *pUTC, double *pdJD_tai)
{
    double dJD;
    double ddAT;
    double dTimeDay;
    REAPSEC *ptbl;

    /*    make date to julian    & time_day */
    dJD = julian(pUTC->nYear, pUTC->nMonth, (double)pUTC->nDay);
    dTimeDay = pUTC->nHour / DAYHOUR + pUTC->nMin / DAYMIN + pUTC->dSec / DAYSEC;

    /* get delta AT    */
    ptbl = tDAT;
    while( dJD < ptbl->dJD){
        ptbl++;
    }
    ddAT = ptbl->dTime;

    /* add deltaAT */
    *pdJD_tai = dJD + dTimeDay + ddAT;

    return (ddAT * DAYSEC);
}

実は・・・
上のプログラムには、バグがあります。
    while( dJD < ptbl->dJD){
        ptbl++;
    }
このループではテーブルの最後を認識していません。
一応-999999.9 という数字を入れてますが、JDが-999999.9よりもマイナスになる日付だと、無限ループとなり暴走します。正しくは、1972年1月1日以前はエラーにします。


【TAIからUTCのプログラム】
TAIからUTCにも60秒問題があります。60秒は実施日の前1秒間だけであり、それに該当するかの判断が必要です。

色々と考えた結果、UTC 変換後次のうるう秒実施日になるか?という判断にしました。

例えば
2015/07/01 00:00:35TAIをUTCにすると
2015/07/01 00:00:00になり、この日は
次のうるう秒の実施日であるから、
2015/06/30 23:59:60UTCである。

こんな感じで判断します。

TAIからテーブル参照する時は、実施日にを加えた日時で行います。
/*
=============================================
=            TAI to UTC                        =
=============================================
*/
double tai_utc(double dJD_TAI, DATETIME *pUTC)
{
    double dJD;
    double dDay;
    double ddAT;
    REAPSEC *ptbl;
    bool bFlag = false;

    /* get deltaAT    */
    ptbl = tDAT;
    while( dJD_TAI < (ptbl->dJD + ptbl->dTime)){
        ptbl++;
    }
    ddAT = ptbl->dTime;

    /* TAII to UTC */
    dJD = dJD_TAI - ddAT;

    /* check UTC 60s */
    if (ptbl != tDAT){
        ptbl--;
        if (dJD >= ptbl->dJD){
            /* 60s mode */
            dJD -= 1.0 / DAYSEC;
            bFlag = true;
        }
    }

    /*    julian to date */
    juian_date(dJD, &pUTC->nYear, &pUTC->nMonth, &dDay);
    pUTC->nDay = (int)dDay;
    day_time(dDay - pUTC->nDay, &pUTC->nHour, &pUTC->nMin, &pUTC->dSec);

    /* make 60s */
   if (bFlag){
     pUTC->dSec += 1.0;
   }

   return (ddAT * DAYSEC);
}
短いプログラムのくせに、少し解り辛いです。


【TAI⇔UTCのサンプル】
コンソール用アプリです。
atime-sample download
atime.c atime.h astro.h main.c Makefile
が入っています。

gccでは、 makeでコンパイル可能です。
Windowsでは、「Win32コンソールアプリ」で上記のソース(.c, .h)を読み込んでください。

使い方は
atime 2015 6 30 23 59 59.987
の様に年月日時分秒を指定します。
出力は
TAI-UTCの値(秒)
UTC→TAIの時刻
TAI→UTCの時刻
の3行です。

実行結果
2015/7/1のうるう秒挿入付近をやってみます。
$ ./atime 2015 6 30 23 59 59.987
TAI-UTC 34.000000
TAI 2015/07/01 00:00:33.9870
UTC 2015/06/30 23:59:59.9870

$ ./atime 2015 6 30 23 59 60.987
TAI-UTC 34.000000
TAI 2015/07/01 00:00:34.9870
UTC 2015/06/30 23:59:60.9870

$ ./atime 2015 7 1 0 0 0.987
TAI-UTC 35.000000
TAI 2015/07/01 00:00:35.9870
UTC 2015/07/01 00:00:00.9870

$ ./atime 2014 6 30 23 59 60.987
TAI-UTC 34.000000
TAI 2014/07/01 00:00:34.9870
UTC 2014/07/01 00:00:00.9870
2015/06/30 23:59:60.987と60秒が変換できてます。


前に戻る 次は地球時の計算
inserted by FC2 system