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