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

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: 
        !            19: /* $Id: tm2unixtime.c 320481 2011-12-06 06:21:08Z derick $ */
        !            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>