2013-03-26 44 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

相关问题