Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The <code>getDateFromJulianDay</code> function originally proposed is too computationally intensive for effective use on an embedded device, containing many multiplication and division operations on large <code>long</code> variables or, as originally written in C++, <a href="http://qt.gitorious.org/qt/qt/blobs/4.7/src/corelib/tools/qdatetime.cpp#line140" rel="nofollow noreferrer"><code>longlong</code> variables</a>.</p> <p>I think I hunted down an efficient epoch to date algorithm for an embedded device.</p> <p>After fruitless Googling, I found myself back on Stack Overflow, and found the question <a href="https://stackoverflow.com/questions/1692184/converting-epoch-time-to-real-date-time">Converting epoch time to “real” date/time</a>, asking about self-written epoch time to date implementation and provides a suitable algorithm. This <a href="https://stackoverflow.com/a/1692210/2209295">answer</a> to the question references the <a href="http://www.raspberryginger.com/jbailey/minix/html/gmtime_8c-source.html" rel="nofollow noreferrer">gmtime.c source code</a>, and provided the source in C I needed to write a Python conversion algorithm: </p> <pre><code>/* * 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 &lt;time.h&gt; #include &lt;limits.h&gt; #include "loc_time.h" struct tm * gmtime(register const time_t *timer) { static struct tm br_time; register struct tm *timep = &amp;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-&gt;tm_sec = dayclock % 60; timep-&gt;tm_min = (dayclock % 3600) / 60; timep-&gt;tm_hour = dayclock / 3600; timep-&gt;tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */ while (dayno &gt;= YEARSIZE(year)) { dayno -= YEARSIZE(year); year++; } timep-&gt;tm_year = year - YEAR0; timep-&gt;tm_yday = dayno; timep-&gt;tm_mon = 0; while (dayno &gt;= _ytab[LEAPYEAR(year)][timep-&gt;tm_mon]) { dayno -= _ytab[LEAPYEAR(year)][timep-&gt;tm_mon]; timep-&gt;tm_mon++; } timep-&gt;tm_mday = dayno + 1; timep-&gt;tm_isdst = 0; return timep; } </code></pre> <p>Additionally, the <a href="https://stackoverflow.com/a/3136466/2209295">analysis</a> of the question <a href="https://stackoverflow.com/questions/3136341/why-is-gmtime-implemented-this-way">Why is gmtime implemented this way?</a> helped affirm that the <code>gmtime</code> function is fairly efficient.</p> <p>Using the <a href="http://www.raspberryginger.com/jbailey/minix/html/" rel="nofollow noreferrer">raspberryginger.com minix Doxygen documentation site</a>, I was able to find the C macros and constants that were included in <a href="http://www.raspberryginger.com/jbailey/minix/html/gmtime_8c-source.html" rel="nofollow noreferrer">gmtime.c</a> from <a href="http://www.raspberryginger.com/jbailey/minix/html/loc__time_8h-source.html" rel="nofollow noreferrer">loc_time.h</a>. The relevant code snippet: </p> <pre><code>#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) &amp;&amp; (((year) % 100) || !((year) % 400))) #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) #define FIRSTSUNDAY(timp) (((timp)-&gt;tm_yday - (timp)-&gt;tm_wday + 420) % 7) #define FIRSTDAYOF(timp) (((timp)-&gt;tm_wday - (timp)-&gt;tm_yday + 420) % 7) #define TIME_MAX ULONG_MAX #define ABB_LEN 3 extern const int _ytab[2][10]; </code></pre> <p>And the <code>extern const int _ytab</code> was defined in <a href="http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2misc_8c-source.html#l00082" rel="nofollow noreferrer">misc.c</a>: </p> <pre><code>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 } }; </code></pre> <p>Some other things I found:</p> <ul> <li>The <a href="http://www.raspberryginger.com/jbailey/minix/html/gmtime_8c.html" rel="nofollow noreferrer">gmtime.c File Reference</a> was very helpful for finding dependencies.</li> <li>The <code>gmtime</code> function starts indexing the Month, Day of Week, and Day of Year at the number zero, (maximal ranges of 0-11, 0-6, 0-365, respectively), whereas the Day of Month starts at the number 1, (1-31), see the <a href="http://publib.boulder.ibm.com/infocenter/zvm/v6r1/index.jsp?topic=/com.ibm.zvm.v610.edclv/gmtime.htm" rel="nofollow noreferrer">IBM <code>gmtime()</code> reference</a>.</li> </ul> <hr> <p>I re-wrote the <code>gmtime</code> function for Python 1.5.2+:</p> <pre class="lang-py prettyprint-override"><code>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 &gt;= year_size(year)): dayno = dayno - year_size(year) year = year + 1 month = 1 # NOTE: month range is (1-12) while (dayno &gt;= 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) </code></pre> <p>Modifications I made re-factoring the C++ <code>gmtime</code> function to my Python function <code>ntp_time_to_date(ntp_time)</code>:</p> <ul> <li>Changed epoch from UNIX epoch of 1970 to NTP epoch of 1900 (<a href="http://www.eecis.udel.edu/~mills/y2k.html#era" rel="nofollow noreferrer">the prime epoch for NTP</a>).</li> <li>Slightly streamlined time of day calculation. <ul> <li>Comparing time of day calculation of <code>gmtime</code> to <code>ntp_time_to_date</code>: <ul> <li>Both <code>(dayclock % 3600) / 60</code> and <code>dayclock / 3600</code> occur behind the scenes in <code>divmod(dayclock,3600)</code> and <code>divmod(sec_past_hour,60)</code>.</li> <li>Only real difference is that <code>divmod(sec_past_hour,60)</code> avoids modulo of <code>dayclock</code> (0-86399) by 60 via <code>dayclock % 60</code>, and instead does modulo of <code>sec_past_hour</code> (0-3599) by 60 within <code>divmod(sec_past_hour,60)</code>.</li> </ul></li> </ul></li> <li>Removed variables and code I did not need, for example, day of week.</li> <li>Changed indexing of Month to start at 1, so Month range is (1-12) instead of (0-11)</li> <li>Type cast variables away from <code>long</code> as soon as values were less than 65535 to greatly decrease code execution time. <ul> <li>The requires long variables are: <ul> <li><code>ntp_time</code>, seconds since 1900 (0-4294967295)</li> <li><code>dayclock</code>, seconds into day (0-86399)</li> </ul></li> <li>The largest of the rest of the variables is the calculated year within the date.</li> </ul></li> </ul> <hr> <p>The Python <code>ntp_time_to_date</code> function (with its dependencies) runs successfully on the Telit GC-864 on an embedded version of Python 1.5.2+, as well as on Python 2.7.3, but of course use the datetime library if you can.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload