/*============================================================================= * drt/sys/ktm2.c * DRT primitive date and time functions for the 'struct drt_tm' type. * * Notes * Defining 'USE_STRFTIME' to nonzero causes this code to call strftime() * for string formatting operations. * * History * 0.01, 1999-04-10, David R Tribble. * First cut. * * Copyright ©1999, by David R. Tribble, all rights reserved. * See "drt/sys/copyr.txt" for more information. *----------------------------------------------------------------------------*/ /* Identification */ static const char id[] = "@(#)drt/sys/ktm2.c 0.01"; /* 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 #include #define drt_std_stdio_h 1 #endif #if DEBUG #include #define drt_std_stdio_h 1 #endif /* Special includes */ #include "kdefs.h" #include "ktime.h" /* Local includes */ #include "kdebug.h" #include "ktimec.h" /*----------------------------------------------------------------------------- * Public constants *----------------------------------------------------------------------------*/ #if DRT_TM_VS/100 != 1 #error DRT_TM_VS has changed #endif const char drt_tm_iso8601[] = "%Y-%m-%d %H:%M:%S"; /* Default ISO-8601 format */ const char drt_tm_month[12][3+1] = { /* Default month names */ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; const char drt_tm_wkday[7][3+1] = { /* Default weekday names */ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /*----------------------------------------------------------------------------- * Public functions *----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- * drt_tm_strf() * Convert date 'th' into the formatted string 's', where 'fmt' specifies * the formatting to apply. No more than 'slen' characters are placed * into string 's'. * * Notes * The format string 'fmt' contains a sequence of regular characters and * format specifiers. Each regular character is copied as is into the * target string 's', while each format specifier copies one or more of * the members of the broken-down time structure 'th' into the target * string as a formatted substring. * * Each format specifier begins with a '%' character, followed by an * optional sequence of digits specifying a width, followed by a one- * or two-character format specification. * * The format specifications supported are: * * % "%" character. * a 3-char weekday name abbr, ["Sun","Sat"]. * b 3-char month name abbr, ["Jan","Dec"]. * c ... * d 2-digit day of the month, ["01","31"]. * e ... * h 2-digit 12-hour number, ["00","12"]. * H 2-digit 24-hour number, ["00","23"]. * j ... * m 2-digit month number, ["01","12"]. * M 2-digit minute number, ["00","59"]. * o ... * s 6-digit microsecond number, ["000000","999999"]. * S 2-digit second number, ["00","60"]. * T? Time, in the form "HH:MM:SS". * u ... * w ... * y 2-digit year number within the century, ["00","99"]. * Y 4-digit year number, ["0000","9999"]. * z ... How do we handle timezones? * ?? 'AD' or 'BC'. * ?? 'CE' or 'BCE'. * ?? 'AM' or 'PM'. * ?? 'am' or 'pm'. * ... * Ec ... * ... * Od ... * ... * #if USE_STRFTIME * This function uses the ISO strftime() function to do most of its work. #endif * * Examples * The following format strings are shown with their resulting string * outputs, assuming a drt_tm structure containing the broken-down time * for the date is used: * * Format Result * "%Y-%m-%d %H:%M:%S %a" "1980-05-08 14:30:45 Thu" * "%m/%d/%y" "05/08/80" * "%YD%j" "1980D127" * "%D" ... * "%T" "14:30:45" * "%H:%M:%S.%s" "14:30:45.666666666" * "%h:%M:%S.%3s %P" "02:30:45.666 PM" * "%c" ... * ... ... * * Returns * The number of characters placed into string 's', or -1 on error. *----------------------------------------------------------------------------*/ int drt_tm_strf(const struct drt_tm *th, const char *fmt, char *s, size_t slen) { #if DRT_TM_VS != 101 #error DRT_TM_VS has changed #endif char * s0; #if DEBUG >= 2 DrtTrace dbg("drt_tm_strf"); #endif /* Check the args */ if (s == null) return (-1); if (fmt == null) return (-1); if (slen == 0) return (0); if (not drt_tm_validate(th)) return (-1); /* Parse the format string, filling the target string as we go */ s0 = s; for ( ; fmt[0] != '\0'; fmt++) { #if USE_STRFTIME ...incomplete char buf[80]; #endif /* Parse the next format string character */ if (fmt[0] == '%') { /* Format specifier */ fmt++; switch (fmt[0]) { #if is_incomplete___ ...etc... #endif case 'd': { int x; /* 2-digit day of the month, ["01","31"] */ if (slen < 2) goto overflow; x = th->tm_mday; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'h': { int x; /* 2-digit 12-hour number, ["00","12"] */ if (slen < 2) goto overflow; x = th->tm_hour; if (x > 12) x -= 12; else if (x == 0) x = 12; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'H': { int x; /* 2-digit 24-hour number, ["00","23"] */ if (slen < 2) goto overflow; x = th->tm_hour; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'm': { int x; /* 2-digit month, ["01","12"] */ if (slen < 2) goto overflow; x = th->tm_mon; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'M': { int x; /* 2-digit minute number, ["00","59"] */ if (slen < 2) goto overflow; x = th->tm_min; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'S': { int x; /* 2-digit second number, ["00","60"] */ if (slen < 2) goto overflow; x = th->tm_sec; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'T': { int x; /* Time, format "HH:MM:SS" */ if (slen < 8) goto overflow; x = th->tm_hour; s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s[2] = ':'; x = th->tm_min; s[3] = x/10 % 10 + '0'; s[4] = x % 10 + '0'; s[5] = ':'; x = th->tm_sec; s[6] = x/10 % 10 + '0'; s[7] = x % 10 + '0'; s += 8; slen -= 8; break; } case 'y': { int x; /* 2-digit year number, ["00","99"] */ if (slen < 2) goto overflow; x = th->tm_year; if (x < 0) x = -x+1; /* Adjust for BC/BCE */ s[0] = x/10 % 10 + '0'; s[1] = x % 10 + '0'; s += 2; slen -= 2; break; } case 'Y': { int x; /* 4-digit year number, ["0000","9999"] */ if (slen < 4) goto overflow; x = th->tm_year; if (x < 0) x = -x+1; /* Adjust for BC/BCE */ s[0] = x/1000 % 10 + '0'; s[1] = x/100 % 10 + '0'; s[2] = x/10 % 10 + '0'; s[3] = x % 10 + '0'; s += 4; slen -= 4; break; } #if is_incomplete___ case ???: { /* 'AD' or 'BC' */ if (slen < 2) goto overflow; if (th->tm_year < 0) { s[0] = 'B'; s[1] = 'C'; } else { s[0] = 'A'; s[1] = 'D'; } s += 2; slen -= 2; break; } #endif #if is_incomplete___ case ???: { /* 'CE' or 'BCE' */ if (th->tm_year < 0) { if (slen < 3) goto overflow; s[0] = 'B'; s[1] = 'C'; s[2] = 'E'; s += 3; slen -= 3; } else { if (slen < 2) goto overflow; s[0] = 'C'; s[1] = 'E'; s += 2; slen -= 2; } break; } #endif #if is_incomplete___ ...etc... #endif case '%': case '\0': { /* '%' character */ if (slen < 1) goto overflow; s[0] = '%'; s += 1; slen -= 1; if (fmt[0] == '\0') fmt--; break; } default: { /* Invalid formatting character */ if (slen < 1) goto overflow; s[0] = '?'; s += 1; slen -= 1; break; } } } else { /* Non-formatting character */ if (slen < 1) goto overflow; s[0] = fmt[0]; s += 1; slen -= 1; } } overflow: /* Delimit the resulting string */ if (slen > 0) { s[0] = '\0'; slen -= 1; } return (s - s0); } #if borrow_these_funcs_from_stm_cpp int DrtTm::dateToString(char *buf, int len /* = 8+1 */) const int DrtTm::timeToString(char *buf, int len /* = 9+1 */) const int DrtTm::toString(char *buf, int len /* = 18+1 */) const int DrtTm::toStringISO(char *buf, int len /* = 23+1 */) const #endif /* End ktm2.c */