strftime.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:12k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * strftime.c --
  3.  *
  4.  * This file contains a modified version of the BSD 4.4 strftime
  5.  * function.
  6.  *
  7.  * This file is a modified version of the strftime.c file from the BSD 4.4
  8.  * source.  See the copyright notice below for details on redistribution
  9.  * restrictions.  The "license.terms" file does not apply to this file.
  10.  *
  11.  * Changes 2002 Copyright (c) 2002 ActiveState Corporation.
  12.  *
  13.  * RCS: @(#) $Id: strftime.c,v 1.10.2.3 2005/11/04 18:18:04 kennykb Exp $
  14.  */
  15. /*
  16.  * Copyright (c) 1989 The Regents of the University of California.
  17.  * All rights reserved.
  18.  *
  19.  * Redistribution and use in source and binary forms, with or without
  20.  * modification, are permitted provided that the following conditions
  21.  * are met:
  22.  * 1. Redistributions of source code must retain the above copyright
  23.  *    notice, this list of conditions and the following disclaimer.
  24.  * 2. Redistributions in binary form must reproduce the above copyright
  25.  *    notice, this list of conditions and the following disclaimer in the
  26.  *    documentation and/or other materials provided with the distribution.
  27.  * 3. All advertising materials mentioning features or use of this software
  28.  *    must display the following acknowledgement:
  29.  * This product includes software developed by the University of
  30.  * California, Berkeley and its contributors.
  31.  * 4. Neither the name of the University nor the names of its contributors
  32.  *    may be used to endorse or promote products derived from this software
  33.  *    without specific prior written permission.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  36.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  39.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  40.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  41.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  42.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  43.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  44.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  45.  * SUCH DAMAGE.
  46.  */
  47. #if defined(LIBC_SCCS)
  48. static char *rcsid = "$Id: strftime.c,v 1.10.2.3 2005/11/04 18:18:04 kennykb Exp $";
  49. #endif /* LIBC_SCCS */
  50. #include <time.h>
  51. #include <string.h>
  52. #include <locale.h>
  53. #include "tclInt.h"
  54. #include "tclPort.h"
  55. #define TM_YEAR_BASE   1900
  56. #define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
  57. typedef struct {
  58.     const char *abday[7];
  59.     const char *day[7];
  60.     const char *abmon[12];
  61.     const char *mon[12];
  62.     const char *am_pm[2];
  63.     const char *d_t_fmt;
  64.     const char *d_fmt;
  65.     const char *t_fmt;
  66.     const char *t_fmt_ampm;
  67. } _TimeLocale;
  68. /*
  69.  * This is the C locale default.  On Windows, if we wanted to make this
  70.  * localized, we would use GetLocaleInfo to get the correct values.
  71.  * It may be acceptable to do localization of month/day names, as the
  72.  * numerical values would be considered the locale-independent versions.
  73.  */
  74. static const _TimeLocale _DefaultTimeLocale = 
  75. {
  76.     {
  77. "Sun","Mon","Tue","Wed","Thu","Fri","Sat",
  78.     },
  79.     {
  80. "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  81. "Friday", "Saturday"
  82.     },
  83.     {
  84. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  85. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  86.     },
  87.     {
  88. "January", "February", "March", "April", "May", "June", "July",
  89. "August", "September", "October", "November", "December"
  90.     },
  91.     {
  92. "AM", "PM"
  93.     },
  94.     "%a %b %d %H:%M:%S %Y",
  95.     "%m/%d/%y",
  96.     "%H:%M:%S",
  97.     "%I:%M:%S %p"
  98. };
  99. static const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale;
  100. static int isGMT;
  101. static size_t gsize;
  102. static char *pt;
  103. static int  _add _ANSI_ARGS_((const char* str));
  104. static int _conv _ANSI_ARGS_((int n, int digits, int pad));
  105. static int _secs _ANSI_ARGS_((const struct tm *t));
  106. static size_t _fmt _ANSI_ARGS_((const char *format,
  107.     const struct tm *t));
  108. static int ISO8601Week _ANSI_ARGS_((CONST struct tm* t, int *year ));
  109. size_t
  110. TclpStrftime(s, maxsize, format, t, useGMT)
  111.     char *s;
  112.     size_t maxsize;
  113.     const char *format;
  114.     const struct tm *t;
  115.     int useGMT;
  116. {
  117.     if (format[0] == '%' && format[1] == 'Q') {
  118. /* Format as a stardate */
  119. sprintf(s, "Stardate %2d%03d.%01d",
  120. (((t->tm_year + TM_YEAR_BASE) + 377) - 2323),
  121. (((t->tm_yday + 1) * 1000) /
  122. (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))),
  123. (((t->tm_hour * 60) + t->tm_min)/144));
  124. return(strlen(s));
  125.     }
  126.     isGMT = useGMT;
  127.     /*
  128.      * We may be able to skip this for useGMT, but it should be harmless.
  129.      * -- hobbs
  130.      */
  131.     tzset();
  132.     pt = s;
  133.     if ((gsize = maxsize) < 1)
  134. return(0);
  135.     if (_fmt(format, t)) {
  136. *pt = '';
  137. return(maxsize - gsize);
  138.     }
  139.     return(0);
  140. }
  141. #define SUN_WEEK(t) (((t)->tm_yday + 7 - 
  142. ((t)->tm_wday)) / 7)
  143. #define MON_WEEK(t) (((t)->tm_yday + 7 - 
  144. ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7)
  145. static size_t
  146. _fmt(format, t)
  147.     const char *format;
  148.     const struct tm *t;
  149. {
  150. #ifdef WIN32
  151. #define BUF_SIZ 256
  152.     TCHAR buf[BUF_SIZ];
  153.     SYSTEMTIME syst = {
  154. t->tm_year + 1900,
  155. t->tm_mon + 1,
  156. t->tm_wday,
  157. t->tm_mday,
  158. t->tm_hour,
  159. t->tm_min,
  160. t->tm_sec,
  161. 0,
  162.     };
  163. #endif
  164.     for (; *format; ++format) {
  165. if (*format == '%') {
  166.     ++format;
  167.     if (*format == 'E') {
  168. /* Alternate Era */
  169. ++format;
  170.     } else if (*format == 'O') {
  171. /* Alternate numeric symbols */
  172. ++format;
  173.     }
  174.     switch(*format) {
  175. case '':
  176.     --format;
  177.     break;
  178. case 'A':
  179.     if (t->tm_wday < 0 || t->tm_wday > 6)
  180. return(0);
  181.     if (!_add(_CurrentTimeLocale->day[t->tm_wday]))
  182. return(0);
  183.     continue;
  184. case 'a':
  185.     if (t->tm_wday < 0 || t->tm_wday > 6)
  186. return(0);
  187.     if (!_add(_CurrentTimeLocale->abday[t->tm_wday]))
  188. return(0);
  189.     continue;
  190. case 'B':
  191.     if (t->tm_mon < 0 || t->tm_mon > 11)
  192. return(0);
  193.     if (!_add(_CurrentTimeLocale->mon[t->tm_mon]))
  194. return(0);
  195.     continue;
  196. case 'b':
  197. case 'h':
  198.     if (t->tm_mon < 0 || t->tm_mon > 11)
  199. return(0);
  200.     if (!_add(_CurrentTimeLocale->abmon[t->tm_mon]))
  201. return(0);
  202.     continue;
  203. case 'C':
  204.     if (!_conv((t->tm_year + TM_YEAR_BASE) / 100,
  205.     2, '0'))
  206. return(0);
  207.     continue;
  208. case 'D':
  209.     if (!_fmt("%m/%d/%y", t))
  210. return(0);
  211.     continue;
  212. case 'd':
  213.     if (!_conv(t->tm_mday, 2, '0'))
  214. return(0);
  215.     continue;
  216. case 'e':
  217.     if (!_conv(t->tm_mday, 2, ' '))
  218. return(0);
  219.     continue;
  220.         case 'g':
  221.     {
  222. int year;
  223. ISO8601Week( t, &year );
  224. if ( !_conv( year%100, 2, '0' ) ) {
  225.     return( 0 );
  226. }
  227. continue;
  228.     }
  229.         case 'G':
  230.     {
  231. int year;
  232. ISO8601Week( t, &year );
  233. if ( !_conv( year, 4, '0' ) ) {
  234.     return( 0 );
  235. }
  236. continue;
  237.     }
  238. case 'H':
  239.     if (!_conv(t->tm_hour, 2, '0'))
  240. return(0);
  241.     continue;
  242. case 'I':
  243.     if (!_conv(t->tm_hour % 12 ?
  244.     t->tm_hour % 12 : 12, 2, '0'))
  245. return(0);
  246.     continue;
  247. case 'j':
  248.     if (!_conv(t->tm_yday + 1, 3, '0'))
  249. return(0);
  250.     continue;
  251. case 'k':
  252.     if (!_conv(t->tm_hour, 2, ' '))
  253. return(0);
  254.     continue;
  255. case 'l':
  256.     if (!_conv(t->tm_hour % 12 ?
  257.     t->tm_hour % 12: 12, 2, ' '))
  258. return(0);
  259.     continue;
  260. case 'M':
  261.     if (!_conv(t->tm_min, 2, '0'))
  262. return(0);
  263.     continue;
  264. case 'm':
  265.     if (!_conv(t->tm_mon + 1, 2, '0'))
  266. return(0);
  267.     continue;
  268. case 'n':
  269.     if (!_add("n"))
  270. return(0);
  271.     continue;
  272. case 'p':
  273.     if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12]))
  274. return(0);
  275.     continue;
  276. case 'R':
  277.     if (!_fmt("%H:%M", t))
  278. return(0);
  279.     continue;
  280. case 'r':
  281.     if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t))
  282. return(0);
  283.     continue;
  284. case 'S':
  285.     if (!_conv(t->tm_sec, 2, '0'))
  286. return(0);
  287.     continue;
  288. case 's':
  289.     if (!_secs(t))
  290. return(0);
  291.     continue;
  292. case 'T':
  293.     if (!_fmt("%H:%M:%S", t))
  294. return(0);
  295.     continue;
  296. case 't':
  297.     if (!_add("t"))
  298. return(0);
  299.     continue;
  300. case 'U':
  301.     if (!_conv(SUN_WEEK(t), 2, '0'))
  302. return(0);
  303.     continue;
  304. case 'u':
  305.     if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0'))
  306. return(0);
  307.     continue;
  308. case 'V':
  309. {
  310.     int week = ISO8601Week( t, NULL );
  311.     if (!_conv(week, 2, '0'))
  312. return(0);
  313.     continue;
  314. }
  315. case 'W':
  316.     if (!_conv(MON_WEEK(t), 2, '0'))
  317. return(0);
  318.     continue;
  319. case 'w':
  320.     if (!_conv(t->tm_wday, 1, '0'))
  321. return(0);
  322.     continue;
  323. #ifdef WIN32
  324. /*
  325.  * To properly handle the localized time routines on Windows,
  326.  * we must make use of the special localized calls.
  327.  */
  328. case 'c':
  329.     if (!GetDateFormat(LOCALE_USER_DEFAULT,
  330.        DATE_LONGDATE | LOCALE_USE_CP_ACP,
  331.        &syst, NULL, buf, BUF_SIZ)
  332. || !_add(buf)
  333. || !_add(" ")) {
  334. return(0);
  335.     }
  336.     /*
  337.      * %c is created with LONGDATE + " " + TIME on Windows,
  338.      * so continue to %X case here.
  339.      */
  340. case 'X':
  341.     if (!GetTimeFormat(LOCALE_USER_DEFAULT,
  342.        LOCALE_USE_CP_ACP,
  343.        &syst, NULL, buf, BUF_SIZ)
  344. || !_add(buf)) {
  345. return(0);
  346.     }
  347.     continue;
  348. case 'x':
  349.     if (!GetDateFormat(LOCALE_USER_DEFAULT,
  350.        DATE_SHORTDATE | LOCALE_USE_CP_ACP,
  351.        &syst, NULL, buf, BUF_SIZ)
  352. || !_add(buf)) {
  353. return(0);
  354.     }
  355.     continue;
  356. #else
  357. case 'c':
  358.     if (!_fmt(_CurrentTimeLocale->d_t_fmt, t))
  359. return(0);
  360.     continue;
  361. case 'x':
  362.     if (!_fmt(_CurrentTimeLocale->d_fmt, t))
  363. return(0);
  364.     continue;
  365. case 'X':
  366.     if (!_fmt(_CurrentTimeLocale->t_fmt, t))
  367. return(0);
  368.     continue;
  369. #endif
  370. case 'y':
  371.     if (!_conv((t->tm_year + TM_YEAR_BASE) % 100,
  372.     2, '0'))
  373. return(0);
  374.     continue;
  375. case 'Y':
  376.     if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0'))
  377. return(0);
  378.     continue;
  379. case 'Z': {
  380.     char *name = (isGMT ? "GMT" : TclpGetTZName(t->tm_isdst));
  381.     int wrote;
  382.     Tcl_UtfToExternal(NULL, NULL, name, -1, 0, NULL,
  383.       pt, gsize, NULL, &wrote, NULL);
  384.     pt += wrote;
  385.     gsize -= wrote;
  386.     continue;
  387. }
  388. case '%':
  389.     /*
  390.      * X311J/88-090 (4.12.3.5): if conversion char is
  391.      * undefined, behavior is undefined.  Print out the
  392.      * character itself as printf(3) does.
  393.      */
  394. default:
  395.     break;
  396.     }
  397. }
  398. if (!gsize--)
  399.     return(0);
  400. *pt++ = *format;
  401.     }
  402.     return(gsize);
  403. }
  404. static int
  405. _secs(t)
  406.     const struct tm *t;
  407. {
  408.     static char buf[15];
  409.     register time_t s;
  410.     register char *p;
  411.     struct tm tmp;
  412.     /* Make a copy, mktime(3) modifies the tm struct. */
  413.     tmp = *t;
  414.     s = mktime(&tmp);
  415.     for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
  416. *p-- = (char)(s % 10 + '0');
  417.     return(_add(++p));
  418. }
  419. static int
  420. _conv(n, digits, pad)
  421.     int n, digits;
  422.     int pad;
  423. {
  424.     static char buf[10];
  425.     register char *p;
  426.     p = buf + sizeof( buf ) - 1;
  427.     *p-- = '';
  428.     if ( n == 0 ) {
  429. *p-- = '0'; --digits;
  430.     } else {
  431. for (; n > 0 && p > buf; n /= 10, --digits)
  432.     *p-- = (char)(n % 10 + '0');
  433.     }
  434.     while (p > buf && digits-- > 0)
  435. *p-- = (char) pad;
  436.     return(_add(++p));
  437. }
  438. static int
  439. _add(str)
  440.     const char *str;
  441. {
  442.     for (;; ++pt, --gsize) {
  443. if (!gsize)
  444.     return(0);
  445. if (!(*pt = *str++))
  446.     return(1);
  447.     }
  448. }
  449. static int
  450. ISO8601Week( t, year )
  451.     CONST struct tm* t;
  452.     int* year;
  453. {
  454.     /* Find the day-of-year of the Thursday in
  455.      * the week in question. */
  456.     
  457.     int ydayThursday;
  458.     int week;
  459.     if ( t->tm_wday == 0 ) {
  460. ydayThursday = t->tm_yday - 3;
  461.     } else {
  462. ydayThursday = t->tm_yday - t->tm_wday + 4;
  463.     }
  464.     
  465.     if ( ydayThursday < 0 ) {
  466. /* This is the last week of the previous year. */
  467. if ( IsLeapYear(( t->tm_year + TM_YEAR_BASE - 1 )) ) {
  468.     ydayThursday += 366;
  469. } else {
  470.     ydayThursday += 365;
  471. }
  472. week = ydayThursday / 7 + 1;
  473. if ( year != NULL ) {
  474.     *year = t->tm_year + 1899;
  475. }
  476.     } else if ( ( IsLeapYear(( t -> tm_year + TM_YEAR_BASE ))
  477.   && ydayThursday >= 366 )
  478. || ( !IsLeapYear(( t -> tm_year
  479.    + TM_YEAR_BASE ))
  480.      && ydayThursday >= 365 ) ) {
  481. /* This is week 1 of the following year */
  482. week = 1;
  483. if ( year != NULL ) {
  484.     *year = t->tm_year + 1901;
  485. }
  486.     } else {
  487. week = ydayThursday / 7 + 1;
  488. if ( year != NULL ) {
  489.     *year = t->tm_year + 1900;
  490. }
  491.     }
  492.     return week;
  493.     
  494. }