2013-03-26 17 views
5

我想知道從紀元時間(自NTP時代1900-01-01 00:00)轉換爲日期時間字符串(MM/DD/YY ,hh:mm:ss)沒有任何庫/模塊/外部函數,因爲它們在嵌入式設備上不可用。Epoch在有限嵌入式設備上進行秒轉換

我的第一個想法是看Python datetime module source code,但是這對我來說並不是很有用。

我在Python中的初始嘗試使用自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 1.5.2+並且只有泰利特GC-864蜂窩式調制解調器具有有限的運營商(大多隻是C運算符),沒有模塊,和一些預期的內置的Python類型。如果您有興趣,確切的功能是here。我爲這個設備編寫Python,好像我正在編寫C代碼 - 我知道不是Pythonic。
  • 我意識到NTP最好只用於時間偏移,但是有限的選擇,我使用NTP作爲絕對時間源(我可以在2036年添加NTP翻轉檢查以啓用另一個136年的操作) 。
  • 具有最新固件的GC-864-V2設備具有NTP功能,但我需要使用的GC-864卡住了以前的固件版本。
+0

你爲什麼在1582年之前打擾日期呢? – 2013-03-26 00:48:49

+0

是的,沒有必要 - 被包含在原始代碼中,忘記包含getDateFromJulianDay函數的C++源代碼,[line 132 here](http://qt.gitorious.org/qt/qt/blobs/4.7/src/ corelib的/工具/ qdatetime.cpp#line132)。 – swolpert 2013-03-26 00:59:02

+0

然後將其從您的發佈代碼中刪除,並讓您的問題更清晰。 – dkamins 2013-03-26 21:38:21

回答

0

TL; DR

如果使用一個泰利特GC-864,Python解釋看似插入某種執行代碼的每一行之間的延遲的。

對於泰利特GC-864,在我的問題getDateFromJulianDay(julianDay)功能比我的回答,ntp_time_to_date(ntp_time)功能更快。

更多詳細

代碼數占主導地位的執行時間在GC-864比代碼的複雜性 - 奇怪,我知道了。在我的問題中功能getDateFromJulianDay(julianDay)有一些複雜的操作,可能是15行代碼。在我的答案ntp_time_to_date(ntp_time)的功能有更簡單的計算複雜度,但while循環造成超過100行代碼執行的:從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變量到int具有相當顯着的效果。如果沒有這種優化:

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

做任何計算涉及上在Python 1.5.2+中運行.pyo文件的Telit GC-864這不是一個好主意。使用具有內置NTP功能的GC-864-V2可以解決遇到此問題的人員。而且,更新的機器對機器(M2M)又名物聯網(IoT)手機調制解調器更有能力。

如果您在GC-864,有類似問題,請考慮使用更新,更現代的手機調制解調器

6

最初提出的getDateFromJulianDay功能是用於嵌入式設備上或有效的利用,在大long變量包含許多乘法和除法運算,如最初用C++編寫,longlong variables計算量太大。

我想我爲嵌入式設備尋找了一個有效的新紀元算法。

在沒有結果的谷歌搜索後,我發現自己回到堆棧溢出,並發現問題Converting epoch time to 「real」 date/time,詢問有關自編寫時代的最新實現,並提供了一個合適的算法。這answer的問題引用gmtime.c source code,並提供了用C我需要寫一個Python轉換算法來源:

/* 
* 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?analysis幫助確認該gmtime功能是相當有效的。

使用raspberryginger.com minix Doxygen documentation site,我能夠從loc_time.h找到包含在gmtime.c中的C宏和常量。相關的代碼片段:

#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的1.5.2+的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) 

修改我做了重新融通C++ gmtime功能,我的Python功能ntp_time_to_date(ntp_time)

  • 從1970年的UNIX時代改爲1900年的NTP時代(the prime epoch for NTP)。
  • 稍微簡化時間計算。
    • 比較gmtime天計算的時間ntp_time_to_date
      • 兩個(dayclock % 3600)/60dayclock/3600發生在divmod(dayclock,3600)divmod(sec_past_hour,60)幕後。
      • 只有真正的區別在於divmod(sec_past_hour,60)經由dayclock % 60避免了dayclock(0-86399)由60取模,並通過60代替確實內divmod(sec_past_hour,60)sec_past_hour(0-3599)模。
  • 刪除變量和代碼,我並不需要,例如,一週中的一天。
  • 月的更改索引儘快值分別爲從1開始,所以月範圍是(1-12)代替(0-11)
  • 型鑄造變量從long遠小於65535,大大減少執行代碼時間。
    • 將需要較長的變量是:
      • ntp_time,秒自1900年以來(0-4294967295)
      • dayclock,秒到天(0-86399)
    • 最大,其餘的的變量是日期內計算的年份。

Python的ntp_time_to_date功能(其依賴)成功地運行在泰利特GC-864的Python 1.5.2+的嵌入式版本,以及關於Python 2.7.3,但如果可以的話,當然可以使用日期時間庫。

+0

當我的平臺非常有限以至於第一個函數太慢時,python必須是您使用的語言,這對我來說很瘋狂。我敢打賭,在現實世界中沒有任何事會發生,但我想我會錯的! – cwa 2013-03-28 23:56:40

+0

您是否在意閏秒(誤差小於40秒,它在1972年之前是恆定的,並且只有在您將時間與實時UTC時間同步的實際物理時鐘(或GPS時間)進行比較時纔可見) ? http://www.eecis.udel.edu/~mills/leap.html – jfs 2013-06-03 13:51:24

+0

@sebastian:我不在乎閏秒在這一點上,但這是很好的知道。我還沒有看到任何偏移量與單獨的Linux(Ubuntu)盒子的NTP同步時間。 Linux NTP時間同步是否佔用閏秒? – swolpert 2013-06-03 21:01:12

相關問題