strftime.c
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:19k
开发平台:

MultiPlatform

  1. /* strftime.c - strftime file for time  */
  2. /* Copyright 1991-1999 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01l,05aug99,cno  atoi calls need byte for null termination (SPR28245)
  7. 01k,23jul00,jrp  SPR 27606 End of DST miscalculated.
  8. 01j,08jun99,map  fixed 12hr reporting (SPR# 7499)
  9. 01i,20jan97,dbt  modified comment concerning seconds (SPR #4436).
  10. 01h,04oct96,dbt  reworked the fix for SPR #7277.
  11. 01g,03oct96,dbt  use memcpy with 'strlen + 1' instead of 'strlen' (SPR #7277)
  12. 01f,27jun96,dbt  corrected __getDstInfo() (spr 2521)
  13.    Updated copyright.
  14. 01g,10feb95,rhp  internal doc tweak from ansiTime.c
  15. 01f,15sep94,rhp  fixed TIMEZONE example in comment (related to SPR #3490)
  16. 01e,17aug93,dvs  changed TIME to TIMEO to fix conflicting defines (SPR #2249)
  17. 01d,05feb93,jdi  documentation cleanup for 5.1.
  18. 01c,20sep92,smb  documentation additions
  19. 01b,26jul92,rrr  fixed decl of __weekOfYear to compile on mips.
  20. 01a,25jul92,smb  written.
  21. */
  22. /*  
  23. DESCRIPTION  
  24.   
  25. INCLUDE FILE: time.h, stdlib.h, string.h, locale.h
  26.    
  27. SEE ALSO: American National Standard X3.159-1989 
  28. NOMANUAL
  29. */
  30. #include "vxWorks.h"
  31. #include "string.h"
  32. #include "stdlib.h"
  33. #include "locale.h"
  34. #include "private/timeP.h"
  35. extern TIMELOCALE * __loctime; /* time locale information */
  36. /* LOCAL */
  37. LOCAL size_t strftime_r (char *, size_t, const char *,
  38.  const struct tm *, TIMELOCALE *);
  39. LOCAL void   __generateTime (char *, const struct tm *,
  40.              TIMELOCALE *, int *, const char *);
  41. LOCAL void   __getDay (char *, int, int, TIMELOCALE *, int *);
  42. LOCAL void   __getMonth (char *, int, int, TIMELOCALE *, int *);
  43. LOCAL void   __getLocale (char *, int, const struct tm *, TIMELOCALE *, int *);
  44. LOCAL void   __intToStr (char *, int, int);
  45. LOCAL int    __weekOfYear (int, int, int);
  46. /*******************************************************************************
  47. *
  48. * strftime - convert broken-down time into a formatted string (ANSI)
  49. *
  50. * This routine formats the broken-down time in <tptr> based on the conversion
  51. * specified in the string <format>, and places the result in the string <s>.
  52. *
  53. * The format is a multibyte character sequence, beginning and ending in its
  54. * initial state.  The <format> string consists of zero or more conversion
  55. * specifiers and ordinary multibyte characters.  A conversion specifier
  56. * consists of a % character followed by a character that determines the
  57. * behavior of the conversion.  All ordinary multibyte characters (including
  58. * the terminating NULL character) are copied unchanged to the array.  If
  59. * copying takes place between objects that overlap, the behavior is
  60. * undefined.  No more than <n> characters are placed into the array.
  61. *
  62. * Each conversion specifier is replaced by appropriate characters as 
  63. * described in the following list.  The appropriate characters are determined 
  64. * by the LC_TIME category of the current locale and by the values contained 
  65. * in the structure pointed to by <tptr>.
  66. *
  67. * .iP %a
  68. * the locale's abbreviated weekday name.
  69. * .iP %A
  70. * the locale's full weekday name.
  71. * .iP %b
  72. * the locale's abbreviated month name.
  73. * .iP %B
  74. * the locale's full month name.
  75. * .iP %c
  76. * the locale's appropriate date and time representation.
  77. * .iP %d
  78. * the day of the month as decimal number (01-31).
  79. * .iP %H
  80. * the hour (24-hour clock) as a decimal number (00-23).
  81. * .iP %I
  82. * the hour (12-hour clock) as a decimal number (01-12).
  83. * .iP %j
  84. * the day of the year as decimal number (001-366).
  85. * .iP %m
  86. * the month as a decimal number (01-12).
  87. * .iP %M
  88. * the minute as a decimal number (00-59).
  89. * .iP %P
  90. * the locale's equivalent of the AM/PM 
  91. * designations associated with a 12-hour clock.
  92. * .iP %S
  93. * the second as a decimal number (00-59).
  94. * .iP %U
  95. * the week number of the year (first Sunday
  96. * as the first day of week 1) as a decimal number (00-53).
  97. * .iP %w
  98. * the weekday as a decimal number (0-6), where Sunday is 0.
  99. * .iP %W
  100. * the week number of the year (the first Monday
  101. * as the first day of week 1) as a decimal number (00-53).
  102. * .iP %x
  103. * the locale's appropriate date representation.
  104. * .iP %X
  105. * the locale's appropriate time representation.
  106. * .iP %y
  107. * the year without century as a decimal number (00-99).
  108. * .iP %Y
  109. * the year with century as a decimal number.
  110. * .iP %Z
  111. * the time zone name or abbreviation, or by no
  112. * characters if no time zone is determinable.
  113. * .iP %%
  114. * %.
  115. * .LP
  116. *
  117. * For any other conversion specifier, the behavior is undefined.
  118. *
  119. * INCLUDE FILES: time.h
  120. *
  121. * RETURNS:
  122. * The number of characters in <s>, not including the terminating null
  123. * character -- or zero if the number of characters in <s>, including the null
  124. * character, is more than <n> (in which case the contents of <s> are
  125. * indeterminate).
  126. */
  127. size_t strftime
  128.     (
  129.     char *            s, /* string array */
  130.     size_t            n, /* maximum size of array */
  131.     const char *      format, /* format of output string */
  132.     const struct tm * tptr /* broken-down time */
  133.     )
  134.     {
  135.     return (strftime_r (s, n, format, tptr, __loctime));
  136.     }
  137. /*******************************************************************************
  138. *
  139. * strftime_r - format time into a string (POSIX)
  140. *
  141. * Re-entrant version of strftime().
  142. *
  143. * RETURNS:
  144. */
  145. LOCAL size_t strftime_r
  146.     (
  147.     char *            bufHd, /* string array */
  148.     size_t            bufMaxSz, /* maximum size of array */
  149.     const char *      fmtHd, /* format of output string */
  150.     const struct tm * tmptr,  /* broken-down time */
  151.     TIMELOCALE *      timeInfo /* locale information */
  152.     )
  153.     {
  154.     const char *      fmt = fmtHd;
  155.     char *            buffer = bufHd;
  156.     char              addOn[MaxBufferSize];
  157.     int               bufLen = 0;
  158.     int               bufszNow = 0;
  159.     
  160.     FOREVER
  161.         {
  162.         while ((*fmt != '%') && (bufszNow != bufMaxSz) && (*fmt != EOS))
  163.     {
  164.          bufszNow++; 
  165.     *buffer++ = *fmt++;
  166.     }
  167.         if (bufszNow == bufMaxSz) 
  168.     break;
  169.         if (*fmt++ != EOS)
  170.     {
  171.     __generateTime (addOn, tmptr, timeInfo, &bufLen, fmt);
  172.     if (bufLen >= 0)
  173.         {
  174.         if (bufMaxSz > (bufszNow + bufLen))
  175.             {
  176.             memcpy (buffer, addOn, bufLen);
  177.       bufszNow += bufLen;
  178.     buffer += bufLen;
  179.     fmt++;
  180.     } /* endif */
  181.         else 
  182.     {
  183.     memcpy (buffer, addOn, bufMaxSz - bufszNow);
  184.     buffer += (bufMaxSz - bufszNow);
  185.     bufszNow = bufMaxSz;
  186.     break;
  187.     }
  188. }
  189.     else 
  190.         { /* process format strings */
  191. *(addOn + abs (bufLen)) = EOS; 
  192. /* This is recursive - but should recurse ONCE only */
  193.         bufLen = (int) strftime_r (buffer, 
  194.    bufMaxSz - bufszNow, 
  195.    addOn, 
  196.    tmptr, 
  197.    timeInfo);
  198.         buffer += bufLen;
  199.         bufszNow += bufLen;
  200.         fmt++;
  201.         } /* endif */
  202.      }
  203.  else break;
  204.          } /* end forever */
  205.     *buffer = EOS;
  206.     return (bufszNow);
  207.     }
  208. /*******************************************************************************
  209. *
  210. * __generateTime - generate a string representing the format indicator.
  211. *
  212. * Internal routine
  213. *
  214. * RETURNS:
  215. * NOMANUAL
  216. */
  217. LOCAL void __generateTime
  218.     (
  219.     char *            addOn, /* string buffer */
  220.     const struct tm * tmptr,  /* broken-down time */
  221.     TIMELOCALE *      timeInfo, /* locale information */
  222.     int *             pnum, /* position number for strftime string */
  223.     const char *      fmt /* format to be decoded */
  224.     )
  225.     {
  226.     switch (*fmt) 
  227.      {
  228.         case 'a': /* day */
  229.          __getDay (addOn, tmptr->tm_wday, ABBR, timeInfo, pnum); 
  230.          break;
  231.         case 'A': /* day */
  232.          __getDay (addOn, tmptr->tm_wday, FULL, timeInfo, pnum); 
  233.          break;
  234.         case 'b': /* month */
  235.          __getMonth (addOn, tmptr->tm_mon, ABBR, timeInfo, pnum); 
  236.          break;
  237.         case 'B': /* month */
  238.          __getMonth (addOn, tmptr->tm_mon, FULL, timeInfo, pnum);
  239.          break;
  240.         case 'c':  /* date and time */
  241.          __getLocale (addOn, DATETIME, tmptr, timeInfo, pnum);
  242.          *pnum = -*pnum;
  243.          break;
  244.         case 'd':  /* day of month */
  245.          __intToStr (addOn, tmptr->tm_mday, *pnum = 2); 
  246.          break;
  247.         case 'H': /* hour */
  248.          __intToStr (addOn, tmptr->tm_hour, *pnum = 2); 
  249.          break;
  250.         case 'I': /* hour */
  251.             __intToStr (addOn, ((tmptr->tm_hour % 12) ?
  252.                                 (tmptr->tm_hour % 12) : 12), *pnum = 2);
  253.          break;
  254.         case 'j': /* day of year */
  255.          __intToStr (addOn, tmptr->tm_yday + 1, *pnum = 3); 
  256.          break;
  257.         case 'm': /* month */
  258.          __intToStr (addOn, tmptr->tm_mon + 1, *pnum = 2); 
  259.          break;
  260.         case 'M': /* minute */
  261.          __intToStr (addOn, tmptr->tm_min, *pnum = 2); 
  262.          break;
  263.         case 'p': /* AP/PM */
  264.          __getLocale (addOn, AMPM, tmptr, timeInfo, pnum);
  265.          break;
  266.         case 'S': /* second */
  267.          __intToStr (addOn, tmptr->tm_sec, *pnum = 2); 
  268.             break;
  269.         case 'U': /* week number */
  270.             __intToStr (addOn, 
  271. __weekOfYear(TM_SUNDAY, tmptr->tm_wday, tmptr->tm_yday),
  272. *pnum = 2);
  273.          break;
  274.         case 'w': /* weekday */
  275.          __intToStr (addOn, tmptr->tm_wday, *pnum = 1); 
  276.          break;
  277.         case 'W': /* week number */
  278.          __intToStr (addOn, 
  279.              __weekOfYear(TM_MONDAY, tmptr->tm_wday, tmptr->tm_yday),
  280.                       *pnum = 2);
  281.          break;
  282.         case 'x': /* date */
  283.          __getLocale (addOn, DATE, tmptr, timeInfo, pnum);
  284.          *pnum = -*pnum;
  285.          break;
  286.         case 'X': /* time */
  287.          __getLocale (addOn, TIMEO, tmptr, timeInfo, pnum);
  288.             *pnum = -*pnum;
  289.          break;
  290.         case 'y': /* year */
  291.          __intToStr (addOn, (tmptr->tm_year % CENTURY), *pnum = 2);
  292.          break;
  293.         case 'Y': /* year */
  294.          __intToStr (addOn, (tmptr->tm_year + TM_YEAR_BASE), *pnum = 4);
  295.          break;
  296.         case 'Z': /* zone */
  297.          __getLocale (addOn, ZONE, tmptr, timeInfo, pnum);
  298.          break;
  299.         case '%': /* % */
  300.          memcpy (addOn, CHAR_FROM_CONST ("%"), 1); 
  301.     *pnum = 1; 
  302.          break;
  303.         default:
  304.          *pnum = 0;
  305.          break;
  306.      }
  307.     }
  308. /*******************************************************************************
  309. *
  310. * __weekOfYear - calulate week of year given julian day and week day.
  311. *
  312. * Internal routine
  313. * The <start> determins whether the week starts on Sunday or Monday.
  314. *
  315. * RETURNS: week of year 
  316. * NOMANUAL
  317. */
  318. LOCAL int __weekOfYear
  319.     (
  320.     int start,  /* either TM_SUNDAY or TM_MONDAY */
  321.     int wday,   /* days since sunday */
  322.     int yday    /* days since Jan 1 */
  323.     )
  324.     {
  325.     wday = (wday - start + DAYSPERWEEK) % DAYSPERWEEK;
  326.     return ((yday - wday + 12) / DAYSPERWEEK - 1);
  327.     }
  328. /*******************************************************************************
  329. *
  330. * __getLocale - determine locale information given an indicator or the
  331. *    type of information needed.
  332. *
  333. * Internal routine
  334. *
  335. * RETURNS: void
  336. * NOMANUAL
  337. */
  338. LOCAL void __getLocale
  339.     (
  340.     char *       buffer, /* buffer for the string */
  341.     int               desc,  /* descriptor */
  342.     const struct tm * tmptr,  /* broken-down time */
  343.     TIMELOCALE *      timeInfo, /* locale information */
  344.     int *             size /* size of array returned */
  345.     )
  346.     {
  347.     char *       p = NULL;
  348.     char        zoneBuf [sizeof (ZONEBUFFER)];
  349.     switch(desc)
  350.      {
  351.         case DATETIME:
  352.          p = timeInfo->_Format [DATETIME]; 
  353.             break;
  354.         case DATE:
  355.          p = timeInfo->_Format [DATE]; 
  356.             break;
  357.         case TIMEO:
  358.          p = timeInfo->_Format [TIMEO]; 
  359.             break;
  360.         case AMPM:
  361.          p = timeInfo->_Ampm [(tmptr->tm_hour < 12) ? 0 : 1];
  362.             break;
  363.         case ZONE:
  364.          (void) __getZoneInfo (zoneBuf, NAME, timeInfo);
  365.     p = zoneBuf;
  366.             break;
  367.      }
  368.     *size = strlen (p);
  369.     strcpy(buffer, p);
  370.     }
  371. /*******************************************************************************
  372. *
  373. * __intToStr - convert an integer into a string of <sz> size with leading 
  374. *   zeroes if neccessary.
  375. *
  376. * Internal routine
  377. *
  378. * RETURNS: void
  379. * NOMANUAL
  380. */
  381. LOCAL void __intToStr
  382.     (
  383.     char * buffer, /* buffer for return string */
  384.     int    number, /* the number to be converted */
  385.     int    size /* size of the string, maximum length of 4 */
  386.     )
  387.     {
  388.     if (number < 0) 
  389. number = 0;
  390.     for (buffer += size; 0 <= --size; number /= 10)
  391. {
  392. *--buffer = number % 10 + '0';
  393. }
  394.     }
  395. /*******************************************************************************
  396. *
  397. * __getDay - determine the locale representation of the day of the week
  398. *
  399. * RETURNS: void
  400. * NOMANUAL
  401. */
  402. LOCAL void __getDay
  403.     (
  404.     char *       buffer, /* buffer for return string */
  405.     int          index,  /* integer representation of day of the week */
  406.     int          abbr, /* abbrievation or full spelling */
  407.     TIMELOCALE * timeInfo, /* locale information */
  408.     int *        size /* size of the string returned */
  409.     )
  410.     {
  411.     char *       dayStr;
  412.     index += (abbr == ABBR) ? 0 : DAYSPERWEEK;
  413.     *size = strlen (dayStr = timeInfo->_Days [index]);
  414.     strcpy (buffer, dayStr);
  415.     }
  416. /*******************************************************************************
  417. *
  418. * __getMonth - determine the locale representation of the month of the year 
  419. *
  420. * RETURNS: void
  421. * NOMANUAL
  422. */
  423. LOCAL void __getMonth
  424.     (
  425.     char *       buffer, /* buffer for return string */
  426.     int          index,  /* integer representation of month of year */
  427.     int          abbr, /* abbrievation or full spelling */
  428.     TIMELOCALE * timeInfo, /* locale information */
  429.     int *        size /* size of the string returned */
  430.     )
  431.     {
  432.     char *       monStr;
  433.     index += (abbr == ABBR) ? 0 : MONSPERYEAR;
  434.     *size = strlen (monStr = timeInfo->_Months [index]);
  435.     strcpy (buffer, monStr);
  436.     }
  437. /******************************************************************************
  438. *
  439. *  __getDstInfo - determins whether day light savings is in effect.
  440. *
  441. * TIMEZONE is of the form 
  442. *     <name of zone>::<time in minutes from UTC>:<daylight start>:<daylight end>
  443. *
  444. * daylight information is expressed as mmddhh ie. month:day:hour
  445. *
  446. * e.g. UTC::0:040102:100102
  447. *
  448. * RETURNS: FALSE if not on, TRUE otherwise.
  449. * NOMANUAL
  450. */
  451. int __getDstInfo
  452.     (
  453.     struct tm *  timeNow, 
  454.     TIMELOCALE * timeInfo
  455.     )
  456.     {
  457.     char *       start = NULL;
  458.     char *       end = NULL;
  459.     char *       dummy = NULL;
  460.     char *       envInfo = NULL;
  461.     char *       last = "";
  462.     int          monStart = 0;
  463.     int          monEnd   = 0;
  464.     int          dayStart = 0;
  465.     int          dayEnd   = 0;
  466.     int          hrStart  = 0;
  467.     int          hrEnd    = 0;
  468.     char         numstr [4];   /* SPR 28245: changed from 2 to 4 chars */
  469.     char         buffer [sizeof (ZONEBUFFER)];
  470.     /* Is daylight saving in effect? '0' NO; '>0' YES; '<0' don't know */
  471.     /* commented out (SPR #2521)
  472.     if (timeNow->tm_isdst != -1) 
  473.         return (FALSE);
  474.     */
  475.     /* Is dst information stored in environmental variables */
  476.     if ((envInfo = getenv("TIMEZONE")) != NULL) 
  477.      {
  478. strcpy (buffer, envInfo);
  479.      dummy = strtok_r (buffer, ":", &last);  /* next */
  480.      dummy = strtok_r (NULL, ":", &last);    /* next */
  481.      /* commented out (SPR #2521) */
  482. /*      dummy = strtok_r (NULL, ":", &last);    /@ next */
  483.      start = strtok_r (NULL, ":", &last);  /* start time */
  484.      end = strtok_r (NULL, ":", &last);    /* end time */
  485.      }
  486.     else
  487.      {
  488.      /* Is dst information stored in the locale tables */
  489.      start = timeInfo->_Isdst[DSTON];
  490.      end = timeInfo->_Isdst[DSTOFF];
  491.      if ((strcmp (start,"") == 0) || (strcmp (end,"") == 0))
  492.          return (FALSE);
  493.      }
  494.     if ((start == NULL) || (end == NULL)) 
  495.         return (FALSE);
  496.     /* analyze the dst information of the form 'mmddhh' */
  497.     bzero (numstr, sizeof (numstr));  /* clear numstr before null terminating */
  498.     monStart = (atoi (strncpy (numstr, start, 2))) - 1;        /*start month */
  499.     bzero (numstr, sizeof (numstr));  /* clear numstr before null terminating */
  500.     monEnd = atoi (strncpy (numstr, end, 2)) - 1;            /* end month */
  501.     if ((timeNow->tm_mon < monStart) || (timeNow->tm_mon > monEnd)) 
  502.      return (FALSE);
  503.     if ((timeNow->tm_mon == monStart) || (timeNow->tm_mon == monEnd))
  504.      {
  505.         bzero (numstr, sizeof (numstr));                    /* clear numstr */
  506.      dayStart = atoi (strncpy (numstr, start+2, 2));  /* start day */
  507.         bzero (numstr, sizeof (numstr));                    /* clear numstr */
  508.      dayEnd = atoi (strncpy (numstr, end+2, 2));      /* end day */
  509.      if (((timeNow->tm_mon == monStart) && (timeNow->tm_mday < dayStart)) || 
  510.          ((timeNow->tm_mon == monEnd) && (timeNow->tm_mday > dayEnd))) 
  511.          return (FALSE);
  512.      if (((timeNow->tm_mon == monStart) && (timeNow->tm_mday == dayStart)) ||
  513.          ((timeNow->tm_mon == monEnd) && (timeNow->tm_mday == dayEnd))) 
  514.          {
  515.             bzero (numstr, sizeof (numstr));                /* clear numstr */
  516.          hrStart = atoi (strncpy (numstr, start+4, 2));  /* hour */
  517.             bzero (numstr, sizeof (numstr));                /* clear numstr */
  518.          hrEnd = atoi (strncpy (numstr, end+4, 2));      /* hour */
  519.         /*
  520.          * SPR 27606.  DST requires a fallback when the local DST reaches
  521.          * the ending hour on the required date.  The timeNow structure
  522.          * holds the non-DST corrected time. Hence for the end of DST check
  523.          * we assume a DST corrected time (tm_hour+1) and test to see if the
  524.          * hour is greater than or *equal* to the ending hour
  525.          */
  526.          return ((((timeNow->tm_mon==monStart) &&
  527.           (timeNow->tm_mday==dayStart) &&
  528.           (timeNow->tm_hour < hrStart)) ||
  529.          ((timeNow->tm_mon == monEnd) &&
  530.           (timeNow->tm_mday==dayEnd) &&
  531.                  ((timeNow->tm_hour+1) >= hrEnd)))  /* SPR 27606 */
  532.         ? FALSE : TRUE);
  533.          }
  534.      }
  535.     return (TRUE);
  536.     }
  537. /******************************************************************************
  538. *
  539. *  __getZoneInfo - determins in minutes the time difference from UTC.
  540. *
  541. * If the environment variable TIMEZONE is set then the information is
  542. * retrieved from this variable, otherwise from the locale information.
  543. *
  544. * RETURNS: time in minutes from UTC.
  545. * NOMANUAL
  546. */
  547. void __getZoneInfo
  548.     (
  549.     char *       buffer,
  550.     int          option,  /* determine which part of zone information */
  551.     TIMELOCALE * timeInfo /* locale information */
  552.     )
  553.     {
  554.     char *       envInfo;
  555.     char *       limitStartPtr;
  556.     char *       limitEndPtr;
  557.     /* Time zone information from the environment variable */
  558.     envInfo = getenv ("TIMEZONE");
  559.      if ((envInfo != NULL) && (strcmp (envInfo, "") != 0)) 
  560.      {
  561. limitEndPtr = strpbrk (envInfo, ":");
  562. if (option == NAME)
  563.     {
  564.     strcpy (buffer, envInfo);
  565.     *(buffer + (limitEndPtr - envInfo)) = EOS;
  566.     return;
  567.     }
  568. limitStartPtr = limitEndPtr + 1;
  569. limitEndPtr = strpbrk (limitStartPtr, ":"); 
  570. if (option == NAME2)
  571.     {
  572.     strcpy (buffer, limitStartPtr);
  573.     *(buffer + (limitEndPtr - limitStartPtr)) = EOS;
  574.     return;
  575.     }
  576. limitStartPtr = limitEndPtr + 1;
  577. limitEndPtr = strpbrk (limitStartPtr, ":"); 
  578. if (option == TIMEOFFSET)
  579.     {
  580.     strcpy (buffer, limitStartPtr);
  581.     if (limitEndPtr != NULL)
  582.         *(buffer + (limitEndPtr - limitStartPtr)) = EOS;
  583.     return;
  584.     }
  585.      }
  586.     else
  587. {
  588.         /* Time zone information from the locale table */
  589.         if (strcmp (timeInfo->_Zone [option], "") != 0)
  590.     strcpy(buffer,timeInfo->_Zone [option]);
  591.         else  
  592.             *buffer = EOS;
  593.         }
  594.     }