00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include "ruby/ruby.h"
00051 #include "timev.h"
00052
00053 #ifndef GAWK
00054 #include <stdio.h>
00055 #include <ctype.h>
00056 #include <string.h>
00057 #include <time.h>
00058 #include <sys/types.h>
00059 #include <errno.h>
00060 #endif
00061 #if defined(TM_IN_SYS_TIME) || !defined(GAWK)
00062 #include <sys/types.h>
00063 #if HAVE_SYS_TIME_H
00064 #include <sys/time.h>
00065 #endif
00066 #endif
00067 #include <math.h>
00068
00069
00070 #define SYSV_EXT 1
00071 #define SUNOS_EXT 1
00072 #define POSIX2_DATE 1
00073 #define VMS_EXT 1
00074 #define MAILHEADER_EXT 1
00075 #define ISO_DATE_EXT 1
00076
00077 #if defined(ISO_DATE_EXT)
00078 #if ! defined(POSIX2_DATE)
00079 #define POSIX2_DATE 1
00080 #endif
00081 #endif
00082
00083 #if defined(POSIX2_DATE)
00084 #if ! defined(SYSV_EXT)
00085 #define SYSV_EXT 1
00086 #endif
00087 #if ! defined(SUNOS_EXT)
00088 #define SUNOS_EXT 1
00089 #endif
00090 #endif
00091
00092 #if defined(POSIX2_DATE)
00093 #define adddecl(stuff) stuff
00094 #else
00095 #define adddecl(stuff)
00096 #endif
00097
00098 #undef strchr
00099
00100 #if !defined __STDC__ && !defined _WIN32
00101 #define const
00102 static int weeknumber();
00103 adddecl(static int iso8601wknum();)
00104 static int weeknumber_v();
00105 adddecl(static int iso8601wknum_v();)
00106 #else
00107 static int weeknumber(const struct tm *timeptr, int firstweekday);
00108 adddecl(static int iso8601wknum(const struct tm *timeptr);)
00109 static int weeknumber_v(const struct vtm *vtm, int firstweekday);
00110 adddecl(static int iso8601wknum_v(const struct vtm *vtm);)
00111 #endif
00112
00113 #ifdef STDC_HEADERS
00114 #include <stdlib.h>
00115 #include <string.h>
00116 #else
00117 extern void *malloc();
00118 extern void *realloc();
00119 extern char *getenv();
00120 extern char *strchr();
00121 #endif
00122
00123 #define range(low, item, hi) max((low), min((item), (hi)))
00124
00125 #undef min
00126
00127
00128
00129 #ifndef __STDC__
00130 static inline int
00131 min(a, b)
00132 int a, b;
00133 #else
00134 static inline int
00135 min(int a, int b)
00136 #endif
00137 {
00138 return (a < b ? a : b);
00139 }
00140
00141 #undef max
00142
00143
00144
00145 #ifndef __STDC__
00146 static inline int
00147 max(a, b)
00148 int a, b;
00149 #else
00150 static inline int
00151 max(int a, int b)
00152 #endif
00153 {
00154 return (a > b ? a : b);
00155 }
00156
00157 #ifdef NO_STRING_LITERAL_CONCATENATION
00158 #error No string literal concatenation
00159 #endif
00160
00161 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
00162 #define sub(x,y) (rb_funcall((x), '-', 1, (y)))
00163 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
00164 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
00165 #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
00166 #define mod(x,y) (rb_funcall((x), '%', 1, (y)))
00167
00168
00169
00170 static size_t
00171 rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, struct timespec *ts, int gmt)
00172 {
00173 const char *const endp = s + maxsize;
00174 const char *const start = s;
00175 const char *sp, *tp;
00176 auto char tbuf[100];
00177 long off;
00178 ptrdiff_t i;
00179 int w;
00180 long y;
00181 int precision, flags, colons;
00182 char padding;
00183 enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E};
00184 #define BIT_OF(n) (1U<<(n))
00185 #ifdef MAILHEADER_EXT
00186 int sign;
00187 #endif
00188
00189
00190 static const char days_l[][10] = {
00191 "Sunday", "Monday", "Tuesday", "Wednesday",
00192 "Thursday", "Friday", "Saturday",
00193 };
00194 static const char months_l[][10] = {
00195 "January", "February", "March", "April",
00196 "May", "June", "July", "August", "September",
00197 "October", "November", "December",
00198 };
00199 static const char ampm[][3] = { "AM", "PM", };
00200
00201 if (s == NULL || format == NULL || vtm == NULL || maxsize == 0)
00202 return 0;
00203
00204
00205 if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) {
00206 err:
00207 errno = ERANGE;
00208 return 0;
00209 }
00210
00211 for (; *format && s < endp - 1; format++) {
00212 #define FLAG_FOUND() do { \
00213 if (precision > 0 || flags & (BIT_OF(LOCALE_E)|BIT_OF(LOCALE_O))) \
00214 goto unknown; \
00215 } while (0)
00216 #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
00217 #define FILL_PADDING(i) do { \
00218 if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \
00219 NEEDS(precision); \
00220 memset(s, padding ? padding : ' ', precision - (i)); \
00221 s += precision - (i); \
00222 } \
00223 else { \
00224 NEEDS(i); \
00225 } \
00226 } while (0);
00227 #define FMT(def_pad, def_prec, fmt, val) \
00228 do { \
00229 int l; \
00230 if (precision <= 0) precision = (def_prec); \
00231 if (flags & BIT_OF(LEFT)) precision = 1; \
00232 l = snprintf(s, endp - s, \
00233 ((padding == '0' || (!padding && (def_pad) == '0')) ? "%0*"fmt : "%*"fmt), \
00234 precision, (val)); \
00235 if (l < 0) goto err; \
00236 s += l; \
00237 } while (0)
00238 #define STRFTIME(fmt) \
00239 do { \
00240 i = rb_strftime_with_timespec(s, endp - s, (fmt), vtm, timev, ts, gmt); \
00241 if (!i) return 0; \
00242 if (precision > i) {\
00243 NEEDS(precision); \
00244 memmove(s + precision - i, s, i);\
00245 memset(s, padding ? padding : ' ', precision - i); \
00246 s += precision; \
00247 }\
00248 else s += i; \
00249 } while (0)
00250 #define FMTV(def_pad, def_prec, fmt, val) \
00251 do { \
00252 VALUE tmp = (val); \
00253 if (FIXNUM_P(tmp)) { \
00254 FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \
00255 } \
00256 else { \
00257 VALUE args[2], result; \
00258 size_t l; \
00259 if (precision <= 0) precision = (def_prec); \
00260 if (flags & BIT_OF(LEFT)) precision = 1; \
00261 args[0] = INT2FIX(precision); \
00262 args[1] = (val); \
00263 if (padding == '0' || (!padding && (def_pad) == '0')) \
00264 result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \
00265 else \
00266 result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \
00267 l = strlcpy(s, StringValueCStr(result), endp-s); \
00268 if ((size_t)(endp-s) <= l) \
00269 goto err; \
00270 s += l; \
00271 } \
00272 } while (0)
00273
00274 if (*format != '%') {
00275 *s++ = *format;
00276 continue;
00277 }
00278 tp = tbuf;
00279 sp = format;
00280 precision = -1;
00281 flags = 0;
00282 padding = 0;
00283 colons = 0;
00284 again:
00285 switch (*++format) {
00286 case '\0':
00287 format--;
00288 goto unknown;
00289
00290 case '%':
00291 FILL_PADDING(1);
00292 *s++ = '%';
00293 continue;
00294
00295 case 'a':
00296 if (flags & BIT_OF(CHCASE)) {
00297 flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
00298 flags |= BIT_OF(UPPER);
00299 }
00300 if (vtm->wday < 0 || vtm->wday > 6)
00301 i = 1, tp = "?";
00302 else
00303 i = 3, tp = days_l[vtm->wday];
00304 break;
00305
00306 case 'A':
00307 if (flags & BIT_OF(CHCASE)) {
00308 flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
00309 flags |= BIT_OF(UPPER);
00310 }
00311 if (vtm->wday < 0 || vtm->wday > 6)
00312 i = 1, tp = "?";
00313 else
00314 i = strlen(tp = days_l[vtm->wday]);
00315 break;
00316
00317 #ifdef SYSV_EXT
00318 case 'h':
00319 #endif
00320 case 'b':
00321 if (flags & BIT_OF(CHCASE)) {
00322 flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
00323 flags |= BIT_OF(UPPER);
00324 }
00325 if (vtm->mon < 1 || vtm->mon > 12)
00326 i = 1, tp = "?";
00327 else
00328 i = 3, tp = months_l[vtm->mon-1];
00329 break;
00330
00331 case 'B':
00332 if (flags & BIT_OF(CHCASE)) {
00333 flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE));
00334 flags |= BIT_OF(UPPER);
00335 }
00336 if (vtm->mon < 1 || vtm->mon > 12)
00337 i = 1, tp = "?";
00338 else
00339 i = strlen(tp = months_l[vtm->mon-1]);
00340 break;
00341
00342 case 'c':
00343 STRFTIME("%a %b %e %H:%M:%S %Y");
00344 continue;
00345
00346 case 'd':
00347 i = range(1, vtm->mday, 31);
00348 FMT('0', 2, "d", (int)i);
00349 continue;
00350
00351 case 'H':
00352 i = range(0, vtm->hour, 23);
00353 FMT('0', 2, "d", (int)i);
00354 continue;
00355
00356 case 'I':
00357 i = range(0, vtm->hour, 23);
00358 if (i == 0)
00359 i = 12;
00360 else if (i > 12)
00361 i -= 12;
00362 FMT('0', 2, "d", (int)i);
00363 continue;
00364
00365 case 'j':
00366 FMT('0', 3, "d", vtm->yday);
00367 continue;
00368
00369 case 'm':
00370 i = range(1, vtm->mon, 12);
00371 FMT('0', 2, "d", (int)i);
00372 continue;
00373
00374 case 'M':
00375 i = range(0, vtm->min, 59);
00376 FMT('0', 2, "d", (int)i);
00377 continue;
00378
00379 case 'p':
00380 case 'P':
00381 if ((*format == 'p' && (flags & BIT_OF(CHCASE))) ||
00382 (*format == 'P' && !(flags & (BIT_OF(CHCASE)|BIT_OF(UPPER))))) {
00383 flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
00384 flags |= BIT_OF(LOWER);
00385 }
00386 i = range(0, vtm->hour, 23);
00387 if (i < 12)
00388 tp = ampm[0];
00389 else
00390 tp = ampm[1];
00391 i = 2;
00392 break;
00393
00394 case 's':
00395 if (ts) {
00396 time_t sec = ts->tv_sec;
00397 if (~(time_t)0 <= 0)
00398 FMT('0', 1, PRI_TIMET_PREFIX"d", sec);
00399 else
00400 FMT('0', 1, PRI_TIMET_PREFIX"u", sec);
00401 }
00402 else {
00403 VALUE sec = div(timev, INT2FIX(1));
00404 FMTV('0', 1, "d", sec);
00405 }
00406 continue;
00407
00408 case 'S':
00409 i = range(0, vtm->sec, 60);
00410 FMT('0', 2, "d", (int)i);
00411 continue;
00412
00413 case 'U':
00414 FMT('0', 2, "d", weeknumber_v(vtm, 0));
00415 continue;
00416
00417 case 'w':
00418 i = range(0, vtm->wday, 6);
00419 FMT('0', 1, "d", (int)i);
00420 continue;
00421
00422 case 'W':
00423 FMT('0', 2, "d", weeknumber_v(vtm, 1));
00424 continue;
00425
00426 case 'x':
00427 STRFTIME("%m/%d/%y");
00428 continue;
00429
00430 case 'X':
00431 STRFTIME("%H:%M:%S");
00432 continue;
00433
00434 case 'y':
00435 i = NUM2INT(mod(vtm->year, INT2FIX(100)));
00436 FMT('0', 2, "d", (int)i);
00437 continue;
00438
00439 case 'Y':
00440 if (FIXNUM_P(vtm->year)) {
00441 long y = FIX2LONG(vtm->year);
00442 FMT('0', 0 <= y ? 4 : 5, "ld", y);
00443 }
00444 else {
00445 FMTV('0', 4, "d", vtm->year);
00446 }
00447 continue;
00448
00449 #ifdef MAILHEADER_EXT
00450 case 'z':
00451 switch (colons) {
00452 case 0:
00453 precision = precision <= 5 ? 2 : precision-3;
00454 NEEDS(precision + 3);
00455 break;
00456
00457 case 1:
00458 precision = precision <= 6 ? 2 : precision-4;
00459 NEEDS(precision + 4);
00460 break;
00461
00462 case 2:
00463 precision = precision <= 9 ? 2 : precision-7;
00464 NEEDS(precision + 7);
00465 break;
00466
00467 default:
00468 format--;
00469 goto unknown;
00470 }
00471 if (gmt) {
00472 off = 0;
00473 }
00474 else {
00475 off = NUM2LONG(rb_funcall(vtm->utc_offset, rb_intern("round"), 0));
00476 }
00477 if (off < 0) {
00478 off = -off;
00479 sign = -1;
00480 } else {
00481 sign = +1;
00482 }
00483 i = snprintf(s, endp - s, (padding == ' ' ? "%+*ld" : "%+.*ld"),
00484 precision + 1, sign * (off / 3600));
00485 if (i < 0) goto err;
00486 if (sign < 0 && off < 3600) {
00487 *(padding == ' ' ? s + i - 2 : s) = '-';
00488 }
00489 s += i;
00490 off = off % 3600;
00491 if (1 <= colons)
00492 *s++ = ':';
00493 i = snprintf(s, endp - s, "%02d", (int)(off / 60));
00494 if (i < 0) goto err;
00495 s += i;
00496 off = off % 60;
00497 if (2 <= colons) {
00498 *s++ = ':';
00499 i = snprintf(s, endp - s, "%02d", (int)off);
00500 if (i < 0) goto err;
00501 s += i;
00502 }
00503 continue;
00504 #endif
00505
00506 case 'Z':
00507 if (flags & BIT_OF(CHCASE)) {
00508 flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
00509 flags |= BIT_OF(LOWER);
00510 }
00511 if (gmt) {
00512 i = 3;
00513 tp = "UTC";
00514 break;
00515 }
00516 if (vtm->zone == NULL)
00517 tp = "";
00518 else
00519 tp = vtm->zone;
00520 i = strlen(tp);
00521 break;
00522
00523 #ifdef SYSV_EXT
00524 case 'n':
00525 FILL_PADDING(1);
00526 *s++ = '\n';
00527 continue;
00528
00529 case 't':
00530 FILL_PADDING(1);
00531 *s++ = '\t';
00532 continue;
00533
00534 case 'D':
00535 STRFTIME("%m/%d/%y");
00536 continue;
00537
00538 case 'e':
00539 FMT(' ', 2, "d", range(1, vtm->mday, 31));
00540 continue;
00541
00542 case 'r':
00543 STRFTIME("%I:%M:%S %p");
00544 continue;
00545
00546 case 'R':
00547 STRFTIME("%H:%M");
00548 continue;
00549
00550 case 'T':
00551 STRFTIME("%H:%M:%S");
00552 continue;
00553 #endif
00554
00555 #ifdef SUNOS_EXT
00556 case 'k':
00557 i = range(0, vtm->hour, 23);
00558 FMT(' ', 2, "d", (int)i);
00559 continue;
00560
00561 case 'l':
00562 i = range(0, vtm->hour, 23);
00563 if (i == 0)
00564 i = 12;
00565 else if (i > 12)
00566 i -= 12;
00567 FMT(' ', 2, "d", (int)i);
00568 continue;
00569 #endif
00570
00571
00572 #ifdef VMS_EXT
00573 case 'v':
00574 STRFTIME("%e-%^b-%4Y");
00575 continue;
00576 #endif
00577
00578
00579 #ifdef POSIX2_DATE
00580 case 'C':
00581 FMTV('0', 2, "d", div(vtm->year, INT2FIX(100)));
00582 continue;
00583
00584 case 'E':
00585
00586 flags |= BIT_OF(LOCALE_E);
00587 goto again;
00588 case 'O':
00589
00590 flags |= BIT_OF(LOCALE_O);
00591 goto again;
00592
00593 case 'V':
00594 FMT('0', 2, "d", iso8601wknum_v(vtm));
00595 continue;
00596
00597 case 'u':
00598
00599 FMT('0', 1, "d", vtm->wday == 0 ? 7 : vtm->wday);
00600 continue;
00601 #endif
00602
00603 #ifdef ISO_DATE_EXT
00604 case 'G':
00605 case 'g':
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 {
00616 VALUE yv = vtm->year;
00617 w = iso8601wknum_v(vtm);
00618 if (vtm->mon == 12 && w == 1)
00619 yv = add(yv, INT2FIX(1));
00620 else if (vtm->mon == 1 && w >= 52)
00621 yv = sub(yv, INT2FIX(1));
00622
00623 if (*format == 'G') {
00624 if (FIXNUM_P(yv)) {
00625 const long y = FIX2LONG(yv);
00626 FMT('0', 0 <= y ? 4 : 5, "ld", y);
00627 }
00628 else {
00629 FMTV('0', 4, "d", yv);
00630 }
00631 }
00632 else {
00633 yv = mod(yv, INT2FIX(100));
00634 y = FIX2LONG(yv);
00635 FMT('0', 2, "ld", y);
00636 }
00637 continue;
00638 }
00639
00640 #endif
00641
00642
00643 case 'L':
00644 w = 3;
00645 goto subsec;
00646
00647 case 'N':
00648
00649
00650
00651
00652
00653
00654
00655
00656 w = 9;
00657 subsec:
00658 if (precision <= 0) {
00659 precision = w;
00660 }
00661 NEEDS(precision);
00662
00663 if (ts) {
00664 long subsec = ts->tv_nsec;
00665 if (9 < precision) {
00666 snprintf(s, endp - s, "%09ld", subsec);
00667 memset(s+9, '0', precision-9);
00668 s += precision;
00669 }
00670 else {
00671 int i;
00672 for (i = 0; i < 9-precision; i++)
00673 subsec /= 10;
00674 snprintf(s, endp - s, "%0*ld", precision, subsec);
00675 s += precision;
00676 }
00677 }
00678 else {
00679 VALUE subsec = mod(timev, INT2FIX(1));
00680 int ww;
00681 long n;
00682
00683 ww = precision;
00684 while (9 <= ww) {
00685 subsec = mul(subsec, INT2FIX(1000000000));
00686 ww -= 9;
00687 }
00688 n = 1;
00689 for (; 0 < ww; ww--)
00690 n *= 10;
00691 if (n != 1)
00692 subsec = mul(subsec, INT2FIX(n));
00693 subsec = div(subsec, INT2FIX(1));
00694
00695 if (FIXNUM_P(subsec)) {
00696 (void)snprintf(s, endp - s, "%0*ld", precision, FIX2LONG(subsec));
00697 s += precision;
00698 }
00699 else {
00700 VALUE args[2], result;
00701 args[0] = INT2FIX(precision);
00702 args[1] = subsec;
00703 result = rb_str_format(2, args, rb_str_new2("%0*d"));
00704 (void)strlcpy(s, StringValueCStr(result), endp-s);
00705 s += precision;
00706 }
00707 }
00708 continue;
00709
00710 case 'F':
00711 STRFTIME("%Y-%m-%d");
00712 continue;
00713
00714 case '-':
00715 FLAG_FOUND();
00716 flags |= BIT_OF(LEFT);
00717 padding = precision = 0;
00718 goto again;
00719
00720 case '^':
00721 FLAG_FOUND();
00722 flags |= BIT_OF(UPPER);
00723 goto again;
00724
00725 case '#':
00726 FLAG_FOUND();
00727 flags |= BIT_OF(CHCASE);
00728 goto again;
00729
00730 case '_':
00731 FLAG_FOUND();
00732 padding = ' ';
00733 goto again;
00734
00735 case ':':
00736 FLAG_FOUND();
00737 colons++;
00738 goto again;
00739
00740 case '0':
00741 padding = '0';
00742 case '1': case '2': case '3': case '4':
00743 case '5': case '6': case '7': case '8': case '9':
00744 {
00745 char *e;
00746 precision = (int)strtoul(format, &e, 10);
00747 format = e - 1;
00748 goto again;
00749 }
00750
00751 default:
00752 unknown:
00753 i = format - sp + 1;
00754 tp = sp;
00755 precision = -1;
00756 flags = 0;
00757 padding = 0;
00758 colons = 0;
00759 break;
00760 }
00761 if (i) {
00762 FILL_PADDING(i);
00763 memcpy(s, tp, i);
00764 switch (flags & (BIT_OF(UPPER)|BIT_OF(LOWER))) {
00765 case BIT_OF(UPPER):
00766 do {
00767 if (ISLOWER(*s)) *s = TOUPPER(*s);
00768 } while (s++, --i);
00769 break;
00770 case BIT_OF(LOWER):
00771 do {
00772 if (ISUPPER(*s)) *s = TOLOWER(*s);
00773 } while (s++, --i);
00774 break;
00775 default:
00776 s += i;
00777 break;
00778 }
00779 }
00780 }
00781 if (s >= endp) {
00782 goto err;
00783 }
00784 if (*format == '\0') {
00785 *s = '\0';
00786 return (s - start);
00787 } else
00788 return 0;
00789 }
00790
00791 size_t
00792 rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, int gmt)
00793 {
00794 return rb_strftime_with_timespec(s, maxsize, format, vtm, timev, NULL, gmt);
00795 }
00796
00797 size_t
00798 rb_strftime_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, struct timespec *ts, int gmt)
00799 {
00800 return rb_strftime_with_timespec(s, maxsize, format, vtm, Qnil, ts, gmt);
00801 }
00802
00803
00804
00805 #ifndef __STDC__
00806 static int
00807 isleap(year)
00808 long year;
00809 #else
00810 static int
00811 isleap(long year)
00812 #endif
00813 {
00814 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
00815 }
00816
00817
00818 static void
00819 vtm2tm_noyear(const struct vtm *vtm, struct tm *result)
00820 {
00821 struct tm tm;
00822
00823
00824 tm.tm_year = FIX2INT(mod(vtm->year, INT2FIX(400))) + 100;
00825
00826 tm.tm_mon = vtm->mon-1;
00827 tm.tm_mday = vtm->mday;
00828 tm.tm_hour = vtm->hour;
00829 tm.tm_min = vtm->min;
00830 tm.tm_sec = vtm->sec;
00831 tm.tm_wday = vtm->wday;
00832 tm.tm_yday = vtm->yday-1;
00833 tm.tm_isdst = vtm->isdst;
00834 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
00835 tm.tm_gmtoff = NUM2LONG(vtm->utc_offset);
00836 #endif
00837 #if defined(HAVE_TM_ZONE)
00838 tm.tm_zone = (char *)vtm->zone;
00839 #endif
00840 *result = tm;
00841 }
00842
00843 #ifdef POSIX2_DATE
00844
00845
00846 #ifndef __STDC__
00847 static int
00848 iso8601wknum(timeptr)
00849 const struct tm *timeptr;
00850 #else
00851 static int
00852 iso8601wknum(const struct tm *timeptr)
00853 #endif
00854 {
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 int weeknum, jan1day;
00870
00871
00872 weeknum = weeknumber(timeptr, 1);
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887 jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
00888 if (jan1day < 0)
00889 jan1day += 7;
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 switch (jan1day) {
00905 case 1:
00906 break;
00907 case 2:
00908 case 3:
00909 case 4:
00910 weeknum++;
00911 break;
00912 case 5:
00913 case 6:
00914 case 0:
00915 if (weeknum == 0) {
00916 #ifdef USE_BROKEN_XPG4
00917
00918 weeknum = 53;
00919 #else
00920
00921 struct tm dec31ly;
00922 dec31ly = *timeptr;
00923 dec31ly.tm_year--;
00924 dec31ly.tm_mon = 11;
00925 dec31ly.tm_mday = 31;
00926 dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
00927 dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L);
00928 weeknum = iso8601wknum(& dec31ly);
00929 #endif
00930 }
00931 break;
00932 }
00933
00934 if (timeptr->tm_mon == 11) {
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 int wday, mday;
00947
00948 wday = timeptr->tm_wday;
00949 mday = timeptr->tm_mday;
00950 if ( (wday == 1 && (mday >= 29 && mday <= 31))
00951 || (wday == 2 && (mday == 30 || mday == 31))
00952 || (wday == 3 && mday == 31))
00953 weeknum = 1;
00954 }
00955
00956 return weeknum;
00957 }
00958
00959 static int
00960 iso8601wknum_v(const struct vtm *vtm)
00961 {
00962 struct tm tm;
00963 vtm2tm_noyear(vtm, &tm);
00964 return iso8601wknum(&tm);
00965 }
00966
00967 #endif
00968
00969
00970
00971
00972
00973 #ifndef __STDC__
00974 static int
00975 weeknumber(timeptr, firstweekday)
00976 const struct tm *timeptr;
00977 int firstweekday;
00978 #else
00979 static int
00980 weeknumber(const struct tm *timeptr, int firstweekday)
00981 #endif
00982 {
00983 int wday = timeptr->tm_wday;
00984 int ret;
00985
00986 if (firstweekday == 1) {
00987 if (wday == 0)
00988 wday = 6;
00989 else
00990 wday--;
00991 }
00992 ret = ((timeptr->tm_yday + 7 - wday) / 7);
00993 if (ret < 0)
00994 ret = 0;
00995 return ret;
00996 }
00997
00998 static int
00999 weeknumber_v(const struct vtm *vtm, int firstweekday)
01000 {
01001 struct tm tm;
01002 vtm2tm_noyear(vtm, &tm);
01003 return weeknumber(&tm, firstweekday);
01004 }
01005
01006 #if 0
01007
01008
01009 Date: Wed, 24 Apr 91 20:54:08 MDT
01010 From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
01011 To: arnold@audiofax.com
01012
01013 Hi Arnold,
01014 in a process of fixing of strftime() in libraries on Atari ST I grabbed
01015 some pieces of code from your own strftime. When doing that it came
01016 to mind that your weeknumber() function compiles a little bit nicer
01017 in the following form:
01018
01019
01020
01021 {
01022 return (timeptr->tm_yday - timeptr->tm_wday +
01023 (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
01024 }
01025 How nicer it depends on a compiler, of course, but always a tiny bit.
01026
01027 Cheers,
01028 Michal
01029 ntomczak@vm.ucs.ualberta.ca
01030 #endif
01031
01032 #ifdef TEST_STRFTIME
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 #ifndef NULL
01062 #include <stdio.h>
01063 #endif
01064 #include <sys/time.h>
01065 #include <string.h>
01066
01067 #define MAXTIME 132
01068
01069
01070
01071
01072
01073 static char *array[] =
01074 {
01075 "(%%A) full weekday name, var length (Sunday..Saturday) %A",
01076 "(%%B) full month name, var length (January..December) %B",
01077 "(%%C) Century %C",
01078 "(%%D) date (%%m/%%d/%%y) %D",
01079 "(%%E) Locale extensions (ignored) %E",
01080 "(%%H) hour (24-hour clock, 00..23) %H",
01081 "(%%I) hour (12-hour clock, 01..12) %I",
01082 "(%%M) minute (00..59) %M",
01083 "(%%O) Locale extensions (ignored) %O",
01084 "(%%R) time, 24-hour (%%H:%%M) %R",
01085 "(%%S) second (00..60) %S",
01086 "(%%T) time, 24-hour (%%H:%%M:%%S) %T",
01087 "(%%U) week of year, Sunday as first day of week (00..53) %U",
01088 "(%%V) week of year according to ISO 8601 %V",
01089 "(%%W) week of year, Monday as first day of week (00..53) %W",
01090 "(%%X) appropriate locale time representation (%H:%M:%S) %X",
01091 "(%%Y) year with century (1970...) %Y",
01092 "(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
01093 "(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
01094 "(%%b) locale's abbreviated month name (Jan..Dec) %b",
01095 "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
01096 "(%%d) day of the month (01..31) %d",
01097 "(%%e) day of the month, blank-padded ( 1..31) %e",
01098 "(%%h) should be same as (%%b) %h",
01099 "(%%j) day of the year (001..366) %j",
01100 "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
01101 "(%%l) hour, 12-hour clock, blank pad ( 1..12) %l",
01102 "(%%m) month (01..12) %m",
01103 "(%%p) locale's AM or PM based on 12-hour clock %p",
01104 "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
01105 "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
01106 "(%%v) VMS date (dd-bbb-YYYY) %v",
01107 "(%%w) day of week (0..6, Sunday == 0) %w",
01108 "(%%x) appropriate locale date representation %x",
01109 "(%%y) last two digits of year (00..99) %y",
01110 "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
01111 (char *) NULL
01112 };
01113
01114
01115
01116 int
01117 main(argc, argv)
01118 int argc;
01119 char **argv;
01120 {
01121 long time();
01122
01123 char *next;
01124 char string[MAXTIME];
01125
01126 int k;
01127 int length;
01128
01129 struct tm *tm;
01130
01131 long clock;
01132
01133
01134
01135 clock = time((long *) 0);
01136 tm = localtime(&clock);
01137
01138 for (k = 0; next = array[k]; k++) {
01139 length = strftime(string, MAXTIME, next, tm);
01140 printf("%s\n", string);
01141 }
01142
01143 exit(0);
01144 }
01145 #endif
01146