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

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

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