/******************************************************************************* * c0xlongtime.c * Test implementation for the ISO C proposal at: * , Revision 2.0. * * This code is designed to run reasonably well on Unix and Win32 systems. * * Notes * Compile with macro '_unix' defined for Unix systems. * Compile with macro '_POSIX' defined for POSIX systems. * * Compile with macro 'TEST' defined to a non-zero value if you want a * test driver 'main()' function compiled into the object code. * * Author * This code was written by David R. Tribble (david@tribble.com), Jul 2004 * thru Mar 2006. * It is hereby placed into the public domain, and may be used for all * purposes, both commercial and private. No warranty is provided for this * source code, and the author cannot be held liable for its use in any * way. * * See also * * * * * NTP v.3 * SNTP v.4 * * * * * * * * * * Since * 2004-07-10 */ /* Identification */ #define c0x_longtime_c 211 static const char REV[] = "@(#)drt/text/stdc/c0xlongtime.c $Revision: 1.11 $ $Date: 2006/07/08 19:29:58 $"; /* System includes */ #include #define _stdc_iso646_h 1 #include #define _stdc_limits_h 1 #include #define _stdc_stdbool_h 1 #include #define _stdc_stddef_h 1 #include #define _stdc_stdio_h 1 #include #define _stdc_string_h 1 #include #define _stdc_time_h 1 #if TEST #include #define _stdc_ctype_h 1 #include #define _stdc_stdlib_h 1 #endif /* System-specific includes */ #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN 1 #include #define _sys_windows_h 1 #elif defined(_unix) #include #define _sys_time_h 1 #else #error Undefined O/S #endif #if defined(_WIN32) && _MSC_VER < 1300 /* For older versions of MS C */ #define LLONG_FMT "I64d" #define ULLONG_FMT "I64u" #define XLLONG_FMT "I64X" #else #define LLONG_FMT "lld" #define ULLONG_FMT "llu" #define XLLONG_FMT "llX" #endif /* Local includes */ /*#include "c0xcalendar.h"*/ #include "c0xtimezone.h" #include "c0xlongtime.h" /******************************************************************************* * Local types *******************************************************************************/ typedef c0x_llong_t llong_t; /******************************************************************************* * Local constants *******************************************************************************/ #define SECS_PER_DAY (24*60*60) /* 24 hours of 60*60 secs */ #define SECS_PER_YEAR 31556952 /* 365.2425 days, 365d 05:49:12 */ #define SECS_PER_400YR ((llong_t)DAYS_PER_400YR * SECS_PER_DAY) #define DAYS_PER_YR 365 /* 365, no leap days */ #define DAYS_PER_4YR 1461 /* 4*365 + 1 leap day */ #define DAYS_PER_100YR 36524 /* 100*365 + 24 leap days */ #define DAYS_PER_400YR 146097 /* 400*365 + 97 leap days */ #define BITS_PER_SEC 29 #define TICKS_PER_SEC (1L << BITS_PER_SEC) #define TICKS_PER_400YR 6776803840072089600 #define TICKS_PER_NSEC_32 2305843009 /* (2^29<<32)/10^9 */ #define LONGTIME_SECS_PER_DAY ((longtime_t)SECS_PER_DAY) #define LONGTIME_SECS_PER_YR ((longtime_t)SECS_PER_YEAR) #define LONGTIME_SECS_PER_400YR ((longtime_t)DAYS_PER_400YR * SECS_PER_DAY) #define LONGTIME_TICKS_PER_DAY (LONGTIME_SECS_PER_DAY * TICKS_PER_SEC) #define LONGTIME_TICKS_PER_YR (LONGTIME_SECS_PER_YR * TICKS_PER_SEC) #define LONGTIME_TICKS_PER_400YR (LONGTIME_SECS_PER_400YR * TICKS_PER_SEC) #define LONGTIME_ZDYEAR 2001 #define LONGTIME_ZDOFFSET 0 #define LONGTIME_ZWKDAY 1 #define ULONGTIME_AD1601 (-146097 * LONGTIME_TICKS_PER_DAY) #define ULONGTIME_AD2001 ((longtime_t) 0) #define ULONGTIME_AD2401 (+146097 * LONGTIME_TICKS_PER_DAY) #define ULONGTIME_AD1601B MK_LONGTIME(1601, 0, 0,0,0,0) #define ULONGTIME_AD1700 MK_LONGTIME(1700, 0, 0,0,0,0) #define ULONGTIME_AD1800 MK_LONGTIME(1800, 0, 0,0,0,0) #define ULONGTIME_AD1858M MK_LONGTIME(1858, 304+17-1, 0,0,0,0) #define ULONGTIME_AD1900 MK_LONGTIME(1900, 0, 0,0,0,0) #define ULONGTIME_AD1970 MK_LONGTIME(1970, 0, 0,0,0,0) #define ULONGTIME_AD1980 MK_LONGTIME(1980, 0, 0,0,0,0) #define ULONGTIME_AD2000 MK_LONGTIME(2000, 0, 0,0,0,0) #define ULONGTIME_AD2050 MK_LONGTIME(2050, 0, 0,0,0,0) #define ULONGTIME_AD2100 MK_LONGTIME(2101, 0, 0,0,0,0) #define ULONGTIME_AD2101 MK_LONGTIME(2100, 0, 0,0,0,0) #define ULONGTIME_AD2200 MK_LONGTIME(2200, 0, 0,0,0,0) #define ULONGTIME_AD2300 MK_LONGTIME(2300, 0, 0,0,0,0) #define ULONGTIME_AD2400 MK_LONGTIME(2400, 0, 0,0,0,0) /******************************************************************************* * Local function macros *******************************************************************************/ #define MK_LONGTIME(yr,yd,h,m,s,n) \ ((((yr)>=LONGTIME_ZDYEAR) ? MK_DATE_DAYSP(yr, yd) : MK_DATE_DAYSN(yr, yd)) \ * LONGTIME_TICKS_PER_DAY + MK_TIME_TICKS(h, m, s, n)) #define MK_DATE_DAYSP(yr,yday) \ MK_DATE_DAYS(yr, yday) #define MK_DATE_DAYSN(yr,yday) \ (MK_DATE_DAYS((yr) + ((LONGTIME_ZDYEAR-(yr))/400+1)*400, yday) \ - ((LONGTIME_ZDYEAR-(yr))/400+1) * DAYS_PER_400YR) #define MK_DATE_DAYS(yr,yday) \ (((yr) - LONGTIME_ZDYEAR)/400 * DAYS_PER_400YR + \ ((yr) - LONGTIME_ZDYEAR)%400/100 * DAYS_PER_100YR + \ ((yr) - LONGTIME_ZDYEAR)%100/4 * DAYS_PER_4YR + \ ((yr) - LONGTIME_ZDYEAR)%4 * DAYS_PER_YR + \ (yday)) #define MK_TIME_TICKS(h,m,s,n) \ ((longtime_t)(((h)*60L + (m))*60L + (s)) << BITS_PER_SEC \ + ((longtime_t)(n)*TICKS_PER_NSEC_32) >> 32) #define LEAPSEC_DATE(yr,dy,adj) \ (MK_LONGTIME(yr, dy, 0, 0, 0, 0) + (adj << BITS_PER_SEC)) #define ADD_LEAPSECS(t) leapsecs[leapsecs_toadd(t)].m_secs /******************************************************************************* * Local constant variables *******************************************************************************/ /*----------------------------------------------------------------------------- * mdays[] * Contains the accumulated number of days for the first day of each * month. The array is based on Jan-01 being the very first day of the * adjusted 400-year Gregorian epoch. * * Caveats * The LONGTIME_ZDOFFSET macro must reflect the fact that Jan-01 is the * first day of the adjusted 400-year epoch. */ static const short mdays[] = { /* 0 Jan */ 0, /* 0 */ /* 1 Feb */ 31, /* 31 */ /* 2 Mar */ 31+28, /* 59 */ /* 3 Apr */ 31+28+31, /* 90 */ /* 4 May */ 31+28+31+30, /* 120 */ /* 5 Jun */ 31+28+31+30+31, /* 151 */ /* 6 Jul */ 31+28+31+30+31+30, /* 181 */ /* 7 Aug */ 31+28+31+30+31+30+31, /* 212 */ /* 8 Sep */ 31+28+31+30+31+30+31+31, /* 243 */ /* 9 Oct */ 31+28+31+30+31+30+31+31+30, /* 273 */ /* 10 Nov */ 31+28+31+30+31+30+31+31+30+31, /* 304 */ /* 11 Dec */ 31+28+31+30+31+30+31+31+30+31+30, /* 334 */ /* 12 - */ 31+28+31+30+31+30+31+31+30+31+30+32, /* 366 */ }; /******************************************************************************* * Local variables *******************************************************************************/ static bool dbg = false; /******************************************************************************* * Functions *******************************************************************************/ /*----------------------------------------------------------------------------- * leapsecs[] * Table of adjusted and unadjusted historical leap second dates (up to * 2006-01-01). Each entry contains a historical adjusted and unadjusted * long time value and the number of leap seconds to add to the unadjusted * value (for all dates at or prior to that date) to make it a proper * adjusted longtime_t value. * * Actual implementations may prefer to load this from some system file. * * @since 1.7, 2006-03-19 */ struct LeapSecondEntry { longtime_t m_date; /* Unadjusted date */ longtime_t m_adjdate; /* Adjusted date */ short m_secs; /* Accumulated leap seconds */ }; #define LT_MIN_LEAPSEC (-22) /* Min added leap seconds */ #define LT_MAX_LEAPSEC (+240) /* Max added leap seconds */ static const struct LeapSecondEntry leapsecs[] = { /* Minimum leap seconds */ { #if TEST _LONGTIME_MIN - ((llong_t)LT_MIN_LEAPSEC << BITS_PER_SEC) - 1, _LONGTIME_MIN - 1, LT_MIN_LEAPSEC #else _LONGTIME_MIN - ((llong_t)LT_MIN_LEAPSEC << BITS_PER_SEC), _LONGTIME_MIN, LT_MIN_LEAPSEC #endif }, /* Official leap seconds */ /* 1. 1972-06-30 23:59:60 */ { LEAPSEC_DATE(1972, 181+1, 0), LEAPSEC_DATE(1972, 181+1, -21), -21 }, /* 2. 1972-12-31 23:59:60 */ { LEAPSEC_DATE(1972, 365+0, 0), LEAPSEC_DATE(1972, 365+0, -20), -20 }, /* 3. 1973-12-31 23:59:60 */ { LEAPSEC_DATE(1973, 365+0, 0), LEAPSEC_DATE(1973, 365+0, -19), -19 }, /* 4. 1974-12-31 23:59:60 */ { LEAPSEC_DATE(1974, 365+0, 0), LEAPSEC_DATE(1974, 365+0, -18), -18 }, /* 5. 1975-12-31 23:59:60 */ { LEAPSEC_DATE(1975, 365+0, 0), LEAPSEC_DATE(1975, 365+0, -17), -17 }, /* 6. 1976-12-31 23:59:60 */ { LEAPSEC_DATE(1976, 365+1, 0), LEAPSEC_DATE(1976, 365+1, -16), -16 }, /* 7. 1977-12-31 23:59:60 */ { LEAPSEC_DATE(1977, 365+0, 0), LEAPSEC_DATE(1977, 365+0, -15), -15 }, /* 8. 1978-12-31 23:59:60 */ { LEAPSEC_DATE(1978, 365+0, 0), LEAPSEC_DATE(1978, 365+0, -14), -14 }, /* 9. 1979-12-31 23:59:60 */ { LEAPSEC_DATE(1979, 365+0, 0), LEAPSEC_DATE(1979, 365+0, -13), -13 }, /* 10. 1981-06-30 23:59:60 */ { LEAPSEC_DATE(1981, 181+0, 0), LEAPSEC_DATE(1981, 181+0, -12), -12 }, /* 11. 1982-06-30 23:59:60 */ { LEAPSEC_DATE(1982, 181+0, 0), LEAPSEC_DATE(1982, 181+0, -11), -11 }, /* 12. 1983-06-30 23:59:60 */ { LEAPSEC_DATE(1983, 181+0, 0), LEAPSEC_DATE(1983, 181+0, -10), -10 }, /* 13. 1985-06-30 23:59:60 */ { LEAPSEC_DATE(1985, 181+0, 0), LEAPSEC_DATE(1985, 181+0, -9), -9 }, /* 14. 1987-12-31 23:59:60 */ { LEAPSEC_DATE(1987, 365+0, 0), LEAPSEC_DATE(1987, 365+0, -8), -8 }, /* 15. 1989-12-31 23:59:60 */ { LEAPSEC_DATE(1989, 365+0, 0), LEAPSEC_DATE(1989, 365+0, -7), -7 }, /* 16. 1990-12-31 23:59:60 */ { LEAPSEC_DATE(1990, 365+0, 0), LEAPSEC_DATE(1990, 365+0, -6), -6 }, /* 17. 1992-06-30 23:59:60 */ { LEAPSEC_DATE(1992, 181+1, 0), LEAPSEC_DATE(1992, 181+1, -5), -5 }, /* 18. 1993-06-30 23:59:60 */ { LEAPSEC_DATE(1993, 181+0, 0), LEAPSEC_DATE(1993, 181+0, -4), -4 }, /* 19. 1994-06-30 23:59:60 */ { LEAPSEC_DATE(1994, 181+0, 0), LEAPSEC_DATE(1994, 181+0, -3), -3 }, /* 20. 1995-12-31 23:59:60 */ { LEAPSEC_DATE(1995, 365+0, 0), LEAPSEC_DATE(1995, 365+0, -2), -2 }, /* 21. 1997-06-30 23:59:60 */ { LEAPSEC_DATE(1997, 181+0, 0), LEAPSEC_DATE(1997, 181+0, -1), -1 }, /* 22. 1998-12-31 23:59:60 */ { LEAPSEC_DATE(1998, 365+0, 0), LEAPSEC_DATE(1998, 365+0, 0), 0 }, /* 23. 2005-12-31 23:59:60 */ { LEAPSEC_DATE(2005, 365+0, 0), LEAPSEC_DATE(2005, 365+0, +1), +1 }, /* Projected leap seconds (guesses only) */ /* (24) 2099-12-31 23:59:60+60 (projected) */ { LEAPSEC_DATE(2099, 365+0, 0), LEAPSEC_DATE(2099, 365+0, +1), +60 }, /* (25) 2199-12-31 23:59:60+60 (projected) */ { LEAPSEC_DATE(2199, 365+0, 0), LEAPSEC_DATE(2199, 365+0, +1), +120 }, /* (26) 2299-12-31 23:59:60+60 (projected) */ { LEAPSEC_DATE(2299, 365+0, 0), LEAPSEC_DATE(2299, 365+0, +1), +180 }, /* (27) 2399-12-31 23:59:60+60 (projected) */ { LEAPSEC_DATE(2399, 365+0, 0), LEAPSEC_DATE(2399, 365+0, +1), +240 }, }; static const size_t nleapsecs = sizeof(leapsecs) / sizeof(leapsecs[0]); /******************************************************************************* * Functions *******************************************************************************/ /*------------------------------------------------------------------------------ * getlongtime() * Retrieve the current system time. * * Returns * The current system time as a long time, or '_LONGTIME_ERROR' if the * system time cannot be obtained. * * Since * 1.1, 2004-07-10 */ longtime_t getlongtime(void) { #if defined(_WIN32) /*------------------------------------------------------------------------- * The Microsoft Win32 API can return the current system time in "file * timestamp" format, which is a 64-bit value representing the number of * 100-nanosecond ticks since {AD1601-01-01 00:00:00 Z}. This time value * is directly convertible into a longtime_t epoch tick count. *------------------------------------------------------------------------*/ { FILETIME ft; llong_t x; llong_t y; int d; /* Get the current system time */ GetSystemTimeAsFileTime(&ft); /* But not GetSystemTime(&st) */ /* Convert to longtime_t form */ x = ((llong_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime; y = (x%10000000 << BITS_PER_SEC) / 10000000; x = (x/10000000 << BITS_PER_SEC) + y; x += ULONGTIME_AD1601; d = leapsecs_toadd(x); if (d >= 0) x += (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; #if TEST y = ((llong_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime; printf("#systime= %08lX:%08lX, %+" LLONG_FMT "\n", (long)ft.dwHighDateTime, (long)ft.dwLowDateTime, y); printf("#time= %+" LLONG_FMT ".%07ld sec Win32\n", y/10000000, (long)(y%10000000)); printf("#AD1601= %+020" LLONG_FMT "\n", (llong_t)ULONGTIME_AD1601); printf("#offset= %+020" LLONG_FMT " ticks\n", x-ULONGTIME_AD1601); printf("#result= %+020" LLONG_FMT "\n", (llong_t)x); #endif return ((longtime_t)x); } #elif defined(_unix) /*------------------------------------------------------------------------- * The BSD gettimeofday() function fills a 'timeval' structure with the * current time_t value (which is the number of seconds since * {AD1970-01-01 00:00:00 Z}) and a microsecond count. These time values * are directly convertible into longtime_t epoch tick counts. * * If the gettimeofday() function is not available, we can use the POSIX.4 * clock_gettime() function instead. *------------------------------------------------------------------------*/ { struct timeval tv; llong_t x; int d; /* Get the current system time (secs & usecs) */ #if USE_POSIX_GETTIMEOFDAY clock_gettimeofday(&tv, NULL); #else gettimeofday(&tv, NULL); #endif #if TEST printf("#systime =<%ld.%06ld>\n", (long)tv.tv_sec, (long)tv.tv_usec); printf("#AD1970= %+20" LLONG_FMT "\n", (llong_t)ULONGTIME_AD1970); #endif /* Convert to longtime_t form */ x = ULONGTIME_AD1970; x += ((llong_t)tv.tv_sec << BITS_PER_SEC); x += ((llong_t)tv.tv_usec << BITS_PER_SEC) / 1000000; d = leapsecs_toadd(x); if (d >= 0) x += (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; return ((longtime_t)x); } #elif defined(_POSIX) /*------------------------------------------------------------------------- * The POSIX time() function returns the number of seconds since * {AD1970-01-01 00:00:00 Z}. This time value is directly convertible into * a longtime_t epoch tick count. *------------------------------------------------------------------------*/ { time_t t; /* Get the current system time (secs & usecs) */ time(&t); #if TEST printf("#systime= <%ld>\n", (long)t); printf("#AD1970= %+20" LLONG_FMT "\n", (llong_t)ULONGTIME_AD1970); #endif /* Convert to longtime_t form */ return (timetolongtime(t)); } #else /* ISO_C */ /*------------------------------------------------------------------------- * If all else fails, we can use the ISO/IEC C/C++ time() function to get * the current system time. * * Unfortunately, the only thing we know (portably) about the value is that * the 'time_t' type is arithmetic. This isn't much help for converting the * value into longtime_t epoch tick counts. We will let the timetolongtime() * function handle all the gory details of the conversion. *------------------------------------------------------------------------*/ { time_t t; /* Get the current system time (secs & usecs) */ time(&t); #if TEST printf("#systime= <%+lf>\n", (double)t); #endif /* Convert to component calendar form */ return (timetolongtime(t)); } #endif } /*------------------------------------------------------------------------------ * leapsecs_toadd() * Determine the leap second table entry to add to an unadjusted long time * value to make it a proper longtime_t value. * * Param t * An unadjusted long system time. * * Returns * Index into the leap second table 'leapsec[]' specifying the number of * accumulated inserted and deleted leap seconds to add to 't', * or -1 if there is no matching entry for 't'. * * Since * 1.7, 2006-03-19 */ static int leapsecs_toadd(longtime_t t) { int i; /* Check for special cases */ if (t == _LONGTIME_ERROR or t < ULONGTIME_AD1601 or t >= ULONGTIME_AD2401) return (-1); /* Simple linear search to find the leap accumulated seconds */ /* Note: This should be replaced with a more efficient algorithm */ for (i = nleapsecs-1; i >= 0; --i) { if (t >= leapsecs[i].m_date) break; } return (i); } /*------------------------------------------------------------------------------ * leapsecs_tosub() * Determine the leap second table entry to subtract from an adjusted long * time value to make it an unadjusted long time value. * * Param t * An adjusted long system time. * * Returns * Index into the leap second table 'leapsec[]' specifying the number of * accumulated inserted and deleted leap seconds to subtract from 't', * or -1 if there is no matching entry for 't'. * * Since * 1.7, 2006-03-19 */ static int leapsecs_tosub(longtime_t t) { int i; /* Check for special cases */ #if TEST if (t == _LONGTIME_ERROR or t < _LONGTIME_MIN-1 or t > _LONGTIME_MAX+1) return (-1); #else if (t == _LONGTIME_ERROR or t < _LONGTIME_MIN or t > _LONGTIME_MAX) return (-1); #endif /* Simple linear search to find the leap accumulated seconds */ /* Note: This should be replaced with a more efficient algorithm */ for (i = nleapsecs-1; i >= 0; --i) { if (t >= leapsecs[i].m_adjdate) break; } return (i); } /*------------------------------------------------------------------------------ * longtimeleapsecs() * Determine the total accumulated inserted and deleted leap seconds * contained in a long time value. * * Param t * A long system time. * * Returns * The total accumulated inserted and deleted leap seconds added to long * time value 't' if 't' is a valid long time value, otherwise INT_MIN. * * Since * 1.6, 2006-03-11 */ int longtimeleapsecs(longtime_t t) { int d; /* Determine accumulated leap seconds in an adjusted long time */ d = leapsecs_tosub(t); if (d >= 0) return (leapsecs[d].m_secs); return (INT_MIN); } /*------------------------------------------------------------------------------ * timetolongtime() * Converts a 'time_t' value into its corresponding long system time value. * * Param t * A system time to convert. * * Returns * The converted long time value if successful, otherwise * '_LONGTIME_ERROR'. If the time value cannot be converted, or the * resulting converted value exceeds the representational limits of the * 'longtime_t' type, the function fails. * * Since * 1.1, 2004-07-10 */ longtime_t timetolongtime(time_t t) { /* Check for special cases */ if (t == _TIME_ERROR or t < _TIME_MIN or t > _TIME_MAX) return (_LONGTIME_ERROR); #if defined(_WIN32) /*------------------------------------------------------------------------- * The Microsoft Win32 API 'time_t' type is identical to the POSIX type, * which is the number of seconds (sans leap seconds) since * {AD1970-01-01 00:00:00 Z}. This is directly convertible into a * longtime_t epoch tick count. *------------------------------------------------------------------------*/ { llong_t x; int d; /* Convert to longtime_t form */ x = (llong_t)t << BITS_PER_SEC; x += ULONGTIME_AD1970; d = leapsecs_toadd(x); if (d >= 0) x += (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; return ((longtime_t)x); } #elif defined(_unix) || defined(_POSIX) /*------------------------------------------------------------------------- * The Unix/POSIX 'time_t' type is the number of seconds (sans leap seconds) * since {AD1970-01-01 00:00:00 Z}. These time values are directly * convertible into longtime_t epoch tick counts. *------------------------------------------------------------------------*/ { llong_t x; int d; /* Convert to longtime_t form */ x = (llong_t)t << BITS_PER_SEC; x += ULONGTIME_AD1970; d = leapsecs_toadd(x); if (d >= 0) x += (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; return ((longtime_t)x); } #else /* ISO_C */ /*------------------------------------------------------------------------- * Unfortunately, the only thing we know (portably) about the time_t value is * that it is an arithmetic type. This isn't much help for converting the * value into longtime_t epoch tick counts. * * We can, however, convert the time_t value into a component 'tm' date * structure, then convert that into a 'calendar' structure, and then * finally convert that into a longtime_t value. What a pain! * This should make it clear how badly a native longtime_t is needed. *------------------------------------------------------------------------*/ { #if _CALENDAR_VS > 20060311 #error struct calendar has changed #endif struct tm st; struct calendar dt; /* Convert time to component date form */ st = *gmtime(&t); /* Note: Thread-safe? */ /* Convert component date form into calendar date */ memset(&dt, 0, sizeof(dt)); dt.cal_era = _CAL_ERA_COMMON; dt.cal_year = st.tm_year+1900; dt.cal_mon = st.tm_mon+1; dt.cal_mday = st.tm_mday; dt.cal_hour = st.tm_hour; dt.cal_min = st.tm_min; dt.cal_sec = st.tm_sec; dt.cal_nsec = 0; dt.cal_yday = 0; dt.cal_wday = 0; dt.cal_leapsec = INT_MIN; /* Convert calendar date into a long time value */ return (mklongtime(&dt, NULL)); } #endif } /*------------------------------------------------------------------------------ * longtimetotime() * Converts a long time value into its corresponding 'time_t' value. * * Param t * A long system time to convert. * * Returns * The converted 'time_t' value if successful, otherwise '_TIME_ERROR'. * If the long time value cannot be converted, or the resulting converted * value exceeds the representational limits of the 'time_t' type, the * function fails. * * Since * 1.1, 2004-07-10 */ time_t longtimetotime(longtime_t t) { int d; /* Check for special cases */ if (t == _LONGTIME_ERROR or t < _LONGTIME_MIN or t > _LONGTIME_MAX) return (_TIME_ERROR); #if defined(_WIN32) /*------------------------------------------------------------------------- * The Microsoft Win32 API 'time_t' type is identical to the POSIX type, * which is the number of seconds (sans leap seconds) since * {AD1970-01-01 00:00:00 Z}. A longtime_t tick count is directly * convertible into this time_t type. *------------------------------------------------------------------------*/ { long x; int d; /* Remove accumulated leap seconds */ d = leapsecs_tosub(t); if (d >= 0) t -= (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; /* Convert longtime_t form to time_t form */ x = (long) ((t - ULONGTIME_AD1970) >> BITS_PER_SEC); /* Check for special cases */ if (x < _TIME_MIN or x > _TIME_MAX) return (_TIME_ERROR); return ((time_t) x); } #elif defined(_unix) || defined(_POSIX) /*------------------------------------------------------------------------- * The Unix/POSIX 'time_t' type is the number of seconds (sans leap seconds) * since {AD1970-01-01 00:00:00 Z}. A longtime_t tick count is directly * convertible into this time_t type. *------------------------------------------------------------------------*/ { long x; int d; /* Remove accumulated leap seconds */ d = leapsecs_tosub(t); if (d >= 0) t -= (llong_t)leapsecs[d].m_secs << BITS_PER_SEC; /* Convert longtime_t form to time_t form */ x = (long) ((t - ULONGTIME_AD1970) >> BITS_PER_SEC); /* Check for special cases */ if (x < _TIME_MIN or x > _TIME_MAX) return (_TIME_ERROR); return ((time_t) x); } #else /* ISO_C */ /*------------------------------------------------------------------------- * If all else fails, we can use the ISO/IEC C/C++ mktime() function to * convert a longtime_t into a native time_t value. * * Unfortunately, the only thing we know (portably) about the time_t type is * that it is an arithmetic type. This isn't much help for converting a * longtime_t tick count into a time_t value. * * We can, however, convert the longtime_t value into a component 'calendar' * date structure, then convert that into a 'tm' structure, and then finally * convert that into a time_t value using mktime(). What a pain! This * should make it clear how badly a native longtime_t is needed. *------------------------------------------------------------------------*/ { #if _CALENDAR_VS > 20060311 #error struct calendar has changed #endif struct calendar dt; struct tm st; /* Adjust for the local timezone */ /* This assumes global variable 'timezone' is defined */ t -= (llong_t)timezone << BITS_PER_SEC; /* Convert long time to component date form */ memset(&dt, 0, sizeof(dt)); dt.cal_type = _CAL_TYPE_GREGORIAN; if (setcalendartime(&dt, NULL, t) < 0) return (_TIME_ERROR); /* Convert component date form into tm date */ memset(&st, 0, sizeof(st)); st.tm_year = dt.cal_year-1900; st.tm_mon = dt.cal_mon-1; st.tm_mday = dt.cal_mday; st.tm_yday = dt.cal_yday-1; st.tm_hour = dt.cal_hour; st.tm_min = dt.cal_min; st.tm_sec = dt.cal_sec; st.tm_isdst = -1; /* Convert calendar date into a long time value */ return (mktime(&st)); } #endif } /*------------------------------------------------------------------------------ * gregorian_setcalendartime() * Converts a long time value into a Gregorian calendar date relative to a * given timezone. * * Param date * A component calendar date object, which will be filled with the * converted Gregorian date. * * Param tz * A timezone object designating the timezone and DST rules to apply to the * converted date. This can be null, in which case GMT and no DST is * assumed. * * Param t * A long system time to convert. * * Returns * Zero if successful, otherwise -1. * * Since * 1.7, 2006-03-13 */ int gregorian_setcalendartime(struct calendar *date, const struct timezone *zone, longtime_t t) { #if _CALENDAR_VS > 20060311 #error struct calendar has changed #endif #if _C0X_TIMEZONE_VS > 20040822 #error struct timezone has changed #endif long int yr; long int t2; int yd; int d; /* Check args */ if (date == NULL) return (-1); if (date->cal_type != _CAL_TYPE_GREGORIAN) return (-1); /* Check for erroneous time value */ date->cal_year = _CAL_YR_ERROR; #if TEST if (t == _LONGTIME_ERROR or t < _LONGTIME_MIN-1 or t > _LONGTIME_MAX+1) return (-1); #else if (t == _LONGTIME_ERROR or t < _LONGTIME_MIN or t > _LONGTIME_MAX) return (-1); #endif /* Undo the old timezone/DST adjustment */ if (date->cal_zone != NULL) { t2 = date->cal_zone->tz_offset; t += ((llong_t)t2 << BITS_PER_SEC) / 1000; d = date->cal_dsti; if (d >= 0) { t2 = date->cal_zone->tz_z[d].z_dst; t -= (llong_t)t2 << BITS_PER_SEC; } } /* Initialize the date object */ memset(date, 0, sizeof(*date)); date->cal_type = _CAL_TYPE_GREGORIAN; date->cal_era = _CAL_ERA_COMMON; /* Remove accumulated leap seconds */ d = leapsecs_tosub(t); d = (d < 0 ? 0 : leapsecs[d].m_secs); date->cal_leapsec = d; t -= (llong_t)d << BITS_PER_SEC; /* Make a new timezone/DST adjustment */ if (zone != NULL) { t2 = date->cal_zone->tz_offset; t -= ((llong_t)t2 << BITS_PER_SEC) / 1000; } date->cal_zone = zone; /* Convert the linear long time into a calendar date */ /* Adjust 't' to be within a 400-year cycle (ZD%400) */ t -= LONGTIME_ZDOFFSET; /* Adjust 't' to be within 400 years of the ZD */ if (t < 0) { /* Add a multiple of 400 years to make 't' positive */ yr = (long)(t / LONGTIME_TICKS_PER_400YR) - 1; } else { /* Adjust 't' to be within 400 years of the ZD */ yr = (long)(t / LONGTIME_TICKS_PER_400YR); } t -= yr * LONGTIME_TICKS_PER_400YR; /* Ticks within 400-yr cycle */ yr *= 400; /* First year of 400-yr cycle */ /* Determine the nanoseconds */ t2 = (long)(t & TICKS_PER_SEC-1); /* Ticks since the second */ t >>= BITS_PER_SEC; /* Seconds since ZD%400 (exact) */ date->cal_nsec = (long)(((llong_t)t2*1000000000L + 500000000L) >> BITS_PER_SEC); #if IS_INCOMPLETE ...need to allow for leap seconds (hh:mm:60.uuu) here, ...where a day has 24*60*60+1 (86400+1) sec, or 24*60*60-1 (86400-1) sec; ...i.e., we need a func to tells us if t is within a leap sec interval #endif /* Determine the time (HH:MM:SS) */ t2 = (long)(t % (24*60*60)); /* Seconds since midnight */ date->cal_hour = t2 / (60*60); t2 %= 60*60; date->cal_min = t2 / 60; t2 %= 60; date->cal_sec = t2; /* Determine the day of the week */ t2 = t / SECS_PER_DAY; /* Days since ZD%400 */ date->cal_wday = (t2+LONGTIME_ZWKDAY) % 7; /* Determine the year and day of the year */ { long int p; long int t3; /* Determine the 100-year period within the 400-year cycle */ t3 = t2; p = t3 / DAYS_PER_100YR; /* 100yr periods since ZD%400 */ if (p >= 400/100) p = 400/100 - 1; yr += p * 100; t3 -= p * DAYS_PER_100YR; /* Days since ZD%100 */ /* Determine the 4-year period within the 100-year cycle */ p = t3 / DAYS_PER_4YR; /* 4yr periods since ZD%100 */ yr += p * 4; t3 -= p * DAYS_PER_4YR; /* Days since ZD%4 */ /* Determine the 1-year period within the 4-year cycle */ p = t3 / DAYS_PER_YR; /* 1yr periods since ZD%4 */ if (p >= 4/1) p = 4/1 - 1; yr += p; t3 -= p * DAYS_PER_YR; /* Days since Jan-01 */ /* Determine the day within the year */ yd = (int) t3; yr += LONGTIME_ZDYEAR; /* Year number (exact) */ date->cal_year = (int) yr; date->cal_yday = yd+1; } /* Determine the month and day of the month */ { bool lept; /* Determine leap days for the year */ lept = false; if (yd >= 31+28 /*mdays[2]*/ and (yr%4 == 0 and (yr%100 != 0 or yr%400 == 0))) { yd--; /* Adjust for a leap day in this year */ lept = true; } #if 1 /* Sanity check */ if (yd < 0 or yd > 365) { printf("*** yday out of range: %d\n", yd); fflush(stdout); return (-1); } #endif /* Determine the month */ d = yd / 31; /* First guess */ if (d < 11 and yd >= mdays[d+1]) d++; /* Corrected guess */ date->cal_mon = d+1; /* Determine the day of the month */ d = yd - mdays[d] + 1; /* Fix up special case of Feb-29 */ if (yd == 31+28-1 and lept) d++; date->cal_mday = d; } #if IS_INCOMPLETE___ /* Determine DST adjustment */ { ...; t2 = date->cal_zone->tz_z[date->cal_dsti].z_dst; t += (llong_t)t2 << BITS_PER_SEC; ...; ...set date->cal_dsti; } #else date->cal_dsti = -1; #endif return (0); } /*------------------------------------------------------------------------------ * setcalendartime() * Converts a long time value into a calendar date relative to a given * timezone. * * Param date * A component calendar date object, which will be filled with the * converted date. * * Param tz * A timezone object designating the timezone and DST rules to apply to the * converted date. This can be null, in which case GMT and no DST is * assumed. * * Param t * A long system time to convert. * * Returns * Zero if successful, otherwise -1. * * Since * 1.2, 2004-07-11 */ int setcalendartime(struct calendar *date, const struct timezone *zone, longtime_t t) { /* Convert the long time to a Gregorian calendar time */ return (gregorian_setcalendartime(date, zone, t)); } /*------------------------------------------------------------------------------ * gregorian_normcalendar() * Normalizes the members of a component calendar date. * * Param date * Pointer to a component calendar date object. The members of this * object are normalized to fall within their normal value ranges prior to * being converted into a long time value. The following members of the * structure are used to perform the conversion: * cal_era * cal_year * cal_mon * cal_mday * cal_hour * cal_min * cal_sec * cal_nsec * cal_leapsec * * These members can contain values outside their normal range of values. * The remaining members of the structure are ignored for the conversion. * * Param tz * Pointer to a timezone object containing timezone and DST adjustments * that have been made to the date represented by the calendar date object. * The timezone and DST adjustments are applied in reverse (i.e., undone) * on the calendar date before it is converted into a long time value. * This can (and should) be the same object as 'date->cal_zone'. * This can be null, in which case GMT and no DST is assumed. * * Returns * If the date can be normalized into a proper component calendar date, the * function returns zero, otherwise it returns -1. * * Since * 1.9, 2006-03-21 */ static int gregorian_normcalendar(struct calendar *date, const struct timezone *tz) { #if _CALENDAR_VS > 20060311 #error struct calendar has changed #endif #if _C0X_TIMEZONE_VS > 20040822 #error struct timezone has changed #endif long int x; long int d; #if IS_INCOMPLETE___ /* Normalize the calendar date members */ ...; +INCOMPLETE; #endif fprintf(stderr, "$ normcalendar(): NOT YET IMPLEMENTED\n"); return (-1); } /*------------------------------------------------------------------------------ * gregorian_mklongtime() * Converts a Gregorian calendar date into its corresponding long time * value. * * Param date * Pointer to a component calendar date object. * * Param tz * Pointer to a timezone object containing timezone and DST adjustments * that have been made to the date represented by the calendar date object. * * Returns * If successful, the function returns the resulting long time value, * otherwise it returns '_LONGTIME_ERROR'. * * Since * 1.9, 2006-03-21 */ longtime_t gregorian_mklongtime(struct calendar *date, const struct timezone *tz) { #if _CALENDAR_VS > 20060311 #error struct calendar has changed #endif #if _C0X_TIMEZONE_VS > 20040822 #error struct timezone has changed #endif long int x; long int d; llong_t t; /* Check args */ if (date == NULL) return (_LONGTIME_ERROR); if (date->cal_year == _CAL_YR_ERROR) return (_LONGTIME_ERROR); if (date->cal_type != _CAL_TYPE_GREGORIAN) return (_LONGTIME_ERROR); /* Normalize the date members */ if (gregorian_normcalendar(date, tz) < 0) return (_LONGTIME_ERROR); #if IS_INCOMPLETE___ +INCOMPLETE; /* Convert the normalized calendar date into a long time */ t = date->cal_year - LONGTIME_ZDYEAR; t = (t*3652425)/10000 + date->cal_yday - 1; t = t*24 + date->cal_hour; t = t*60 + date->cal_min; t = t*60 + date->cal_sec; t <<= BITS_PER_SEC; t += ((llong_t)date->cal_nsec * TICKS_PER_NSEC_32) >> 32; +INCOMPLETE; /* Add accumulated leap seconds */ d = leapsecs_toadd(t); d = (d < 0 ? 0 : leapsecs[d].m_secs); date->cal_leapsec = (int) d; t += d << BITS_PER_SEC; ...determine date->cal_mon, date->cal_mday; ...determine date->cal_dsti; +INCOMPLETE; return ((longtime_t) t); #endif fprintf(stderr, "$ mklongtime(): NOT YET IMPLEMENTED\n"); return (_LONGTIME_ERROR); } /*------------------------------------------------------------------------------ * mklongtime() * Converts a calendar date into its corresponding long time value. * * Param date * Pointer to a component calendar date object. The members of this * object are normalized to fall within their normal value ranges prior to * being converted into a long time value. The following members of the * structure are used to perform the conversion: * cal_era * cal_year * cal_mon * cal_mday * cal_hour * cal_min * cal_sec * cal_nsec * cal_leapsec * * These members can contain values outside their normal range of values. * The remaining members of the structure are ignored for the conversion. * * Param tz * Pointer to a timezone object containing timezone and DST adjustments * that have been made to the date represented by the calendar date object. * The timezone and DST adjustments are applied in reverse (i.e., undone) * on the calendar date before it is converted into a long time value. * This can (and should) be the same object as 'date->cal_zone'. * This can be null, in which case GMT and no DST is assumed. * * Returns * If successful, the function returns the resulting long time value, * otherwise it returns '_LONGTIME_ERROR'. If the calendar date does not * represent a meaningful date, or cannot be converted into a valid long * time value after adjustments have been applied, the function fails. * * Since * 1.1, 2004-07-10 */ longtime_t mklongtime(struct calendar *date, const struct timezone *tz) { return (gregorian_mklongtime(date, tz)); } /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ #if TEST static const char PROG[] = "c0xlongtime"; static const char VERS[] = "$Revision: 1.11 $"; static const char DATE[] = "$Date: 2006/07/08 19:29:58 $"; static void print_longtime(const char *name, longtime_t t) { struct calendar date; int o; /* Print the min time_t as a long time date */ o = (ispunct(name[0]) ? 1 : 0); dbg = (name[0] == '?'); memset(&date, 0, sizeof(date)); setcalendartime(&date, NULL, t); printf("%s :%+20" LLONG_FMT ", ", name+o, (llong_t)t); if (t == _LONGTIME_ERROR) printf("= _LONGTIME_ERROR"); else if (t < _LONGTIME_MIN-1) printf("< _LONGTIME_MIN"); else if (t > _LONGTIME_MAX+1) printf("> _LONGTIME_MAX"); else printf("%04d/%02d/%02d(%03d) %02d:%02d:%02d.%09ld(%+2ds) Z", date.cal_year, date.cal_mon, date.cal_mday, date.cal_yday, date.cal_hour, date.cal_min, date.cal_sec, date.cal_nsec, date.cal_leapsec); if (o > 0) printf(" %c", name[0]); printf("\n"); fflush(stdout); dbg = false; } /*------------------------------------------------------------------------------ * main() * Test driver. * * Usage * c0xlongtime * * Since * 1.1, 2004-07-10 */ int main(int argc, const char *const *argv) { time_t onow; time_t ot; longtime_t now; longtime_t t; struct tm ts; unsigned char * cp; int i; /* Display a program banner */ printf("[%s, %s %s]\n", PROG, VERS, DATE); printf("\n"); /* Get the current system time */ printf("Current time:\n"); now = getlongtime(); time(&onow); printf("\n"); /* Get the current system time as a time_t */ printf("Current time_t:\n"); printf("time(): ["); cp = (unsigned char *)&onow; for (i = 0; i < sizeof(onow); i++) printf("%s%02X", (i > 0 ? " " : ""), cp[i]); printf("], "); if (sizeof(time_t) >= sizeof(llong_t)) printf("%+" LLONG_FMT ", 0x%08" XLLONG_FMT "\n", (llong_t)onow, (llong_t)onow); else printf("%+lf, 0x%08lX\n", (double)onow, (long)onow); fflush(stdout); /* Print the current time as a date */ ot = onow; ts = *gmtime(&ot); printf("now : %04d/%02d/%02d(%03d) %02d:%02d:%02d Z *gmtime\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec); ts = *localtime(&ot); printf("now : %04d/%02d/%02d(%03d) %02d:%02d:%02d %s\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec, tzname[!!ts.tm_isdst]); printf("\n"); fflush(stdout); /* Print the min time as a date */ ot = _TIME_MIN; ts = *gmtime(&ot); printf("min : %04d/%02d/%02d(%03d) %02d:%02d:%02d Z\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec); fflush(stdout); /* Print a zero time as a date */ ot = (time_t)0; ts = *gmtime(&ot); printf("zero : %04d/%02d/%02d(%03d) %02d:%02d:%02d Z\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec); fflush(stdout); /* Print the max time as a date */ ot = _TIME_MAX; ts = *gmtime(&ot); printf("max : %04d/%02d/%02d(%03d) %02d:%02d:%02d Z\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec); printf("\n"); fflush(stdout); /* Get the current system time as a longtime_t */ printf("Current longtime:\n"); t = now; printf("longtime(): %+" LLONG_FMT ", 0x%016" XLLONG_FMT, (llong_t)t, (llong_t)t); printf(", ["); cp = (unsigned char *)&t; for (i = 0; i < sizeof(t); i++) printf("%s%02X", (i > 0 ? " " : ""), cp[i]); printf("]\n"); printf(" %+" LLONG_FMT ":%09ld", (llong_t)(t >> BITS_PER_SEC), (long)(t & ((1<> BITS_PER_SEC), (long)(t & ((1<> BITS_PER_SEC); x >>= BITS_PER_SEC; /* secs */ date.cal_sec = (int)(x % 60); x /= 60; /* mins */ date.cal_min = (int)(x % 60); x /= 60; /* hours */ date.cal_hour = (int)(x % 24); x /= 24; /* days */ y = x*10000 / 3652425; /* years */ date.cal_yday = (int)(x - y*3652425/10000) + 1; date.cal_year = (int)(y) + LONGTIME_ZDYEAR; date.cal_mon = (int)(date.cal_yday/30) + 1; date.cal_mday = (int)(date.cal_yday - mdays[date.cal_yday/31]); printf("fragments: : %04dy " "%+ldd %+ldy %04d/%02d/%02d(%03d) %02d:%02d:%02d.%09ld\n", LONGTIME_ZDYEAR, (long)x, (long)y, date.cal_year, date.cal_mon, date.cal_mday, date.cal_yday, date.cal_hour, date.cal_min, date.cal_sec, date.cal_nsec); fflush(stdout); } printf("\n"); /* Print the current long time as a date */ print_longtime("*now ", t); printf("\n"); /* Print a past and future long times as a date */ print_longtime("now-1000d ", t - 1000*LONGTIME_TICKS_PER_DAY); print_longtime("now+1000d ", t + 1000*LONGTIME_TICKS_PER_DAY); printf("\n"); /* Print the min long time as a date */ print_longtime("min-1 ", _LONGTIME_MIN-1); print_longtime("min ", _LONGTIME_MIN); print_longtime("min+1 ", _LONGTIME_MIN+1); /* Print a zero+delta long times as a date */ print_longtime("zero-1sec ", (longtime_t)-TICKS_PER_SEC); print_longtime("zero-1 ", (longtime_t)-1); print_longtime("zero ", (longtime_t)+0); print_longtime("zero+1 ", (longtime_t)+1); print_longtime("zero+1sec ", (longtime_t)TICKS_PER_SEC); print_longtime("zero+1hr ", (longtime_t)3600*TICKS_PER_SEC); print_longtime("zero+1day ", (longtime_t)86400*TICKS_PER_SEC); print_longtime("zero+1yr ", (longtime_t)365*86400*TICKS_PER_SEC); /* Print the max long time as a date */ print_longtime("max ", _LONGTIME_MAX); print_longtime("max+1 ", _LONGTIME_MAX+1); fflush(stdout); printf("\n"); /* Print the leap seconds table */ { int i; printf("Leap seconds:\n"); for (i = 0; i < nleapsecs; i++) { printf(" %2d. %+20" LLONG_FMT " %+20" LLONG_FMT " %+d\n", i, (llong_t)leapsecs[i].m_date, (llong_t)leapsecs[i].m_adjdate, leapsecs[i].m_secs); } printf("\n"); } /* Print some special dates */ printf("Special dates:\n"); print_longtime("AD1601 ", (longtime_t)ULONGTIME_AD1601B + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1601B) << BITS_PER_SEC)); print_longtime("AD1700 ", (longtime_t)ULONGTIME_AD1700 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1700) << BITS_PER_SEC)); print_longtime("AD1800 ", (longtime_t)ULONGTIME_AD1800 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1800) << BITS_PER_SEC)); print_longtime("AD1858M ", (longtime_t)ULONGTIME_AD1858M + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1858M) << BITS_PER_SEC)); print_longtime("AD1900 ", (longtime_t)ULONGTIME_AD1900 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1900) << BITS_PER_SEC)); print_longtime("AD1970 ", (longtime_t)ULONGTIME_AD1970 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1970) << BITS_PER_SEC)); print_longtime("?AD1980L-2 ", (longtime_t)ULONGTIME_AD1980 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1980)-2 << BITS_PER_SEC)); print_longtime("?AD1980L-1 ", (longtime_t)ULONGTIME_AD1980 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1980)-1 << BITS_PER_SEC)); print_longtime("?AD1980L ", (longtime_t)ULONGTIME_AD1980 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1980) << BITS_PER_SEC)); print_longtime("?AD1980L+1 ", (longtime_t)ULONGTIME_AD1980 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD1980)+1 << BITS_PER_SEC)); print_longtime("AD2000 ", (longtime_t)ULONGTIME_AD2000 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2000) << BITS_PER_SEC)); print_longtime("AD2050 ", (longtime_t)ULONGTIME_AD2050 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2050) << BITS_PER_SEC)); print_longtime("AD2100 ", (longtime_t)ULONGTIME_AD2100 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2100) << BITS_PER_SEC)); print_longtime("AD2101 ", (longtime_t)ULONGTIME_AD2101 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2101) << BITS_PER_SEC)); print_longtime("AD2200 ", (longtime_t)ULONGTIME_AD2200 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2200) << BITS_PER_SEC)); print_longtime("AD2300 ", (longtime_t)ULONGTIME_AD2300 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2300) << BITS_PER_SEC)); print_longtime("AD2400 ", (longtime_t)ULONGTIME_AD2400 + ((llong_t)ADD_LEAPSECS(ULONGTIME_AD2400) << BITS_PER_SEC)); printf("\n"); fflush(stdout); /* Convert the current time_t into a longtime_t */ printf("Convert time_t to longtime_t:\n"); t = timetolongtime(onow); printf("time_t now: %+" LLONG_FMT ", 0x%08" XLLONG_FMT "\n", (llong_t)t, (llong_t)t); printf(" %+" LLONG_FMT ":%09ld", (llong_t)(t >> BITS_PER_SEC), (long)(t & ((1<> BITS_PER_SEC), (long)(t & ((1< %ld, 0x%08lX\n", (llong_t)now, (long)ot, (long)ot); if (ot != _TIME_ERROR and ot >= _TIME_MIN and ot <= _TIME_MAX) { ts = *gmtime(&ot); printf(" : %04d/%02d/%02d(%03d) %02d:%02d:%02d Z *\n", ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_yday+1, ts.tm_hour, ts.tm_min, ts.tm_sec); } else if (ot == _TIME_ERROR) printf(" : _TIME_ERROR\n"); else printf(" : error\n"); fflush(stdout); /* Done */ return (EXIT_SUCCESS); } #endif /* TEST */ /* End c0xlongtime.c */