Annotation of embedaddon/php/ext/date/lib/tm2unixtime.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2010 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #include "timelib.h"
                     22: 
                     23: /*                                    jan  feb  mrt  apr  may  jun  jul  aug  sep  oct  nov  dec */
                     24: static int month_tab_leap[12]     = {  -1,  30,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334 };
                     25: static int month_tab[12]          = {   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334 };
                     26: 
                     27: /*                                    dec  jan  feb  mrt  apr  may  jun  jul  aug  sep  oct  nov  dec */
                     28: static int days_in_month_leap[13] = {  31,  31,  29,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31 };
                     29: static int days_in_month[13]      = {  31,  31,  28,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31 };
                     30: 
                     31: static int do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b)
                     32: {
                     33:        if (*a < start) {
                     34:                *b -= (start - *a - 1) / adj + 1;
                     35:                *a += adj * ((start - *a - 1) / adj + 1);
                     36:        }
                     37:        if (*a >= end) {
                     38:                *b += *a / adj;
                     39:                *a -= adj * (*a / adj);
                     40:        }
                     41:        return 0;
                     42: }
                     43: 
                     44: static void inc_month(timelib_sll *y, timelib_sll *m)
                     45: {
                     46:        (*m)++;
                     47:        if (*m > 12) {
                     48:                *m -= 12;
                     49:                (*y)++;
                     50:        }
                     51: }
                     52: 
                     53: static void dec_month(timelib_sll *y, timelib_sll *m)
                     54: {
                     55:        (*m)--;
                     56:        if (*m < 1) {
                     57:                *m += 12;
                     58:                (*y)--;
                     59:        }
                     60: }
                     61: 
                     62: static void do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d, timelib_sll invert)
                     63: {
                     64:        timelib_sll leapyear;
                     65:        timelib_sll month, year;
                     66:        timelib_sll days;
                     67: 
                     68:        do_range_limit(1, 13, 12, base_m, base_y);
                     69: 
                     70:        year = *base_y;
                     71:        month = *base_m;
                     72: 
                     73: /*
                     74:        printf( "S: Y%d M%d   %d %d %d   %d\n", year, month, *y, *m, *d, days);
                     75: */
                     76:        if (!invert) {
                     77:                while (*d < 0) {
                     78:                        dec_month(&year, &month);
                     79:                        leapyear = timelib_is_leap(year);
                     80:                        days = leapyear ? days_in_month_leap[month] : days_in_month[month];
                     81: 
                     82:                        /* printf( "I  Y%d M%d   %d %d %d   %d\n", year, month, *y, *m, *d, days); */
                     83: 
                     84:                        *d += days;
                     85:                        (*m)--;
                     86:                }
                     87:        } else {
                     88:                while (*d < 0) {
                     89:                        leapyear = timelib_is_leap(year);
                     90:                        days = leapyear ? days_in_month_leap[month] : days_in_month[month];
                     91: 
                     92:                        /* printf( "I  Y%d M%d   %d %d %d   %d\n", year, month, *y, *m, *d, days); */
                     93: 
                     94:                        *d += days;
                     95:                        (*m)--;
                     96:                        inc_month(&year, &month);
                     97:                }
                     98:        }
                     99:        /*
                    100:        printf( "E: Y%d M%d   %d %d %d   %d\n", year, month, *y, *m, *d, days);
                    101:        */
                    102: }
                    103: 
                    104: static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d)
                    105: {
                    106:        timelib_sll leapyear;
                    107:        timelib_sll days_this_month;
                    108:        timelib_sll last_month, last_year;
                    109:        timelib_sll days_last_month;
                    110:        
                    111:        /* can jump an entire leap year period quickly */
                    112:        if (*d >= DAYS_PER_LYEAR_PERIOD || *d <= -DAYS_PER_LYEAR_PERIOD) {
                    113:                *y += YEARS_PER_LYEAR_PERIOD * (*d / DAYS_PER_LYEAR_PERIOD);
                    114:                *d -= DAYS_PER_LYEAR_PERIOD * (*d / DAYS_PER_LYEAR_PERIOD);
                    115:        }
                    116: 
                    117:        do_range_limit(1, 13, 12, m, y);
                    118: 
                    119:        leapyear = timelib_is_leap(*y);
                    120:        days_this_month = leapyear ? days_in_month_leap[*m] : days_in_month[*m];
                    121:        last_month = (*m) - 1;
                    122: 
                    123:        if (last_month < 1) {
                    124:                last_month += 12;
                    125:                last_year = (*y) - 1;
                    126:        } else {
                    127:                last_year = (*y);
                    128:        }
                    129:        leapyear = timelib_is_leap(last_year);
                    130:        days_last_month = leapyear ? days_in_month_leap[last_month] : days_in_month[last_month];
                    131: 
                    132:        if (*d <= 0) {
                    133:                *d += days_last_month;
                    134:                (*m)--;
                    135:                return 1;
                    136:        }
                    137:        if (*d > days_this_month) {
                    138:                *d -= days_this_month;
                    139:                (*m)++;
                    140:                return 1;
                    141:        }
                    142:        return 0;
                    143: }
                    144: 
                    145: static void do_adjust_for_weekday(timelib_time* time)
                    146: {
                    147:        timelib_sll current_dow, difference;
                    148: 
                    149:        current_dow = timelib_day_of_week(time->y, time->m, time->d);
                    150:        if (time->relative.weekday_behavior == 2)
                    151:        {
                    152:                if (time->relative.weekday == 0) {
                    153:                        time->relative.weekday = 7;
                    154:                }
                    155:                time->d -= current_dow;
                    156:                time->d += time->relative.weekday;
                    157:                return;
                    158:        }
                    159:        difference = time->relative.weekday - current_dow;
                    160:        if ((time->relative.d < 0 && difference < 0) || (time->relative.d >= 0 && difference <= -time->relative.weekday_behavior)) {
                    161:                difference += 7;
                    162:        }
                    163:        if (time->relative.weekday >= 0) {
                    164:                time->d += difference;
                    165:        } else {
                    166:                time->d -= (7 - (abs(time->relative.weekday) - current_dow));
                    167:        }
                    168:        time->relative.have_weekday_relative = 0;
                    169: }
                    170: 
                    171: void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt)
                    172: {
                    173:        do {} while (do_range_limit(0, 60, 60, &rt->s, &rt->i));
                    174:        do {} while (do_range_limit(0, 60, 60, &rt->i, &rt->h));
                    175:        do {} while (do_range_limit(0, 24, 24, &rt->h, &rt->d));
                    176:        do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
                    177: 
                    178:        do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert);
                    179:        do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
                    180: }
                    181: 
                    182: void timelib_do_normalize(timelib_time* time)
                    183: {
                    184:        if (time->s != TIMELIB_UNSET) do {} while (do_range_limit(0, 60, 60, &time->s, &time->i));
                    185:        if (time->s != TIMELIB_UNSET) do {} while (do_range_limit(0, 60, 60, &time->i, &time->h));
                    186:        if (time->s != TIMELIB_UNSET) do {} while (do_range_limit(0, 24, 24, &time->h, &time->d));
                    187:        do {} while (do_range_limit(1, 13, 12, &time->m, &time->y));
                    188: 
                    189:        do {} while (do_range_limit_days(&time->y, &time->m, &time->d));
                    190:        do {} while (do_range_limit(1, 13, 12, &time->m, &time->y));
                    191: }
                    192: 
                    193: static void do_adjust_relative(timelib_time* time)
                    194: {
                    195:        if (time->relative.have_weekday_relative) {
                    196:                do_adjust_for_weekday(time);
                    197:        }
                    198:        timelib_do_normalize(time);
                    199: 
                    200:        if (time->have_relative) {
                    201:                time->s += time->relative.s;
                    202:                time->i += time->relative.i;
                    203:                time->h += time->relative.h;
                    204: 
                    205:                time->d += time->relative.d;
                    206:                time->m += time->relative.m;
                    207:                time->y += time->relative.y;
                    208:        }
                    209:        switch (time->relative.first_last_day_of) {
                    210:                case 1: /* first */
                    211:                        time->d = 1;
                    212:                        break;
                    213:                case 2: /* last */
                    214:                        time->d = 0;
                    215:                        time->m++;
                    216:                        break;
                    217:        }
                    218:        timelib_do_normalize(time);
                    219: }
                    220: 
                    221: static void do_adjust_special_weekday(timelib_time* time)
                    222: {
                    223:        timelib_sll current_dow, count;
                    224: 
                    225:        count = time->relative.special.amount;
                    226: 
                    227:        current_dow = timelib_day_of_week(time->y, time->m, time->d);
                    228:        if (count == 0) {
                    229:                /* skip over saturday and sunday */
                    230:                if (current_dow == 6) {
                    231:                        time->d += 2;
                    232:                }
                    233:                /* skip over sunday */
                    234:                if (current_dow == 0) {
                    235:                        time->d += 1;
                    236:                }
                    237:        } else if (count > 0) {
                    238:                /* skip over saturday and sunday */
                    239:                if (current_dow == 5) {
                    240:                        time->d += 2;
                    241:                }
                    242:                /* skip over sunday */
                    243:                if (current_dow == 6) {
                    244:                        time->d += 1;
                    245:                }
                    246:                /* add increments of 5 weekdays as a week */
                    247:                time->d += (count / 5) * 7;
                    248:                /* if current DOW plus the remainder > 5, add two days */
                    249:                current_dow = timelib_day_of_week(time->y, time->m, time->d);
                    250:                time->d += (count % 5);
                    251:                if ((count % 5) + current_dow > 5) {
                    252:                        time->d += 2;
                    253:                }
                    254:        } else if (count < 0) {
                    255:                /* skip over sunday and saturday */
                    256:                if (current_dow == 1) {
                    257:                        time->d -= 2;
                    258:                }
                    259:                /* skip over satruday */
                    260:                if (current_dow == 0 ) {
                    261:                        time->d -= 1;
                    262:                }
                    263:                /* subtract increments of 5 weekdays as a week */
                    264:                time->d += (count / 5) * 7;
                    265:                /* if current DOW minus the remainder < 0, subtract two days */
                    266:                current_dow = timelib_day_of_week(time->y, time->m, time->d);
                    267:                time->d += (count % 5);
                    268:                if ((count % 5) + current_dow < 1) {
                    269:                        time->d -= 2;
                    270:                }
                    271:        }
                    272: }
                    273: 
                    274: static void do_adjust_special(timelib_time* time)
                    275: {
                    276:        if (time->relative.have_special_relative) {
                    277:                switch (time->relative.special.type) {
                    278:                        case TIMELIB_SPECIAL_WEEKDAY:
                    279:                                do_adjust_special_weekday(time);
                    280:                                break;
                    281:                }
                    282:        }
                    283:        timelib_do_normalize(time);
                    284:        memset(&(time->relative.special), 0, sizeof(time->relative.special));
                    285: }
                    286: 
                    287: static void do_adjust_special_early(timelib_time* time)
                    288: {
                    289:        if (time->relative.have_special_relative) {
                    290:                switch (time->relative.special.type) {
                    291:                        case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
                    292:                                time->d = 1;
                    293:                                time->m += time->relative.m;
                    294:                                time->relative.m = 0;
                    295:                                break;
                    296:                        case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
                    297:                                time->d = 1;
                    298:                                time->m += time->relative.m + 1;
                    299:                                time->relative.m = 0;
                    300:                                break;
                    301:                }
                    302:        }
                    303:        timelib_do_normalize(time);
                    304: }
                    305: 
                    306: static timelib_sll do_years(timelib_sll year)
                    307: {
                    308:        timelib_sll i;
                    309:        timelib_sll res = 0;
                    310:        timelib_sll eras;
                    311: 
                    312:        eras = (year - 1970) / 40000;
                    313:        if (eras != 0) {
                    314:                year = year - (eras * 40000);
                    315:                res += (SECS_PER_ERA * eras * 100);
                    316:        }
                    317: 
                    318:        if (year >= 1970) {
                    319:                for (i = year - 1; i >= 1970; i--) {
                    320:                        if (timelib_is_leap(i)) {
                    321:                                res += (DAYS_PER_LYEAR * SECS_PER_DAY);
                    322:                        } else {
                    323:                                res += (DAYS_PER_YEAR * SECS_PER_DAY);
                    324:                        }
                    325:                }
                    326:        } else {
                    327:                for (i = 1969; i >= year; i--) {
                    328:                        if (timelib_is_leap(i)) {
                    329:                                res -= (DAYS_PER_LYEAR * SECS_PER_DAY);
                    330:                        } else {
                    331:                                res -= (DAYS_PER_YEAR * SECS_PER_DAY);
                    332:                        }
                    333:                }
                    334:        }
                    335:        return res;
                    336: }
                    337: 
                    338: static timelib_sll do_months(timelib_ull month, timelib_ull year)
                    339: {
                    340:        if (timelib_is_leap(year)) {
                    341:                return ((month_tab_leap[month - 1] + 1) * SECS_PER_DAY);
                    342:        } else {
                    343:                return ((month_tab[month - 1]) * SECS_PER_DAY);
                    344:        }
                    345: }
                    346: 
                    347: static timelib_sll do_days(timelib_ull day)
                    348: {
                    349:        return ((day - 1) * SECS_PER_DAY);
                    350: }
                    351: 
                    352: static timelib_sll do_time(timelib_ull hour, timelib_ull minute, timelib_ull second)
                    353: {
                    354:        timelib_sll res = 0;
                    355: 
                    356:        res += hour * 3600;
                    357:        res += minute * 60;
                    358:        res += second;
                    359:        return res;
                    360: }
                    361: 
                    362: static timelib_sll do_adjust_timezone(timelib_time *tz, timelib_tzinfo *tzi)
                    363: {
                    364:        switch (tz->zone_type) {
                    365:                case TIMELIB_ZONETYPE_OFFSET:
                    366: 
                    367:                        tz->is_localtime = 1;
                    368:                        return tz->z * 60;
                    369:                        break;
                    370: 
                    371:                case TIMELIB_ZONETYPE_ABBR: {
                    372:                        timelib_sll tmp;
                    373: 
                    374:                        tz->is_localtime = 1;
                    375:                        tmp = tz->z;
                    376:                        tmp -= tz->dst * 60;
                    377:                        tmp *= 60;
                    378:                        return tmp;
                    379:                        }
                    380:                        break;
                    381: 
                    382:                case TIMELIB_ZONETYPE_ID:
                    383:                        tzi = tz->tz_info;
                    384:                        /* Break intentionally missing */
                    385: 
                    386:                default:
                    387:                        /* No timezone in struct, fallback to reference if possible */
                    388:                        if (tzi) {
                    389:                                timelib_time_offset *before, *after;
                    390:                                timelib_sll          tmp;
                    391:                                int                  in_transistion;
                    392:                                
                    393:                                tz->is_localtime = 1;
                    394:                                before = timelib_get_time_zone_info(tz->sse, tzi);
                    395:                                after = timelib_get_time_zone_info(tz->sse - before->offset, tzi);
                    396:                                timelib_set_timezone(tz, tzi);
                    397: 
                    398:                                in_transistion = (
                    399:                                        ((tz->sse - after->offset) >= (after->transistion_time + (before->offset - after->offset))) &&
                    400:                                        ((tz->sse - after->offset) < after->transistion_time)
                    401:                                );
                    402:                                
                    403:                                if ((before->offset != after->offset) && !in_transistion) {
                    404:                                        tmp = -after->offset;
                    405:                                } else {
                    406:                                        tmp = -tz->z;
                    407:                                }
                    408:                                timelib_time_offset_dtor(before);
                    409:                                timelib_time_offset_dtor(after);
                    410: 
                    411:                                {
                    412:                                        timelib_time_offset *gmt_offset;
                    413: 
                    414:                                        gmt_offset = timelib_get_time_zone_info(tz->sse + tmp, tzi);
                    415:                                        tz->z = gmt_offset->offset;
                    416: 
                    417:                                        tz->dst = gmt_offset->is_dst;
                    418:                                        if (tz->tz_abbr) {
                    419:                                                free(tz->tz_abbr);
                    420:                                        }
                    421:                                        tz->tz_abbr = strdup(gmt_offset->abbr);
                    422:                                        timelib_time_offset_dtor(gmt_offset);
                    423:                                }
                    424:                                return tmp;
                    425:                        }
                    426:        }
                    427:        return 0;
                    428: }
                    429: 
                    430: void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi)
                    431: {
                    432:        timelib_sll res = 0;
                    433: 
                    434:        do_adjust_special_early(time);
                    435:        do_adjust_relative(time);
                    436:        do_adjust_special(time);
                    437:        res += do_years(time->y);
                    438:        res += do_months(time->m, time->y);
                    439:        res += do_days(time->d);
                    440:        res += do_time(time->h, time->i, time->s);
                    441:        time->sse = res;
                    442: 
                    443:        res += do_adjust_timezone(time, tzi);
                    444:        time->sse = res;
                    445: 
                    446:        time->sse_uptodate = 1;
                    447:        time->have_relative = time->relative.have_weekday_relative = time->relative.have_special_relative = 0;
                    448: }
                    449: 
                    450: #if 0
                    451: int main(void)
                    452: {
                    453:        timelib_sll res;
                    454:        timelib_time time;
                    455: 
                    456:        time = timelib_strtotime("10 Feb 2005 06:07:03 PM CET"); /* 1108055223 */
                    457:        printf ("%04d-%02d-%02d %02d:%02d:%02d.%-5d %+04d %1d",
                    458:                time.y, time.m, time.d, time.h, time.i, time.s, time.f, time.z, time.dst);
                    459:        if (time.have_relative) {
                    460:                printf ("%3dY %3dM %3dD / %3dH %3dM %3dS", 
                    461:                        time.relative.y, time.relative.m, time.relative.d, time.relative.h, time.relative.i, time.relative.s);
                    462:        }
                    463:        if (time.have_weekday_relative) {
                    464:                printf (" / %d", time.relative.weekday);
                    465:        }
                    466:        res = time2unixtime(&time);
                    467:        printf("%Ld\n", res);
                    468: 
                    469:        return 0;
                    470: }
                    471: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>