Annotation of embedaddon/ntp/libntp/caljulian.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * caljulian - determine the Julian date from an NTP time.
                      3:  */
                      4: #include <sys/types.h>
                      5: 
                      6: #include "ntp_types.h"
                      7: #include "ntp_calendar.h"
                      8: #include "ntp_stdlib.h"
                      9: #include "ntp_fp.h"
                     10: #include "ntp_unixtime.h"
                     11: 
                     12: #if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
                     13:       defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
                     14:       defined(ISC_CHECK_INVARIANT))
                     15: # define ISC_CHECK_ALL
                     16: #endif
                     17: 
                     18: #include "ntp_assert.h"
                     19: 
                     20: #if 1
                     21: 
                     22: /* Updated 2008-11-10 Juergen Perlinger <juergen.perlinger@t-online.de>
                     23:  *
                     24:  * Make the conversion 2038-proof with proper NTP epoch unfolding and extended
                     25:  * precision calculations. Though we should really get a 'time_t' with more
                     26:  * than 32 bits at least until 2037, because the unfolding cannot work after
                     27:  * the wrap of the 32-bit 'time_t'.
                     28:  */
                     29: 
                     30: void
                     31: caljulian(
                     32:        u_long                          ntptime,
                     33:        register struct calendar        *jt
                     34:        )
                     35: {
                     36:        u_long  saved_time = ntptime;
                     37:        u_long  ntp_day; /* days (since christian era or in year) */ 
                     38:        u_long  n400;    /* # of Gregorian cycles */
                     39:        u_long  n100;    /* # of normal centuries */
                     40:        u_long  n4;      /* # of 4-year cycles */
                     41:        u_long  n1;      /* # of years into a leap year cycle */
                     42:        u_long  sclday;  /* scaled days for month conversion */
                     43:        int     leaps;   /* # of leaps days in year */
                     44:        time_t  now;     /* current system time */
                     45:        u_int32 tmplo;   /* double precision tmp value / lo part */
                     46:        int32   tmphi;   /* double precision tmp value / hi part */
                     47: 
                     48:        NTP_INSIST(NULL != jt);
                     49: 
                     50:        /*
                     51:         * First we have to unfold the ntp time stamp around the current time
                     52:         * to make sure we are in the right epoch. Also we we do *NOT* fold
                     53:         * before the begin of the first NTP epoch, so we WILL have a
                     54:         * non-negative time stamp afterwards. Though at the time of this
                     55:         * writing (2008 A.D.) it would be really strange to have systems
                     56:         * running with clock set to he 1960's or before...
                     57:         *
                     58:         * But's important to use a 32 bit max signed value -- LONG_MAX is 64
                     59:         * bit on a 64-bit system, and it will give wrong results.
                     60:         */
                     61:        now   = time(NULL);
                     62:        tmplo = (u_int32)now;
                     63: #if ( SIZEOF_TIME_T > 4 )
                     64:        tmphi = (int32)(now >> 16 >> 16);
                     65: #else
                     66:        /*
                     67:         * Get the correct sign extension in the high part. 
                     68:         * (now >> 32) may not work correctly on every 32 bit 
                     69:         * system, e.g. it yields garbage under Win32/VC6.
                     70:         */
                     71:     tmphi = (int32)(now >> 31);
                     72: #endif
                     73:        
                     74:        M_ADD(tmphi, tmplo, 0, ((1UL << 31)-1)); /* 32-bit max signed */
                     75:        M_ADD(tmphi, tmplo, 0, JAN_1970);
                     76:        if ((ntptime > tmplo) && (tmphi > 0))
                     77:                --tmphi;
                     78:        tmplo = ntptime;
                     79:        
                     80:        /*
                     81:         * Now split into days and seconds-of-day, using the fact that
                     82:         * SECSPERDAY (86400) == 675 * 128; we can get roughly 17000 years of
                     83:         * time scale, using only 32-bit calculations. Some magic numbers here,
                     84:         * sorry for that. (This could be streamlined for 64 bit machines, but
                     85:         * is worth the trouble?)
                     86:         */
                     87:        ntptime  = tmplo & 127; /* save remainder bits */
                     88:        tmplo    = (tmplo >> 7) | (tmphi << 25);
                     89:        ntp_day  =  (u_int32)tmplo / 675;
                     90:        ntptime += ((u_int32)tmplo % 675) << 7;
                     91: 
                     92:        /* some checks for the algorithm 
                     93:         * There's some 64-bit trouble out there: the original NTP time stamp
                     94:         * had only 32 bits, so our calculation invariant only holds in 32 bits!
                     95:         */
                     96:        NTP_ENSURE(ntptime < SECSPERDAY);
                     97:        NTP_INVARIANT((u_int32)(ntptime + ntp_day * SECSPERDAY) == (u_int32)saved_time);
                     98: 
                     99:        /*
                    100:         * Do the easy stuff first: take care of hh:mm:ss, ignoring leap
                    101:         * seconds
                    102:         */
                    103:        jt->second = (u_char)(ntptime % SECSPERMIN);
                    104:        ntptime   /= SECSPERMIN;
                    105:        jt->minute = (u_char)(ntptime % MINSPERHR);
                    106:        ntptime   /= MINSPERHR;
                    107:        jt->hour   = (u_char)(ntptime);
                    108: 
                    109:        /* check time invariants */
                    110:        NTP_ENSURE(jt->second < SECSPERMIN);
                    111:        NTP_ENSURE(jt->minute < MINSPERHR);
                    112:        NTP_ENSURE(jt->hour   < HRSPERDAY);
                    113: 
                    114:        /*
                    115:         * Find the day past 1900/01/01 00:00 UTC
                    116:         */
                    117:        ntp_day += DAY_NTP_STARTS - 1;  /* convert to days in CE */
                    118:        n400     = ntp_day / GREGORIAN_CYCLE_DAYS; /* split off cycles */
                    119:        ntp_day %= GREGORIAN_CYCLE_DAYS;
                    120:        n100     = ntp_day / GREGORIAN_NORMAL_CENTURY_DAYS;
                    121:        ntp_day %= GREGORIAN_NORMAL_CENTURY_DAYS;
                    122:        n4       = ntp_day / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
                    123:        ntp_day %= GREGORIAN_NORMAL_LEAP_CYCLE_DAYS;
                    124:        n1       = ntp_day / DAYSPERYEAR;
                    125:        ntp_day %= DAYSPERYEAR; /* now zero-based day-of-year */
                    126: 
                    127:        NTP_ENSURE(ntp_day < 366);
                    128: 
                    129:        /*
                    130:         * Calculate the year and day-of-year
                    131:         */
                    132:        jt->year = (u_short)(400*n400 + 100*n100 + 4*n4 + n1);
                    133: 
                    134:        if ((n100 | n1) > 3) {
                    135:                /*
                    136:                 * If the cycle year ever comes out to 4, it must be December
                    137:                 * 31st of a leap year.
                    138:                 */
                    139:                jt->month    = 12;
                    140:                jt->monthday = 31;
                    141:                jt->yearday  = 366;
                    142:        } else {
                    143:                /*
                    144:                 * The following code is according to the excellent book
                    145:                 * 'Calendrical Calculations' by Nachum Dershowitz and Edward
                    146:                 * Reingold. It converts the day-of-year into month and
                    147:                 * day-of-month, using a linear transformation with integer
                    148:                 * truncation. Magic numbers again, but they will not be used
                    149:                 * anywhere else.
                    150:                 */
                    151:                sclday = ntp_day * 7 + 217;
                    152:                leaps  = ((n1 == 3) && ((n4 != 24) || (n100 == 3))) ? 1 : 0;
                    153:                if (ntp_day >= (u_long)(JAN + FEB + leaps))
                    154:                        sclday += (2 - leaps) * 7;
                    155:                ++jt->year;
                    156:                jt->month    = (u_char)(sclday / 214);
                    157:                jt->monthday = (u_char)((sclday % 214) / 7 + 1);
                    158:                jt->yearday  = (u_short)(1 + ntp_day);
                    159:        }
                    160: 
                    161:        /* check date invariants */
                    162:        NTP_ENSURE(1 <= jt->month    && jt->month    <=  12); 
                    163:        NTP_ENSURE(1 <= jt->monthday && jt->monthday <=  31);
                    164:        NTP_ENSURE(1 <= jt->yearday  && jt->yearday  <= 366);
                    165: }
                    166: 
                    167: #else
                    168: 
                    169: /* Updated 2003-12-30 TMa
                    170: 
                    171:    Uses common code with the *prettydate functions to convert an ntp
                    172:    seconds count into a calendar date.
                    173:    Will handle ntp epoch wraparound as long as the underlying os/library 
                    174:    does so for the unix epoch, i.e. works after 2038.
                    175: */
                    176: 
                    177: void
                    178: caljulian(
                    179:        u_long                          ntptime,
                    180:        register struct calendar        *jt
                    181:        )
                    182: {
                    183:        struct tm *tm;
                    184:        NTP_REQUIRE(jt != NULL);
                    185: 
                    186:        tm = ntp2unix_tm(ntptime, 0);
                    187:        NTP_INSIST(tm != NULL);
                    188: 
                    189:        jt->hour = (u_char) tm->tm_hour;
                    190:        jt->minute = (u_char) tm->tm_min;
                    191:        jt->month = (u_char) (tm->tm_mon + 1);
                    192:        jt->monthday = (u_char) tm->tm_mday;
                    193:        jt->second = (u_char) tm->tm_sec;
                    194:        jt->year = (u_short) (tm->tm_year + 1900);
                    195:        jt->yearday = (u_short) (tm->tm_yday + 1);  /* Assumes tm_yday starts with day 0! */
                    196: }
                    197: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>