Annotation of embedaddon/ntp/libntp/caljulian.c, revision 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>