2013-03-26 11 views
5

エポック秒(NTPエポック1900-01-01 00:00以降)からdatetime文字列(MM/DD/YY)に変換する最善の方法を理解しようとしています。 、hh:mm:ss)にはライブラリ/モジュール/外部関数はありません。制限付き組み込みデバイスでのエポック秒から日付変換

私の最初の考えはPython datetime module source codeを見ることでしたが、それは私にはあまり役に立ちませんでした。

私の最初の試みでは、0001-01-01からgetDateFromJulianDayをPythonに合わせてC++ sourceに変換し、モジュロ演算を組み合わせて時間を取得しています。それは動作しますが、より良い方法がありますか?

def getDateFromJulianDay(julianDay): 
    # Gregorian calendar starting from October 15, 1582 
    # This algorithm is from: 
    # Henry F. Fliegel and Thomas C. van Flandern. 1968. 
    # Letters to the editor: 
    #  a machine algorithm for processing calendar dates. 
    # Commun. ACM 11, 10 (October 1968), 657-. DOI=10.1145/364096.364097 
    # http://doi.acm.org/10.1145/364096.364097 
    ell = julianDay + 68569; 
    n = (4 * ell)/146097; 
    ell = ell - (146097 * n + 3)/4; 
    i = (4000 * (ell + 1))/1461001; 
    ell = ell - (1461 * i)/4 + 31; 
    j = (80 * ell)/2447; 
    d = ell - (2447 * j)/80; 
    ell = j/11; 
    m = j + 2 - (12 * ell); 
    y = 100 * (n - 49) + i + ell; 
    return y,m,d 

# NTP response (integer portion) for Monday, March 25, 2013 at 6:40:43 PM 
sec_since_1900 = 3573225643 

# 2415021 is the number of days between 0001-01-01 and 1900-01-01, 
#  the start of the NTP epoch 
(year,month,day) = getDateFromJulianDay(2415021 + sec_since_1900/60/60/24) 

seconds_into_day = sec_since_1900 % 86400 
(hour, sec_past_hour) = divmod(seconds_into_day,3600) 
(min, sec) = divmod(sec_past_hour,60) 
print 'year:',year,'month:',month,'day:',day 
print 'hour:',hour,'min:',min,'sec:',sec 

なぜ私はこれをやっている: 私はNTPサーバから現在の時刻を取得し、日付のみを受け付け、ハードウェアリアルタイムクロック(RTC)を更新するための額面で、この時間を割いています、時間と時間帯:MM/DD/YY、hh:mm:ss、±zz。私は後で真のNTP機能を実装する予定です。時間同期方法については、this questionのように他の場所に残しておくのが最も良い方法です。

  • マイ埋め込みデバイスは、Pythonを実行TelitのGC-864セルラーモデムである1.5.2+のみオペレータ(大部分だけC演算子)、無モジュール、および予想の一部を制限しています組み込みのPython型。あなたが興味を持っているのなら、正確な能力はhereです。あたかも私がCコードを書いているかのように、私はこのデバイス用にPythonを書いています。
  • 私はNTPがタイムオフセットのためだけに使用されるのが最も良いと認識していますが、オプションが限られているため、絶対時間ソースとしてNTPを使用しています(さらに、N36ロールオーバーをチェックして、 。
  • 最新のファームウェアを搭載したGC-864-V2デバイスにはNTP機能がありますが、使用する必要のあるGC-864は、以前のファームウェアでスタックされています。元々提案
+0

1582年以前の日付を扱うのはどうですか? –

+0

元のコードに含まれていましたが、getDateFromJulianDay関数のC++ソースを含めていませんでした。[ここでは132行目です](http://qt.gitorious.org/qt/qt/blobs/4.7/src/ corelib/tools/qdatetime.cpp#line132)。 – swolpert

+0

それから、あなたの投稿されたコードから削除し、あなたの質問を明確にしてください。 – dkamins

答えて

0

; DR

あなたはTelitのGC-864を使用している場合は、Pythonのインタープリタは、一見コード実行の各ライン間における遅延のいくつかの並べ替えを挿入します。

Telit GC-864の場合、私の質問getDateFromJulianDay(julianDay)の機能は、私の答えの機能であるntp_time_to_date(ntp_time)よりも高速です。

詳細

ラインコードの数は、コードの複雑さよりGC-864より上の実行時間を支配 - 奇妙な、私は知っています。私の質問にある関数getDateFromJulianDay(julianDay)には、わずか15行の複雑な操作があります。私の答えntp_time_to_date(ntp_time)内の関数は、単純な計算の複雑さを持っていますが、whileループは、コード実行の100+行原因:現在に現在の年に月1から

  • 別のループ回数を1900年から

    • 1つのループ回数を月

    テスト

    タイミング・テストの結果は、実際のGC-864(注:ない GC-864-V2)上で実行されている結果と同じを使用して各試行のNTP時間入力(各機能は "3/25/2013 18:40"を出力します)。タイミングはprintf文のデバッグを使用して実行され、コンピュータのシリアル端末はGC-864によって送信された各行にタイムスタンプを設定します。

    getDateFromJulianDay(julianDay)試験:

    • 0.3802秒
    • 0.3370秒
    • 0.3370秒
    • 平均:0.3514秒

    ntp_time_to_date(ntp_time)試験:

    • 0.8899秒
    • 0.9072秒
    • 0.8986秒
    • 平均:0.8986秒

    変動は、部分的に、定期的に携帯電話ネットワークのタスクにサービスを提供GC-864細胞モデムに由来します。

    ntp_time_to_date(ntp_time)で可能な限り速くに変数longの型キャストを最適化するとかなりの効果があります。この最適化がなけれ:

    • 2.3155秒
    • 1.5034秒
    • 1.5293秒
    • 2.0995秒
    • 2.0909秒
    • 平均:1.9255秒

    は何も、計算上の関与を行いますPython 1.5.2以降で.pyoファイルを実行するTelit GC-864素晴らしいアイディアではありません。 GC-864-V2はNTP機能を内蔵していますので、この問題を抱える人にとっては可能です。さらに、より新しいマシンツーマシン(M2M)、すなわち物事(IoT)の携帯電話モデムは、はるかに優れています。

    GC-864で同様の問題が発生した場合は、より新しい最新の携帯電話モデムを使用することを検討してください。

  • 6

    getDateFromJulianDay関数は元々C++、longlong variablesで書かれたような大きなlong変数または、上に多くの乗算と除算演算を含む、埋め込みデバイス上の効果的な使用のためにあまりにも計算集約的です。

    私は、組み込みデバイスの効率的なエポックからアルゴリズムまでを探し回ったと思います。

    無駄なグーグルの後、私は自分自身をStack Overflowに戻し、Converting epoch time to “real” date/timeという質問を見つけ、独自のエポックタイムトゥーデートの実装について質問し、適切なアルゴリズムを提供しました。質問へのこのanswergmtime.c source codeを参照し、私はPythonの変換アルゴリズムを記述するために必要なCソースを提供:

    /* 
    * gmtime - convert the calendar time into broken down time 
    */ 
    /* $Header: /opt/proj/minix/cvsroot/src/lib/ansi/gmtime.c,v 1.1.1.1 2005/04/21 14:56:05 beng Exp $ */ 
    
    #include  <time.h> 
    #include  <limits.h> 
    #include  "loc_time.h" 
    
    struct tm * 
    gmtime(register const time_t *timer) 
    { 
         static struct tm br_time; 
         register struct tm *timep = &br_time; 
         time_t time = *timer; 
         register unsigned long dayclock, dayno; 
         int year = EPOCH_YR; 
    
         dayclock = (unsigned long)time % SECS_DAY; 
         dayno = (unsigned long)time/SECS_DAY; 
    
         timep->tm_sec = dayclock % 60; 
         timep->tm_min = (dayclock % 3600)/60; 
         timep->tm_hour = dayclock/3600; 
         timep->tm_wday = (dayno + 4) % 7;  /* day 0 was a thursday */ 
         while (dayno >= YEARSIZE(year)) { 
           dayno -= YEARSIZE(year); 
           year++; 
         } 
         timep->tm_year = year - YEAR0; 
         timep->tm_yday = dayno; 
         timep->tm_mon = 0; 
         while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) { 
           dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon]; 
           timep->tm_mon++; 
         } 
         timep->tm_mday = dayno + 1; 
         timep->tm_isdst = 0; 
    
         return timep; 
    } 
    

    また、質問Why is gmtime implemented this way?analysisgmtime機能はかなり効率的であることを断言し役立ちました。

    raspberryginger.com minix Doxygen documentation siteを使用して、gmtime.cに含まれていたCマクロと定数がloc_time.hから見つかりました。関連するコードスニペット:

    #define YEAR0   1900     /* the first year */ 
    #define EPOCH_YR  1970   /* EPOCH = Jan 1 1970 00:00:00 */ 
    #define SECS_DAY  (24L * 60L * 60L) 
    #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) 
    #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) 
    #define FIRSTSUNDAY(timp)  (((timp)->tm_yday - (timp)->tm_wday + 420) % 7) 
    #define FIRSTDAYOF(timp)  (((timp)->tm_wday - (timp)->tm_yday + 420) % 7) 
    #define TIME_MAX  ULONG_MAX 
    #define ABB_LEN   3 
    
    extern const int _ytab[2][10]; 
    

    そしてextern const int _ytabmisc.cで定義されていた。

    const int _ytab[2][12] = { 
           { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
           { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 
         }; 
    

    私が見つけたいくつかの他の事:

    • gmtime.c File Referenceは、依存関係を見つけるために非常に役に立ちました。
    • gmtime関数は、月、曜日、および曜日のインデックス番号をゼロから開始します(最大範囲はそれぞれ0-11,0-6,0-365)。番号1(1-31)は、IBM gmtime() referenceを参照してください。

        :私は私のPythonの関数 ntp_time_to_date(ntp_time)にC++ gmtime機能を再ファクタリング製

        def is_leap_year(year): 
            return (not ((year) % 4) and (((year) % 100) or (not((year) % 400)))) 
        
        def year_size(year): 
            if is_leap_year(year): 
             return 366 
            else: 
             return 365 
        
        def ntp_time_to_date(ntp_time): 
            year = 1900   # EPOCH_YR for NTP 
            ytab = [ [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], 
               [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] ] 
        
            (dayno,dayclock) = divmod(ntp_time, 86400L) 
            dayno = int(dayno) 
        
            # Calculate time of day from seconds on the day's clock. 
            (hour, sec_past_hour) = divmod(dayclock,3600) 
            hour = int(hour) 
            (min, sec) = divmod(int(sec_past_hour),60) 
        
            while (dayno >= year_size(year)): 
             dayno = dayno - year_size(year) 
             year = year + 1 
            month = 1       # NOTE: month range is (1-12) 
            while (dayno >= ytab[is_leap_year(year)][month]): 
             dayno = dayno - ytab[is_leap_year(year)][month] 
             month = month + 1 
            day = dayno + 1 
        
            return (year, month, day, hour, min, sec) 
        

        変更:Pythonの1.5.2+のため、私は再び書いたgmtime機能


    • 1970年のUNIXエポックから1900年のNTPエポックに変更されたエポック(the prime epoch for NTP)。
    • 時間計算をやや簡素化しました。 ntp_time_to_dategmtimeの日計算の時間を比較すると、
        • 両方(dayclock % 3600)/60dayclock/3600divmod(dayclock,3600)divmod(sec_past_hour,60)に舞台裏で起こります。
        • のみ実質的な違いは、divmod(sec_past_hour,60)dayclock % 60介して60によってdayclock(0から86399)のモジュロを回避し、その代わりにdivmod(sec_past_hour,60)内60によってsec_past_hour(0から3599)のモジュロを行うことです。
    • 私は、例えば、曜日を必要としなかった変数やコードを削除しました。月の範囲は、すぐに値が大きくコードの実行を減少させる未満65535であったとして離れるlongから(1-12)の代わりに(0-11)
    • 型キャスト変数であるので、1から開始する月の
    • 変更インデキシング時間。
      • ザ・が長い変数である必要があります。1900年(0〜4294967295)
      • dayclock以来
        • ntp_time、秒、日中の秒(0から86399)
      • 残りの最大変数のうち、日付の中で計算された年です。(その依存関係)

    ザパイソンntp_time_to_date機能は、Python 1.5.2+の埋め込まれたバージョンに、同様のPython 2.7.3にTelitのGC-864上で正常に実行され、しかし可能であれば、もちろんdatetimeライブラリを使用してください。 TL

    +0

    プラットフォームが非常に限られているために、最初の関数が遅すぎると、Pythonがあなたが使用する言語でなければならないことは私には狂っています。私は現実世界で起こるようなことは何もないとお金を賭けていただろうが、私は間違っていただろうと思う! – cwa

    +0

    あなたはうるう秒に気をつけますか(誤差は40秒未満です。これは1972年以前は一定ですが、現時点ではUTCスケールで同期化された実際の物理時計(またはGPS時刻)と時刻を比較する場合にのみ表示されます) ? http://www.eecis.udel.edu/~mills/leap.html – jfs

    +0

    @sebastian:私はこの時点でうるう秒については気にしませんが、それは確かに知っていることです。私は別のLinux(Ubuntu)ボックスのNTP同期時間に対してオフセットを見たことがありません。 LinuxのNTP時間同期は閏秒を考慮していますか? – swolpert

    関連する問題