1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
/*
* prettydate - convert a time stamp to something readable
*/
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h" /* includes <sys/time.h> */
#include "lib_strbuf.h"
#include "ntp_stdlib.h"
#include "ntp_assert.h"
static char *common_prettydate(l_fp *, int);
const char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const char *days[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
/* Helper function to handle possible wraparound of the ntp epoch.
Works by periodic extension of the ntp time stamp in the NTP epoch. If the
'time_t' is 32 bit, use solar cycle warping to get the value in a suitable
range. Also uses solar cycle warping to work around really buggy
implementations of 'gmtime()' / 'localtime()' that cannot work with a
negative time value, that is, times before 1970-01-01. (MSVCRT...)
Apart from that we're assuming that the localtime/gmtime library functions
have been updated so that they work...
*/
/* solar cycle in secs, unsigned secs and years. And the cycle limits.
**
** And an explanation. The julian calendar repeats ever 28 years, because it's
** the LCM of 7 and 4, the week and leap year cycles. This is called a 'solar
** cycle'. The gregorian calendar does the same as long as no centennial year
** (divisible by 100, but not 400) goes in the way. So between 1901 and 2099
** (inclusive) we can warp time stamps by 28 years to make them suitable for
** localtime() and gmtime() if we have trouble. Of course this will play
** hubbubb with the DST zone switches, so we should do it only if necessary;
** but as we NEED a proper conversion to dates via gmtime() we should try to
** cope with as many idiosyncrasies as possible.
*/
#define SOLAR_CYCLE_SECS 0x34AADC80UL /* 7*1461*86400*/
#define SOLAR_CYCLE_YEARS 28
#define MINFOLD -3
#define MAXFOLD 3
struct tm *
ntp2unix_tm(
u_long ntp, int local
)
{
struct tm *tm;
int32 folds = 0;
time_t t = time(NULL);
u_int32 dwlo = (int32)t; /* might expand for SIZEOF_TIME_T < 4 */
#if ( SIZEOF_TIME_T > 4 )
int32 dwhi = (int32)(t >> 16 >> 16);/* double shift: avoid warnings */
#else
/*
* Get the correct sign extension in the high part.
* (now >> 32) may not work correctly on every 32 bit
* system, e.g. it yields garbage under Win32/VC6.
*/
int32 dwhi = (int32)(t >> 31);
#endif
/* Shift NTP to UN*X epoch, then unfold around currrent time. It's
* important to use a 32 bit max signed value -- LONG_MAX is 64 bit on
* a 64-bit system, and it will give wrong results.
*/
M_ADD(dwhi, dwlo, 0, ((1UL << 31)-1)); /* 32-bit max signed */
if ((ntp -= JAN_1970) > dwlo)
--dwhi;
dwlo = ntp;
# if SIZEOF_TIME_T < 4
# error sizeof(time_t) < 4 -- this will not work!
# elif SIZEOF_TIME_T == 4
/*
** If the result will not fit into a 'time_t' we have to warp solar
** cycles. That's implemented by looped addition / subtraction with
** M_ADD and M_SUB to avoid implicit 64 bit operations, especially
** division. As he number of warps is rather limited there's no big
** performance loss here.
**
** note: unless the high word doesn't match the sign-extended low word,
** the combination will not fit into time_t. That's what we use for
** loop control here...
*/
while (dwhi != ((int32)dwlo >> 31)) {
if (dwhi < 0 && --folds >= MINFOLD)
M_ADD(dwhi, dwlo, 0, SOLAR_CYCLE_SECS);
else if (dwhi >= 0 && ++folds <= MAXFOLD)
M_SUB(dwhi, dwlo, 0, SOLAR_CYCLE_SECS);
else
return NULL;
}
# else
/* everything fine -- no reduction needed for the next thousand years */
# endif
/* combine hi/lo to make time stamp */
t = ((time_t)dwhi << 16 << 16) | dwlo; /* double shift: avoid warnings */
# ifdef _MSC_VER /* make this an autoconf option? */
/*
** The MSDN says that the (Microsoft) Windoze versions of 'gmtime()'
** and 'localtime()' will bark on time stamps < 0. Better to fix it
** immediately.
*/
while (t < 0) {
if (--folds < MINFOLD)
return NULL;
t += SOLAR_CYCLE_SECS;
}
# endif /* Microsoft specific */
/* 't' should be a suitable value by now. Just go ahead. */
while ( (tm = (*(local ? localtime : gmtime))(&t)) == 0)
/* seems there are some other pathological implementations of
** 'gmtime()' and 'localtime()' somewhere out there. No matter
** if we have 32-bit or 64-bit 'time_t', try to fix this by
** solar cycle warping again...
*/
if (t < 0) {
if (--folds < MINFOLD)
return NULL;
t += SOLAR_CYCLE_SECS;
} else {
if ((++folds > MAXFOLD) || ((t -= SOLAR_CYCLE_SECS) < 0))
return NULL; /* That's truely pathological! */
}
/* 'tm' surely not NULL here... */
NTP_INSIST(tm != NULL);
if (folds != 0) {
tm->tm_year += folds * SOLAR_CYCLE_YEARS;
if (tm->tm_year <= 0 || tm->tm_year >= 200)
return NULL; /* left warp range... can't help here! */
}
return tm;
}
static char *
common_prettydate(
l_fp *ts,
int local
)
{
char *bp;
struct tm *tm;
u_long sec;
u_long msec;
LIB_GETBUF(bp);
sec = ts->l_ui;
msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */
tm = ntp2unix_tm(sec, local);
if (!tm)
snprintf(bp, LIB_BUFLENGTH,
"%08lx.%08lx --- --- -- ---- --:--:--",
(u_long)ts->l_ui, (u_long)ts->l_uf);
else
snprintf(bp, LIB_BUFLENGTH,
"%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03lu",
(u_long)ts->l_ui, (u_long)ts->l_uf,
days[tm->tm_wday], months[tm->tm_mon],
tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour,
tm->tm_min, tm->tm_sec, msec);
return bp;
}
char *
prettydate(
l_fp *ts
)
{
return common_prettydate(ts, 1);
}
char *
gmprettydate(
l_fp *ts
)
{
return common_prettydate(ts, 0);
}
|