/*============================================================================= * drt/sys/ktm.c * DRT primitive date and time functions for the 'struct drt_tm_t' type. * * History * 0.01, 1999-04-10, David R Tribble. * First cut. * * 0.02, 1999-08-12, David R Tribble. * Added drt_tm_adjtz(). * * Copyright ©1999, by David R. Tribble, all rights reserved. * See "drt/sys/copyr.txt" for more information. *----------------------------------------------------------------------------*/ /* Identification */ static const char id[] = "@(#)drt/sys/ktm.c 0.02"; /* System includes */ #include #define drt_std_assert_h 1 #include #define drt_std_limits_h 1 #include #define drt_std_string_h 1 #if TEST || DEBUG #include #define drt_std_stdio_h 1 #endif /* Special includes */ #include "kdefs.h" /* Local includes */ #include "kdebug.h" #include "ktime.h" #include "ktimec.h" /* Local macros */ #if TEST #if DEBUG #define T(e) (e) #else #define T(e) (0) #endif #else #define T(e) (0) #endif /*----------------------------------------------------------------------------- * Public constants *----------------------------------------------------------------------------*/ #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif const int drt_tm_VS = DRT_TM_VS; /* Struct version number */ /*----------------------------------------------------------------------------- * Public functions *----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- * drt_tm_validate() * Verifies that 'th' is a valid date object. * * Returns * True if 'th' is a valid object, otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_validate(const struct drt_tm *th) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif /* Verify the object */ if (th == null) return (false); if (th->tm_vers/100 != DRT_TM_VS/100) return (false); /* Object appears to be valid */ return (true); } /*----------------------------------------------------------------------------- * drt_tm_zero() * Initializes date object 'th', setting its members to reflect the zero * date (ZD) of the 'drt_time_t' epoch. * * Returns * True if pointer 'th' is not null, otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_zero(struct drt_tm *th) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_zero"); #endif /* Initialize the date members to ZD, */ th->tm_vers = DRT_TM_VS; th->tm_year = TIME_ZDYEAR; th->tm_mon = 0; th->tm_mday = 1; th->tm_hour = 0; th->tm_min = 0; th->tm_sec = 0; th->tm_nsec = 0; th->tm_yday = TIME_ZDYRDAY; th->tm_wday = TIME_ZWKDAY; return (true); } /*----------------------------------------------------------------------------- * drt_tm_is_valid() * Determines if date 'th' represents a valid date, i.e., contains proper * member values. "Unknown" and "never" dates are also considered valid. * * Returns * True if this date is valid, otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_is_valid(const struct drt_tm *th) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_is_valid"); #endif /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Check for special cases */ if (th->tm_year == TIME_YR_UNKNOWN) /* Is 'unknown' */ return (true); if (th->tm_year == TIME_YR_NEVER) /* Is 'never' */ return (true); /* Check the date fields for normal values */ if (th->tm_year < TIME_MINYEAR or th->tm_year > TIME_MAXYEAR) return (false); if (th->tm_mon < 0 or th->tm_mon > 11) return (false); if (th->tm_mday < 1 or th->tm_mday > 31) return (false); if (th->tm_hour < 0 or th->tm_hour > 23) return (false); if (th->tm_min < 0 or th->tm_min > 59) return (false); if (th->tm_sec < 0 or th->tm_sec > 60) return (false); if (th->tm_nsec < 0 or th->tm_nsec > 999999999) return (false); return (true); } /*----------------------------------------------------------------------------- * drt_tm_is_unknown() * Determines if date 'th' represents an "unknown" date. * * Returns * True if this date is "unknown", otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_is_unknown(const struct drt_tm *th) { #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_is_unknown"); #endif /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Check for 'unknown' date */ if (th->tm_year == TIME_YR_UNKNOWN) return (true); return (false); } /*----------------------------------------------------------------------------- * drt_tm_is_never() * Determines if date 'th' represents a "never" date. * * Returns * True if this date is "never", otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_is_never(const struct drt_tm *th) { #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_is_never"); #endif /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Check for 'never' date */ if (th->tm_year == TIME_YR_NEVER) return (true); return (false); } /*----------------------------------------------------------------------------- * drt_tm_is_leap() * Determines if the date 'th' is a leap year. * * Returns * True if the year in date 'th' is a leap year, otherwise false. *----------------------------------------------------------------------------*/ bool drt_tm_is_leap(const struct drt_tm *th) { #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_is_leap"); #endif /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Check for leap year */ if (th->tm_year % 4 != 0) return (false); if (th->tm_year % 100 != 0) return (true); if (th->tm_year % 400 != 0) return (false); return (true); } /*----------------------------------------------------------------------------- * drt_tm_yday() * Determines the day of the year from the members of date 'th'. * * Returns * The numeric day of the year (i.e., the number of days since Jan-01). *----------------------------------------------------------------------------*/ int drt_tm_yday(const struct drt_tm *th) { int yday; /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Compute the day of the year */ yday = drt_time_mdays[th->tm_mon] + th->tm_mday - 1; if (drt_time_is_leap(th->tm_year) and th->tm_mon >= 2) yday++; /* Add a leap day */ return (yday); } /*----------------------------------------------------------------------------- * drt_tm_wday() * Determines the day of the week from the member of date 'th'. * * Returns * The numeric day of the week (i.e., the number of days since Sunday). *----------------------------------------------------------------------------*/ int drt_tm_wday(const struct drt_tm *th) { int wday; /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Compute the day of the week */ wday = 0; #if is_incomplete___ ... #endif return (wday); } /*----------------------------------------------------------------------------- * drt_tm_normalize() * Adjusts the members of date 'th' so that they fall within normal * numeric ranges. * * Returns * True if this date is valid (after normalization), otherwise false. * * Caveats * It is possible for members of structure 'th' to overflow or underflow * during the normalization process. This possibility is reduced somewhat * by using 'long int' values for the member adjustments. *----------------------------------------------------------------------------*/ bool drt_tm_normalize(struct drt_tm *th) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif bool changed; int total_changes = 0; #if DEBUG >= 2 DrtTrace dbg("drt_tm_normalize"); #endif /* Check this object */ if (not drt_tm_validate(th)) { T(printf("> Null/invalid\n")); return (false); } /* Check for special cases */ if (th->tm_year == TIME_YR_UNKNOWN or /* Is 'unknown' */ th->tm_year == TIME_YR_NEVER) /* Is 'never' */ { /* Set all other members to zero */ th->tm_mon = 0; th->tm_mday = 0; th->tm_hour = 0; th->tm_min = 0; th->tm_sec = 0; th->tm_nsec = 0; th->tm_yday = 0; th->tm_wday = 0; T(printf("> Unknown\n")); return (true); } /* Validate and normalize the date members */ do { long curr; long next; long year; T(printf("> [%+05d%+03d%+03d/%+03d%+03d%+03d.%+011d]\n", th->tm_year, th->tm_mon+1, th->tm_mday, th->tm_hour, th->tm_min, th->tm_sec, th->tm_nsec)); /* Adjust the year */ year = th->tm_year; if (year < TIME_MINYEAR or year > TIME_MAXYEAR) { /* Is invalid, outside the proper epoch */ T(printf("> year %ld outside the epoch\n", year)); goto fail; } else T(printf("> year %ld within the epoch\n", year)); changed = false; /* Adjust the nanosecond */ curr = th->tm_nsec; next = th->tm_sec; if (curr >= 1000000000) { T(printf("> nsec+, %ld\n", curr)); next += (curr / 1000000000); curr %= 1000000; changed = true; } else if (curr < 0) { T(printf("> nsec-, %ld\n", curr)); next -= (-curr / 1000000000); curr = (-curr % 1000000000); changed = true; } else T(printf("> nsec %ld okay\n", curr)); th->tm_nsec = curr; /* Adjust the second */ curr = next; next = th->tm_min; if (curr >= 60) { T(printf("> sec+, %ld\n", curr)); next += (curr / 60); curr %= 60; changed = true; } else if (curr < 0) { T(printf("> sec-, %ld\n", curr)); next -= (-curr / 60); curr = (-curr % 60); changed = true; } else T(printf("> sec %ld okay\n", curr)); th->tm_sec = curr; /* Adjust the minute */ curr = next; next = th->tm_hour; if (curr >= 60) { T(printf("> min+, %ld\n", curr)); next += (curr / 60); curr %= 60; changed = true; } else if (curr < 0) { T(printf("> min-, %ld\n", curr)); next -= (-curr / 60); curr = (-curr % 60); changed = true; } else T(printf("> min %ld okay\n", curr)); th->tm_min = curr; /* Adjust the hour */ curr = next; next = th->tm_mday; if (curr >= 24) { T(printf("> hour+, %ld\n", curr)); next += (curr / 24); curr %= 24; changed = true; } else if (curr < 0) { T(printf("> hour-, %ld\n", curr)); next -= (-curr / 24); curr = (-curr % 24); changed = true; } else T(printf("> hour %ld okay\n", curr)); th->tm_hour = curr; /* Adjust the month */ curr = th->tm_mon; if (curr >= 12) { T(printf("> mon+ %ld, add 12x%ld months\n", curr, curr/12)); year += (curr / 12); curr %= 12; changed = true; } else if (curr < 0) { T(printf("> mon- %ld, sub 12x%ld months\n", curr, -curr/12)); year -= (-curr / 12); curr = (-curr % 12); changed = true; } else T(printf("> mon %ld(%ld) okay\n", curr, curr+1)); th->tm_mon = curr; /* Adjust the day of the month */ { int wday = 1; ///Needed here? long yr400; ///Needed at all? long yr100; ///Needed at all? long yr4; ///Needed at all? curr = next; /* Adjust the day of the month to be within a 400-year period */ if (curr >= DAYS_PER_400YR) { T(printf("> mday+ %ld, add 400x%ld=%ld years", curr, curr/DAYS_PER_400YR, curr/DAYS_PER_400YR*400)); year += (curr / DAYS_PER_400YR) * 400; curr %= DAYS_PER_400YR; T(printf(": %ld\n", year)); changed = true; } else if (curr <= 0) { T(printf("> mday- %ld, sub 400x%ld=%ld years", curr, -curr/DAYS_PER_400YR+1, (-curr/DAYS_PER_400YR+1)*400)); year -= (-curr/DAYS_PER_400YR + 1) * 400; curr = (DAYS_PER_400YR - -curr%DAYS_PER_400YR); T(printf(": %ld\n", year)); changed = true; } else T(printf("> mday %ld, within 400yr range (<%ld)\n", curr, DAYS_PER_400YR)); /* Adjust the day of the month within the 400-year period */ { yr400 = (year-1)/400 * 400 + 1; /* Nearest 400-yr multiple */ T(printf("> 400yr base is %ld (year %ld)\n", yr400, year)); } /* Adjust the day of the month to be within a 100-year period */ if (curr >= DAYS_PER_100YR) { T(printf("> mday+ %ld, add 100x%ld=%ld years", curr, curr/DAYS_PER_100YR, curr/DAYS_PER_100YR*100)); year += (curr / DAYS_PER_100YR) * 100; curr %= DAYS_PER_100YR; T(printf(": %ld\n", year)); changed = true; } else if (curr <= 0) { T(printf("> mday- %ld, sub 100x%ld=%ld years", curr, -curr/DAYS_PER_100YR+1, (-curr/DAYS_PER_100YR+1)*100)); year -= (-curr/DAYS_PER_100YR + 1) * 100; curr = (DAYS_PER_100YR - -curr%DAYS_PER_100YR); T(printf(": %ld\n", year)); changed = true; } else T(printf("> mday %ld, within 100yr range (<%ld)\n", curr, DAYS_PER_100YR)); /* Adjust the day of the month within the 100-year period */ { yr100 = (year-1)/100 * 100 + 1; /* Nearest 100-yr multiple */ T(printf("> 100yr base is %ld (year %ld)\n", yr100, year)); } /* Adjust the day of the month to be within a 4-year period */ if (curr >= DAYS_PER_4YR) { T(printf("> mday+ %ld, add 4x%ld=%ld years", curr, curr/DAYS_PER_4YR, curr/DAYS_PER_4YR*4)); year += (curr / DAYS_PER_4YR) * 4; curr %= DAYS_PER_4YR; T(printf(": %ld\n", year)); changed = true; } else if (curr <= 0) { T(printf("> mday- %ld, sub 4x%ld=%ld years", curr, -curr/DAYS_PER_4YR+1, (-curr/DAYS_PER_4YR+1)*4)); year -= (-curr/DAYS_PER_4YR + 1) * 4; curr = (DAYS_PER_4YR - -curr%DAYS_PER_4YR); T(printf(": %ld\n", year)); changed = true; } else T(printf("> mday %ld, within 4yr range (<%ld)\n", curr, DAYS_PER_4YR)); /* Adjust the day of the month within the 4-year period */ { yr4 = (year-1)/4 * 4 + 1; /* Nearest 4-yr multiple */ T(printf("> 4yr base is %ld (year %ld)\n", yr4, year)); } /* Adjust the day of the month to be within a 1-year period */ if (curr >= DAYS_PER_YEAR) { T(printf("> mday+ %ld, add 1x%ld=%ld years", curr, curr/DAYS_PER_YEAR, curr/DAYS_PER_YEAR*1)); year += (curr / DAYS_PER_YEAR); curr %= DAYS_PER_YEAR; T(printf(": %ld\n", year)); changed = true; } else if (curr <= 0) { T(printf("> mday- %ld, sub 1x%ld=%ld years", curr, -curr/DAYS_PER_YEAR+1, (-curr/DAYS_PER_YEAR+1)*1)); year -= (-curr/DAYS_PER_YEAR + 1); curr = (DAYS_PER_YEAR - -curr%DAYS_PER_YEAR); T(printf(": %ld\n", year)); changed = true; } else T(printf("> mday %ld, within 1yr range (<%ld)\n", curr, DAYS_PER_YEAR)); #if 0 ///Needed here at all? ////Does this work? ////This should only be used for wday computation /* Adjust the day of the month to be within a 100-year period */ if (year + curr/DAYS_PER_100YR*100 - yr400 >= 100) { int delta; delta = (year + curr/DAYS_PER_100YR*100 - yr400)/100; T(printf("> yr>100, add %ldx5 100yr leapdays\n", delta)); wday += delta*5; } ////Does this work? ////This should only be used for wday computation /* Adjust the day of the month to be within a 4-year period */ if (year + curr/DAYS_PER_4YR*4 - yr400 >= 4) { int delta; delta = (year + curr/DAYS_PER_4YR*4 - yr400)/4; T(printf("> yr>4, add %ldx5 4yr leapdays\n", delta)); wday += delta*5; } #if 0 // not_needed ////Does this work? ////This should only be used for wday computation /* Adjust the day of the month to be within a 1-year period */ if (year + curr/DAYS_PER_YEAR - yr400 >= 1) { long delta; delta = year + curr/DAYS_PER_YEAR - yr400; T(printf("> yr>1, add 1x%ld years", delta)); year += delta; curr -= delta*DAYS_PER_YEAR; T(printf(": %ld (%+ld mdays)\n", year, curr)); changed = true; } #endif #endif ///Needed here at all? th->tm_wday = wday % 7; T(printf("> wday=%d\n", th->tm_wday)); if (changed) T(printf("> Adjusted base year is %ld\n", year)); } th->tm_mday = curr; /* Adjust the day of the month within the given month */ curr = th->tm_mday; next = th->tm_mon; while (curr >= drt_time_mdays[next%12+1] - drt_time_mdays[next%12]) ////This does not handle Feb-29! { T(printf("# mday+ %ld, add a month#%d of %d days\n", curr, next%12+1, drt_time_mdays[next%12+1]-drt_time_mdays[next%12])); curr -= drt_time_mdays[next%12+1] - drt_time_mdays[next%12]; next++; changed = true; if (next >= 12) { T(printf("# mon+ %ld, roll to next year %ld\n", next, year+1)); next -= 12; year++; changed = true; } } th->tm_mday = curr; th->tm_mon = next; ////Is this extra adjustment needed? /* Adjust the month */ curr = th->tm_mon; if (curr >= 12) { T(printf("> mon+ %ld, add 12x%ld months\n", curr, curr/12)); year += (curr / 12); curr %= 12; changed = true; } else if (curr < 0) { T(printf("> mon- %ld, sub 12x%ld months\n", curr, -curr/12)); year -= (-curr / 12); curr = (-curr % 12); changed = true; } else T(printf("> mon %ld(%ld) okay\n", curr, curr+1)); th->tm_mon = curr; /* Adjust the year */ if (year < TIME_MINYEAR or year > TIME_MAXYEAR) { T(printf("> year %ld out of epoch\n", year)); goto fail; /* Is invalid */ } else T(printf("> year %ld okay\n", year)); th->tm_year = year; if (changed) { T(printf("> changes incurred\n")); total_changes++; if (total_changes > 3) break; } else { T(printf("> [%+05d%+03d%+03d/%+03d%+03d%+03d.%+011d]\n", th->tm_year, th->tm_mon+1, th->tm_mday, th->tm_hour, th->tm_min, th->tm_sec, th->tm_nsec)); } } while (changed); /* Re-compute the day of the year */ th->tm_yday = drt_tm_yday(th); /* Re-compute the day of the week */ th->tm_wday = drt_tm_wday(th); T(printf("> wday=%d\n", th->tm_wday)); #if is_incomplete___ /* Re-compute the week of the year */ //... compute th->tm_week #endif #if is_incomplete___ //... check th->tm_dst ?? #endif /* Done */ return (true); fail: /* Date is invalid, set it to 'unknown' */ th->tm_year = TIME_YR_UNKNOWN; /* Set all other members to zero */ th->tm_mon = 0; th->tm_mday = 0; th->tm_hour = 0; th->tm_min = 0; th->tm_sec = 0; th->tm_nsec = 0; th->tm_yday = 0; th->tm_wday = 0; T(printf("> Invalid -> Unknown\n")); return (false); } /*----------------------------------------------------------------------------- * drt_tm_cmp() * Compares date 'a' to date 'b'. * * Returns * Signed value x, where: * x < 0 if date 'a' occurs before date 'b', or * x = 0 if date 'a' is the same as date 'b', or * x > 0 if date 'a' occurs after date 'b'. * * An "unknown" date always compares less than any other date, and a * "never" date always compares greater than any other date. * * | b * a | unknown valid never invalid * --------+------------------------------ * unknown | = < < < * valid | > <,=,> < ? * never | > > = > * invalid | ? ? ? ? * * "?" indicates an indeterminate ordering. * * Caveats * Returns -1 if either date 'a' or 'b' is invalid. *----------------------------------------------------------------------------*/ int drt_tm_cmp(const struct drt_tm *a, const struct drt_tm *b) { #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif int dif; #if DEBUG >= 2 DrtTrace dbg("drt_tm_cmp"); #endif /* Check args */ if (not drt_tm_validate(a)) return (-1); if (not drt_tm_validate(b)) return (+1); /* Handle special cases */ if (a->tm_year == TIME_YR_UNKNOWN) /* Is 'unknown' */ { if (b->tm_year == TIME_YR_UNKNOWN) return (0); /* Both are 'unknown' */ return (-1); } if (a->tm_year == TIME_YR_NEVER) /* Is 'never' */ { if (b->tm_year == TIME_YR_NEVER) return (0); /* Both are 'never' */ return (+1); } /* Compare the date members */ dif = a->tm_year - b->tm_year; if (dif != 0) return (dif); dif = a->tm_mon - b->tm_mon; if (dif != 0) return (dif); dif = a->tm_mday - b->tm_mday; if (dif != 0) return (dif); dif = a->tm_hour - b->tm_hour; if (dif != 0) return (dif); dif = a->tm_min - b->tm_min; if (dif != 0) return (dif); dif = a->tm_sec - b->tm_sec; if (dif != 0) return (dif); if (a->tm_nsec < b->tm_nsec) return (-1); if (a->tm_nsec > b->tm_nsec) return (+1); /* Note: Ignore m_yday */ /* Note: Ignore m_wday */ /* Otherwise the dates are equal */ return (0); } /*----------------------------------------------------------------------------- * drt_tm_adjtz() * Adjusts the members of date 'th' by adding the timezone offset in 'tz', * and then normalizing the members of 'th'. * * Returns * True if this date is valid (after normalization), otherwise false. * * Caveats * Pointer 'tz' can be null, in which case no adjustment to 'th' is made. * * Date values of 'unknown' and 'never' are not adjusted. *----------------------------------------------------------------------------*/ bool drt_tm_adjtz(struct drt_tm *th, const struct drt_tz *tz) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif #if DRT_TZ_VS != 101 #error DRT_TZ_VS has changed #endif #if DEBUG >= 2 DrtTrace dbg("drt_tm_normalize"); #endif /* Check this object */ if (not drt_tm_validate(th)) return (false); /* Check args */ if (tz == null) return (true); if (not drt_tz_validate(tz)) return (false); /* Check for special cases */ if (th->tm_year == TIME_YR_UNKNOWN or /* Is 'unknown' */ th->tm_year == TIME_YR_NEVER) /* Is 'never' */ { /* Date stays the same, do not adjust it */ return (true); } /* Add the timezone offset to the time */ th->tm_sec += tz->tz_sec; th->tm_min += tz->tz_min; th->tm_hour += tz->tz_hour; /* Normalize the adjusted date */ return (drt_tm_normalize(th)); } /*===========================================================================*/ /*===========================================================================*/ #if TEST == 1 static const char wkday[7][3+1] = { /* Default weekday names */ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /*----------------------------------------------------------------------------- * Local fake functions *----------------------------------------------------------------------------*/ static bool drt_tz_validate(const struct drt_tz *tz) { return (tz != null); } /*----------------------------------------------------------------------------- */ static void printtm(const struct drt_tm *th) { if (th->tm_year == TIME_YR_UNKNOWN) printf("UNKNOWN"); else if (th->tm_year == TIME_YR_NEVER) printf("NEVER "); else if (th->tm_year < 0) printf("BC%04d", th->tm_year+1); else printf("AD%04d", th->tm_year); printf("-%02d-%02d(%+04d)", th->tm_mon+1, th->tm_mday, th->tm_yday); printf(" %02d:%02d:%02d.%09ld", th->tm_hour, th->tm_min, th->tm_sec, th->tm_nsec); printf(" %s", (th->tm_wday >= 0) ? wkday[th->tm_wday] : "? "); printf("\n"); } /*----------------------------------------------------------------------------- * main() * Test driver. *----------------------------------------------------------------------------*/ int main(void) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif struct drt_tm t0; struct drt_tm ti; struct drt_tm ts; struct drt_tm te; /* Set up */ { drt_tm_zero(&t0); t0.tm_year = TIME_ZDYEAR; t0.tm_mon = 0; t0.tm_mday = 1; t0.tm_hour = 0; t0.tm_min = 0; t0.tm_sec = 0; t0.tm_nsec = 0; t0.tm_yday = -1; t0.tm_wday = -1; drt_tm_zero(&ti); ti.tm_year = 1980; ti.tm_mon = 12-1; ti.tm_mday = 31; ti.tm_hour = 23; ti.tm_min = 59; ti.tm_sec = 59; ti.tm_nsec = 999999999; ti.tm_yday = -1; ti.tm_wday = -1; } /* Test 1 */ { /* Add a few denormalizing values to the date members */ ts = ti; printf("Start: "); printtm(&ts); ts.tm_nsec += 1; te = t0; te.tm_year = ts.tm_year+1; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("Expect: "); printtm(&te); printf("---\n\n"); } /* Test 2 */ { /* Add a few denormalizing values to the date members */ ts = ti; printf("Start: "); printtm(&ts); ts.tm_nsec += 1; ts.tm_mday += 1; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } /* Test 3 */ { /* Add a few denormalizing values to the date members */ ts = ti; printf("Start: "); printtm(&ts); ts.tm_year += -1; ts.tm_mon += 1; ts.tm_mday += 1; ts.tm_nsec += 1; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } /* Test 4 */ { /* Add a few denormalizing values to the date members */ ts = t0; ts.tm_year = 1900; printf("Start: "); printtm(&ts); ts.tm_mon += 12*5; /* 5 year's worth of months */ printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } /* Test 5 */ { /* Add a few denormalizing values to the date members */ ts = t0; ts.tm_year = 1900; printf("Start: "); printtm(&ts); ts.tm_nsec += 1000000000; ts.tm_sec += 60; ts.tm_min += 60; ts.tm_hour += 24; ts.tm_mday += 31; ts.tm_mon += 12; ts.tm_year += 1111; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } /* Test 6 */ { /* Add a few denormalizing values to the date members */ ts = t0; ts.tm_year = 1900; printf("Start: "); printtm(&ts); ts.tm_nsec -= 1000000000; ts.tm_sec -= 60; ts.tm_min -= 60; ts.tm_hour -= 24; ts.tm_mday -= 31; ts.tm_mon -= 12; ts.tm_year -= 1111; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } /* Test 7 */ { /* Add a few denormalizing values to the date members */ ts = t0; ts.tm_year = 1964; printf("Start: "); printtm(&ts); te = ts; ts.tm_mon = 2-1; ts.tm_mday = 29+1; te.tm_mon = 3-1; te.tm_mday = 1; printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("Expect: "); printtm(&te); printf("---\n\n"); } /* Test 8 */ { /* Add a few denormalizing values to the date members */ ts = t0; ts.tm_year = 1970; printf("Start: "); printtm(&ts); ts.tm_sec += (29L*36525/100) * 86400; /* 29 year's worth of secs */ printf("Denorm: "); printtm(&ts); /* Normalize the denormalized date */ if (not drt_tm_normalize(&ts)) printf("Can't normalize\n"); printf("Norm: "); printtm(&ts); printf("---\n\n"); } return (0); } #endif /* TEST == 1 */ /* End ktm.c */