gonzui


Format: Advanced Search

t2ex/t2ex_source/t2ex/datetime/src/strftime.cbare sourcepermlink (0.07 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T2EX Software Package
    4:  *
    5:  *    Copyright 2012 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2012/12/12.
   10:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/04.
   11:  *
   12:  *----------------------------------------------------------------------
   13:  */
   14: /*
   15:  * This software package is available for use, modification, 
   16:  * and redistribution in accordance with the terms of the attached 
   17:  * T-License 2.x.
   18:  * If you want to redistribute the source code, you need to attach 
   19:  * the T-License 2.x document.
   20:  * There's no obligation to publish the content, and no obligation 
   21:  * to disclose it to the TRON Forum if you have modified the 
   22:  * software package.
   23:  * You can also distribute the modified source code. In this case, 
   24:  * please register the modification to T-Kernel traceability service.
   25:  * People can know the history of modifications by the service, 
   26:  * and can be sure that the version you have inherited some 
   27:  * modification of a particular version or not.
   28:  *
   29:  *    http://trace.tron.org/tk/?lang=en
   30:  *    http://trace.tron.org/tk/?lang=ja
   31:  *
   32:  * As per the provisions of the T-License 2.x, TRON Forum ensures that 
   33:  * the portion of the software that is copyrighted by Ken Sakamura or 
   34:  * the TRON Forum does not infringe the copyrights of a third party.
   35:  * However, it does not make any warranty other than this.
   36:  * DISCLAIMER: TRON Forum and Ken Sakamura shall not be held
   37:  * responsible for any consequences or damages caused directly or
   38:  * indirectly by the use of this software package.
   39:  *
   40:  * The source codes in bsd_source.tar.gz in this software package are 
   41:  * derived from NetBSD or OpenBSD and not covered under T-License 2.x.
   42:  * They need to be changed or redistributed according to the 
   43:  * representation of each source header.
   44:  */
   45: 
   46: /*
   47:  *      @(#)strftime.c
   48:  *
   49:  *       T2EX: calendar functions
   50:  *       dt_strftime
   51:  */
   52: 
   53: #include <basic.h>
   54: #include <ctype.h>
   55: #include <errno.h>
   56: #include <t2ex/datetime.h>
   57: #include "internal.h"
   58: 
   59: /* Update timezone information */
   60: Inline ER update_tz( struct tzinfo* tz )
   61: {
   62:         if (tz->tzname[0][0] == '\0') {
   63:                 ER er = dt_getsystz(tz);
   64:                 if (er < E_OK) {
   65:                         return er;
   66:                 }
   67:         }
   68:         return (tz->tzname[0][0] != '\0') ? E_OK : EX_INVAL;
   69: }
   70: 
   71: /* Calculate ISO 8601 week-based date */
   72: LOCAL void update_gv(int gv[2], const struct tm *t)
   73: {
   74:         int k, v, d;
   75: 
   76:         /* Already calculated */
   77:         if (gv[1] >= 0) return;
   78: 
   79:         k = (t -> tm_wday - t -> tm_yday + (53 * 7) + 6) % 7; /* day of the week of January 1st (Mon=0, Tue=1, ...) */
   80:         v = ((k > 3) ? 1 : 0) + (t -> tm_yday + k + 1) / 7;
   81: 
   82:         if (v > 0) {
   83:                 /* The given date belongs to this week-based year */
   84:                 gv[0] = t->tm_year;
   85:                 gv[1] = v;
   86:         }
   87:         else {
   88:                 /* The given date belongs to the previous week-based year */
   89:                 d = 365 + (isleap(1900 + t -> tm_yday - 1) ? 1 : 0); /* the number of days for the previous year */
   90:                 k = ( k + (53 * 7) - d) % 7; /* day of the week of the previous January 1st */
   91:                 v = ((k > 3) ? 1 : 0) + (d + t -> tm_yday + k + 1) / 7;
   92: 
   93:                 gv[0] = t->tm_year - 1;
   94:                 gv[1] = v;
   95:         }
   96: }
   97: 
   98: /* outputs a result for a single `%' specification */
   99: LOCAL int put( const char c, const struct tm *t, char **p, int *siz, struct tzinfo* tz, int gv[2] )
  100: {
  101:         ER er;
  102:         int k; const char *q;
  103: 
  104:         switch (c) {
  105:         case 'd' :
  106:         case 'm' :
  107:         case 'y' :
  108:         case 'H' :
  109:         case 'I' :
  110:         case 'M' :
  111:         case 'S' :
  112:         case 'C' :
  113:         case 'U' :
  114:         case 'W' :
  115:         case 'V' :
  116:         case 'g' :
  117:                 if (c == 'd') { /* day of the month [01,31] */
  118:                         k = t -> tm_mday;
  119:                 }
  120:                 else if (c == 'm') { /* month [01,12] */
  121:                         k = t -> tm_mon + 1;
  122:                 }
  123:                 else if (c == 'y') { /* year (2 digits) */
  124:                         k = t -> tm_year % 100;
  125:                 }
  126:                 else if (c == 'H') { /* hour [00,23] */
  127:                         k = t -> tm_hour;
  128:                 }
  129:                 else if (c == 'I') { /* hour [01,12] */
  130:                         k = ((t -> tm_hour + 11) % 12) + 1;
  131:                 }
  132:                 else if (c == 'M') { /* minute [00,59] */
  133:                         k = t -> tm_min;
  134:                 }
  135:                 else if (c == 'S') { /* second [00,59] */
  136:                         k = t -> tm_sec;
  137:                 }
  138:                 else if (c == 'C') { /* century */
  139:                         k = (t -> tm_year + 1900) / 100;
  140:                 }
  141:                 else if (c == 'U') { /* week number of the year [00,53] */
  142:                         k = (t -> tm_wday - t -> tm_yday + (53 * 7) + 6) % 7; /* day of the week of January 1st (Mon=0, Tue=1, ...) */
  143:                         k = (t -> tm_yday + k + 1) / 7;
  144:                 }
  145:                 else if (c == 'W') { /* week number of the year [00,53] */
  146:                         k = (t -> tm_wday - t -> tm_yday + (53 * 7) + 5) % 7; /* day of the week of January 1st (Tue=0, Wed=1, ...) */
  147:                         k = (t -> tm_yday + k + 1) / 7;
  148:                 }
  149:                 else if (c == 'V') { /* week number of the year [01,53] */
  150:                         update_gv(gv, t);
  151:                         k = gv[1];
  152:                 }
  153:                 else /*if (c == 'g')*/ { /* week-based year (2 digits) */
  154:                         update_gv(gv, t);
  155:                         k = (gv[0] + 1900) % 100;
  156:                 }
  157:                 *siz -= 2; if (*siz < 0) return -1;
  158:                 *(*p)++ = ((k / 10) % 10) + '0';
  159:                 *(*p)++ = ((k) % 10) + '0';
  160:                 break;
  161:         case 'u' :
  162:         case 'w' :
  163:                 /* day of the week (%w: Sun=0, Mon=1, ..., Sat=6 / %u: Sun=1, Mon=2, ..., Sat=7) */
  164:                 k = (t -> tm_wday) + ((c == 'u') ? 1 : 0);
  165:                 if (--*siz < 0) return -1;
  166:                 *(*p)++ = ((k) % 10) + '0';
  167:                 break;
  168:         case 'j' :
  169:                 /* day of the year [001,366] */
  170:                 k = t -> tm_yday + 1;
  171:                 *siz -= 3; if (*siz < 0) return -1;
  172:                 *(*p)++ = ((k / 100) % 10) + '0';
  173:                 *(*p)++ = ((k / 10) % 10) + '0';
  174:                 *(*p)++ = ((k) % 10) + '0';
  175:                 break;
  176:         case 'Y' :
  177:         case 'G' :
  178:                 if (c == 'Y') { /* year (4 digits) */
  179:                         k = t -> tm_year + 1900;
  180:                 }
  181:                 else /*if (c == 'G')*/ { /* week-based year (4 digits) */
  182:                         update_gv(gv, t);
  183:                         k = gv[0] + 1900;
  184:                 }
  185:                 *siz -= 4; if (*siz < 0) return -1;
  186:                 *(*p)++ = ((k / 1000) % 10) + '0';
  187:                 *(*p)++ = ((k / 100) % 10) + '0';
  188:                 *(*p)++ = ((k / 10) % 10) + '0';
  189:                 *(*p)++ = ((k) % 10) + '0';
  190:                 break;
  191:         case 'e' :
  192:                 /* day of the month [ 1,31] */
  193:                 k = t -> tm_mday;
  194:                 *siz -= 2; if (*siz < 0) return -1;
  195:                 *(*p)++ = ((k >= 10) ? ((k / 10) % 10) + '0' : ' ');
  196:                 *(*p)++ = ((k) % 10) + '0';
  197:                 break;
  198:         case 'a' :
  199:         case 'A' :
  200:         case 'b' :
  201:         case 'h' :
  202:         case 'B' :
  203:         case 'p' :
  204:                 if (c == 'a') { /* day of the week (short) */
  205:                         k = 3;
  206:                         q = _dt_weeknm + ((sizeof(_dt_weeknm) / 7) * t -> tm_wday);
  207:                 }
  208:                 else if (c == 'A') { /* day of the week (full) */
  209:                         k = sizeof(_dt_weeknm) / 7;
  210:                         q = _dt_weeknm + (k * t -> tm_wday);
  211:                 }
  212:                 else if (c == 'b' || c == 'h') { /* month (short) */
  213:                         k = 3;
  214:                         q = _dt_monthnm + ((sizeof(_dt_monthnm) / 12) * t -> tm_mon);
  215:                 }
  216:                 else if (c == 'B') { /* month (full) */
  217:                         k = sizeof(_dt_monthnm) / 12;
  218:                         q = _dt_monthnm + (k * t -> tm_mon);
  219:                 }
  220:                 else /*if (c == 'p')*/ { /* AM/PM */
  221:                         k = sizeof(_dt_ampm) / 2;
  222:                         q = _dt_ampm + (k * (t -> tm_hour >= 12));
  223:                 }
  224:                 while (k-- > 0) {
  225:                         if (*q <= ' ') break;
  226:                         if (--*siz < 0) return -1;
  227:                         *(*p)++ = *q++;
  228:                 }
  229:                 break;
  230:         case 'x':
  231:         case 'D':
  232:                 /* date (mm/dd/yy) */
  233:                 put( 'm', t, p, siz, tz, gv );
  234:                 if (--*siz < 0) return -1;
  235:                 *(*p)++ = '/';
  236:                 put( 'd', t, p, siz, tz, gv );
  237:                 if (--*siz < 0) return -1;
  238:                 *(*p)++ = '/';
  239:                 put( 'y', t, p, siz, tz, gv );
  240:                 break;
  241:         case 'F':
  242:                 /* date (yyyy/mm/dd) */
  243:                 put( 'Y', t, p, siz, tz, gv );
  244:                 if (--*siz < 0) return -1;
  245:                 *(*p)++ = '-';
  246:                 put( 'm', t, p, siz, tz, gv );
  247:                 if (--*siz < 0) return -1;
  248:                 *(*p)++ = '-';
  249:                 put( 'd', t, p, siz, tz, gv );
  250:                 break;
  251:         case 'X':
  252:         case 'T':
  253:         case 'R':
  254:                 /* time (hh:mm:ss/hh:mm) */
  255:                 put( 'H', t, p, siz, tz, gv );
  256:                 if (--*siz < 0) return -1;
  257:                 *(*p)++ = ':';
  258:                 put( 'M', t, p, siz, tz, gv );
  259:                 if (c == 'R') break;
  260:                 if (--*siz < 0) return -1;
  261:                 *(*p)++ = ':';
  262:                 put( 'S', t, p, siz, tz, gv );
  263:                 break;
  264:         case 'r':
  265:                 /* time (hh:mm:ss pp) */
  266:                 put( 'I', t, p, siz, tz, gv );
  267:                 if (--*siz < 0) return -1;
  268:                 *(*p)++ = ':';
  269:                 put( 'M', t, p, siz, tz, gv );
  270:                 if (--*siz < 0) return -1;
  271:                 *(*p)++ = ':';
  272:                 put( 'S', t, p, siz, tz, gv );
  273:                 if (--*siz < 0) return -1;
  274:                 *(*p)++ = ' ';
  275:                 put( 'p', t, p, siz, tz, gv );
  276:                 break;
  277:         case 'c':
  278:                 /* date and time */
  279:                 put( 'a', t, p, siz, tz, gv );
  280:                 if (--*siz < 0) return -1;
  281:                 *(*p)++ = ' ';
  282:                 put( 'b', t, p, siz, tz, gv );
  283:                 if (--*siz < 0) return -1;
  284:                 *(*p)++ = ' ';
  285:                 put( 'd', t, p, siz, tz, gv );
  286:                 if (--*siz < 0) return -1;
  287:                 *(*p)++ = ' ';
  288:                 put( 'X', t, p, siz, tz, gv );
  289:                 if (--*siz < 0) return -1;
  290:                 *(*p)++ = ' ';
  291:                 put( 'Y', t, p, siz, tz, gv );
  292:                 break;
  293:         case 'z':
  294:                 /* offset from UTC */
  295:                 er = update_tz(tz);
  296:                 if (er < E_OK) return -1;
  297:                 k = tz->daylight ? tz->dst_offset : tz->offset;
  298:                 if (k >= 0) {
  299:                         *(*p)++ = '-';
  300:                 }
  301:                 else {
  302:                         *(*p)++ = '+';
  303:                         k = -k;
  304:                 }
  305:                 if (--*siz < 0) return -1;
  306:                 *(*p)++ = ((k / (60 * 60) / 10) % 10) + '0';
  307:                 if (--*siz < 0) return -1;
  308:                 *(*p)++ = ((k / (60 * 60)) % 10) + '0';
  309:                 if (--*siz < 0) return -1;
  310:                 k %= (60 * 60);
  311:                 *(*p)++ = ((k / 60 / 10) % 10) + '0';
  312:                 if (--*siz < 0) return -1;
  313:                 *(*p)++ = ((k / 60) % 10) + '0';
  314:                 break;
  315:         case 'Z':
  316:                 /* system timezone name */
  317:                 er = update_tz(tz);
  318:                 if (er < E_OK) return -1;
  319:                 q = tz->tzname[tz->daylight ? 1 : 0];
  320:                 for (k = 0; q[k] != '\0' && k < TZNAME_MAX; ) {
  321:                         if (--*siz < 0) return -1;
  322:                         *(*p)++ = q[k++];
  323:                 }
  324:                 break;
  325:         case 't':
  326:                 /* tab character */
  327:                 if (--*siz < 0) return -1;
  328:                 *(*p)++ = '\t';
  329:                 break;
  330:         }
  331:         return 0;
  332: }
  333: 
  334: /*
  335:   strftime
  336: */
  337: EXPORT int dt_strftime( char *s, size_t max, const char *format, const struct tm *tm, const struct tzinfo* tz )
  338: {
  339:         struct tzinfo systz;
  340:         int c, n; const char *p; char d;
  341:         int gv[2] = {-1, -1};
  342: 
  343:         if (tz == NULL) {
  344:                 systz.tzname[0][0] = '\0';
  345:                 tz = &systz;
  346:         }
  347:         else if (tz->tzname[0][0] == '\0') {
  348:                 return EX_INVAL;
  349:         }
  350: 
  351:         n = max;
  352:         for( p = format; (c = _dt_spec( &p, &d )); ) {
  353:                 if (c == 1) {
  354:                         if (--n < 0) goto err_ret;
  355:                         *s++ = d;
  356:                 }
  357:                 else {
  358:                         if (put( c, tm, &s, &n, (struct tzinfo*)tz, gv ) < 0) goto err_ret;
  359:                 }
  360:         }
  361: 
  362:         *s = '\0';
  363:         return max - n;
  364: 
  365: err_ret:
  366:         /* Not enough space to store the output */
  367:         return EX_RANGE;
  368: }