亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

PHP strtotime函數用法、實現原理和源碼分析

2024-05-04 23:30:55
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了PHP strtotime函數用法、實現原理和源碼分析,本文講解了strtotime函數的一些用法、strtotime函數的實現基本原理、strtotime(“-1 month”)求值失敗的原因等內容,需要的朋友可以參考下
 

源碼位置:/ext/date/php_date.c

復制代碼代碼如下:

/* {{{ proto int strtotime(string time [, int now ])
   Convert string representation of date and time to a timestamp */
PHP_FUNCTION(strtotime)
{
    char *times, *initial_ts;
    int   time_len, error1, error2;
    struct timelib_error_container *error;
    long  preset_ts = 0, ts;

 

    timelib_time *t, *now;
    timelib_tzinfo *tzi;

    tzi = get_timezone_info(TSRMLS_C);

    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, “sl”, ×, &time_len, &preset_ts) != FAILURE) {
        /* We have an initial timestamp */
        now = timelib_time_ctor();

        initial_ts = emalloc(25);
        snprintf(initial_ts, 24, “@%ld UTC”, preset_ts);
        t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); /* we ignore the error here, as this should never fail */
        timelib_update_ts(t, tzi);
        now->tz_info = tzi;
        now->zone_type = TIMELIB_ZONETYPE_ID;
        timelib_unixtime2local(now, t->sse);
        timelib_time_dtor(t);
        efree(initial_ts);
    } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “s|l”, ×, &time_len, &preset_ts) != FAILURE) {
        /* We have no initial timestamp */
        now = timelib_time_ctor();
        now->tz_info = tzi;
        now->zone_type = TIMELIB_ZONETYPE_ID;
        timelib_unixtime2local(now, (timelib_sll) time(NULL));
    } else {
        RETURN_FALSE;
    }

    if (!time_len) {
        timelib_time_dtor(now);    
        RETURN_FALSE;
    }

    t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    error1 = error->error_count;
    timelib_error_container_dtor(error);
    timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
    timelib_update_ts(t, tzi);
    ts = timelib_date_to_int(t, &error2);

    timelib_time_dtor(now);
    timelib_time_dtor(t);

    if (error1 || error2) {
        RETURN_FALSE;
    } else {
        RETURN_LONG(ts);
    }
}
/* }}} */


strtotime函數在使用strtotime(“-1 month”)求上一個月的今天時會出一些狀況,

 

因此也引出寫這篇文章,本文包括如下內容:

1).strtotime函數的一些用法
2).strtotime函數的實現基本原理
3).strtotime(“-1 month”)求值失敗的原因

strtotime函數的一些用法

1、 strtotime(“JAN”)和strtotime(“January”)

這兩個用法的效果是一樣的,都是返回指定月份的今天,如果指定月份沒有今天,則順延到下一個月。 如在2011-03-31計算二月,代碼:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("feb", strtotime("2011-03-31")));

程序會輸出: 2011-03-03 00:00:00。 從表象來看,這個結果也許不一定是我們想要的,但是這也算是一種解決方案,這種方案是由什么決定的呢? strtotime函數在執行月份的計算時只計算了月份,相當于直接將月份設置為指定的月份的值,而如jan,january都會有一個對應內部數值。

 

2、 first關鍵字

first是一個輔助型的關鍵字,它可以與星期,天等可以指定確認值的關鍵字組合使用,如求2011年的第一個星期天:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("second sunday", strtotime("2011-01-01"))), "<br />";

在PHP的源碼中,對于first與星期和天的組合使用是分開的,即first day對應一個處理操作, 在最終的C實現中,天的值指定為1,即time結構中的d字段指定為1,如下代碼:
復制代碼代碼如下:

switch (time->relative.first_last_day_of) {
    case 1: /* first */
        time->d = 1;
        break;
    case 2: /* last */
        time->d = 0;
        time->m++;
        break;
}

3、previous和next關鍵字

 

與first類似,previous關鍵字可以與星期,天組合使用,表示指定時間的前一個星期幾或前一天。如下所示代碼:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("previous sunday", strtotime("2011-02-01"))), "<br />";

程序會輸出:2011-01-30 00:00:00
程序求2011-02-01的前一個星期天。

 

next關鍵字與previous相反,它表示下一個星期幾或后一天。

4、 last關鍵字

last關鍵字既可以作為上一個,也可以作為最后一個。如求上一個星期天的日期:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("last sunday", strtotime("2011-02-05"))), "<br />";

程序會輸出: 2011-01-30 00:00:00

 

當程序作為最后時,其應用場景是指定日期所在月的最后一天,相當于date(“t”)的結果。如求2000年2月的最后一天:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("last day", strtotime("2000-02-01"))), "<br />";

first、previous、last和this關鍵字在re文件中屬于同一組。

 

5、 back和front關鍵字

這兩個關鍵字是對一天中的小時的向前和向后操作,其調用格式如下:

復制代碼代碼如下:

echo date("Y-m-d H:i:s", strtotime("back of 24", strtotime("2011-02-01"))), "<br />";
echo date("Y-m-d H:i:s", strtotime("front of 24", strtotime("2011-02-01"))), "<br />";

back表示將時間設置指定小時值的后一個小時的15分的位置。如果是24點,則算到第二天的0點15分。
front表示將時間設置指定小時值的前一個小時的45分的位置。如果是0點,則算前一天的23點45分。
上面的代碼輸出:2011-02-02 00:15:00 2011-02-01 23:45:00。 其中back of和front of后接的數組必須大于等于0并且小于等于24。

 

strtotime函數的實現基本原理
官方文檔對于strtotime函數的說明是這樣的:本函數預期接受一個包含美國英語日期格式的字符串并嘗試將其解析為 Unix 時間戳 (自 January 1 1970 00:00:00 GMT 起的秒數),其值相對于 now 參數給出的時間,如果沒有提供此參數則用系統當前時間。

這是一個標準PHP內置函數,從PHP4起就已經存在。strtotime函數是以一個擴展的方式加載進來的,在ext/date目錄下有其全部實現。 作為一個標準的內置函數,其定義格式也是標準的,如下:

復制代碼代碼如下:

PHP_FUNCTION(strtotime)
    //  處理輸入,對于是否有第二個參數有沒的處理

 

    //  調用相關函數,實現字符串的解析和結果計算

    //  返回結果
}


在輸入處理中,先識別兩個參數都存在的情況并進行處理,如果不是此種狀態,則處理第二個參數不存在的情況, 如果都沒有,則報錯,返回FALSE。

 

strtotime函數的第一個參數是一個字符串,對于這個字符串,由于其復雜性,PHP使用了其詞法解析一樣的工具:re2c。在/ext/date/lib目錄下,從parse_date.re文件我們可以看到其原始的re文件。 當用戶以參數的形式傳入一個字符串,此字符串將交給此程序處理,針對其字符串的不同,匹配不同的處理函數。 如strtotime(“yesterday”)調用,分析字符串時,將匹配yesterday字符串,此字符串對應函數如下:

復制代碼代碼如下:

'yesterday'
{
    DEBUG_OUTPUT("yesterday");
    TIMELIB_INIT;
    TIMELIB_HAVE_RELATIVE();
    TIMELIB_UNHAVE_TIME();

 

    s->time->relative.d = -1;
    TIMELIB_DEINIT;
    return TIMELIB_RELATIVE;
}


這里有幾個關鍵的結構體:
復制代碼代碼如下:

typedef struct Scanner {
    int           fd;
    uchar        *lim, *str, *ptr, *cur, *tok, *pos;
    unsigned int  line, len;
    struct timelib_error_container *errors;

 

    struct timelib_time *time;
    const timelib_tzdb  *tzdb;
} Scanner;

typedef struct timelib_time {
    timelib_sll      y, m, d;     /* Year, Month, Day */
    timelib_sll      h, i, s;     /* Hour, mInute, Second */
    double           f;           /* Fraction */
    int              z;           /* GMT offset in minutes */
    char            *tz_abbr;     /* Timezone abbreviation (display only) */
    timelib_tzinfo  *tz_info;     /* Timezone structure */
    signed int       dst;         /* Flag if we were parsing a DST zone */
    timelib_rel_time relative;

    timelib_sll      sse;         /* Seconds since epoch */

    unsigned int   have_time, have_date, have_zone, have_relative, have_weeknr_day;

    unsigned int   sse_uptodate; /* !0 if the sse member is up to date with the date/time members */
    unsigned int   tim_uptodate; /* !0 if the date/time members are up to date with the sse member */
    unsigned int   is_localtime; /*  1 if the current struct represents localtime, 0 if it is in GMT */
    unsigned int   zone_type;    /*  1 time offset,
                                  *  3 TimeZone identifier,
                                  *  2 TimeZone abbreviation */
} timelib_time;

typedef struct timelib_rel_time {
    timelib_sll y, m, d; /* Years, Months and Days */
    timelib_sll h, i, s; /* Hours, mInutes and Seconds */

    int weekday; /* Stores the day in 'next monday' */
    int weekday_behavior; /* 0: the current day should *not* be counted when advancing forwards; 1: the current day *should* be counted */

    int first_last_day_of;
    int invert; /* Whether the difference should be inverted */
    timelib_sll days; /* Contains the number of *days*, instead of Y-M-D differences */

    timelib_special  special;
    unsigned int   have_weekday_relative, have_special_relative;
} timelib_rel_time;


s->time->relative.d = -1;所表示的意思是當前時間的相對天數是-1。 這只是中間詞法解析的中間結果,但是最后結果是通過這些中間結果計算出來的。

 

strtotime(“-1 month”)求值失敗的原因

雖然strtotime(“-1 month”)這種方法對于后一個月比前一個月的天數的情況會求值失敗,但是從其本質上來說,這并沒有錯。 PHP這樣實現也無可厚非。只是我們的需求決定了我們不能使用這種方法,因此我們稱其為求值失敗。

我們來看它的實現過程,由于沒有第二個參數,所以程序使用默認的當前時間。 第一個參數傳入的是-1 month字符串,這個字符串所對應的re文件中的正則為:

復制代碼代碼如下:

reltextunit = (('sec'|'second'|'min'|'minute'|'hour'|'day'|'fortnight'|'forthnight'|'month'|'year') 's'?) | 'weeks' | daytext;

 

relnumber = ([+-]*[ /t]*[0-9]+);
relative = relnumber space? (reltextunit | 'week' );


最終relative會對應一系列操作,程序會識別出前面的-1 和后面的month字符串,month對應一種操作類型:TIMELIB_MONTH。 在此之后,根據識別出來的數字和操作類型執行操作,如下代碼:
復制代碼代碼如下:

case TIMELIB_MONTH:  s->time->relative.m += amount * relunit->multiplier; break;

如上代碼,則是直接記錄月份的相對值減一。 但是對于類似于3月31號這樣的情況,2月沒有31號,程序會自動將日期計算到下一個月。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人免费淫片aa视频免费| 久久免费精品日本久久中文字幕| 亚洲国产高潮在线观看| 成人在线精品视频| 国产精品第2页| 97视频在线免费观看| 俺去亚洲欧洲欧美日韩| 亚洲免费视频在线观看| 国产日韩欧美中文| 久热精品视频在线| xvideos成人免费中文版| 日韩经典中文字幕| 亚洲天堂男人的天堂| 亚洲人av在线影院| 97视频在线观看网址| 国产人妖伪娘一区91| 中文字幕在线看视频国产欧美| 国产欧美日韩中文字幕在线| 国产亚洲精品一区二区| 亚洲美女视频网| 久久人人爽人人爽人人片av高清| 搡老女人一区二区三区视频tv| 91在线免费视频| 最近2019年中文视频免费在线观看| 92看片淫黄大片欧美看国产片| 69视频在线播放| 国产精品免费一区二区三区都可以| 91精品国产色综合久久不卡98口| 91精品国产高清久久久久久久久| 一个人看的www久久| 国产精品老女人精品视频| 亚洲最新视频在线| 91国产美女视频| 欧美国产激情18| 北条麻妃在线一区二区| 国产精品普通话| 亚洲天堂久久av| 国产在线观看不卡| 日本国产精品视频| 菠萝蜜影院一区二区免费| 亚洲乱码一区av黑人高潮| 亚洲最新av在线网站| 91中文在线视频| 奇米一区二区三区四区久久| 国产成人亚洲精品| y97精品国产97久久久久久| 欧美性生活大片免费观看网址| 亚洲欧美一区二区三区四区| 91精品国产高清久久久久久91| 中文字幕少妇一区二区三区| 亚洲一级一级97网| 精品久久久久久久大神国产| 午夜欧美大片免费观看| 国产欧美精品一区二区| 国产精品视频一区二区高潮| 亚洲免费电影一区| 欧美在线国产精品| 色多多国产成人永久免费网站| 97视频在线观看视频免费视频| 欧美黄色性视频| 青青青国产精品一区二区| 亚洲伊人成综合成人网| 国产精品揄拍一区二区| 91在线直播亚洲| 欧美极品美女视频网站在线观看免费| 日本91av在线播放| 欧美一性一乱一交一视频| 国产剧情日韩欧美| 日韩在线观看电影| 国产精品人成电影在线观看| 蜜臀久久99精品久久久久久宅男| 亚洲一区二区福利| 国产剧情日韩欧美| 97在线观看视频国产| 欧美福利在线观看| 久久国产精品影片| 久久精品久久久久电影| 久久久欧美一区二区| 69久久夜色精品国产69乱青草| 日韩a**中文字幕| 一区二区三区动漫| 欧美成人合集magnet| 亚洲福利视频网| 亚洲国产精品99久久| 日韩在线中文字| 久久久午夜视频| 国产欧美日韩91| 国产精品久久久久久久美男| 亚洲精品久久在线| 国产91精品久久久久| 亚洲综合中文字幕在线| 欧美最猛黑人xxxx黑人猛叫黄| 国产美女主播一区| 欧美激情中文字幕在线| 久久久精品在线观看| 久久久久久噜噜噜久久久精品| 在线观看国产精品91| 亚洲福利精品在线| 欧美国产日本在线| 亚洲人成人99网站| 久久天天躁狠狠躁夜夜躁| 91网站免费观看| 国产精品视频网| 亚洲欧美国产制服动漫| 91精品视频免费看| 日本精品久久电影| 日韩一级裸体免费视频| 日韩理论片久久| 91在线视频导航| 色久欧美在线视频观看| 这里只有视频精品| 久久久精品国产亚洲| 亚洲国产精品久久久久秋霞蜜臀| 在线观看日韩av| 午夜精品一区二区三区视频免费看| 亚洲国产97在线精品一区| 亚洲高清久久久久久| 久久免费在线观看| 国产精品久久久久久久7电影| 欧美成人激情在线| 亚洲一区二区三区在线免费观看| 国产一区视频在线播放| 久久人人爽人人爽人人片av高请| 日韩人体视频一二区| 亚洲男人天堂视频| 国产精品久久久久久一区二区| 一区二区欧美日韩视频| 日韩一区二区欧美| 一道本无吗dⅴd在线播放一区| 国产一区二区欧美日韩| 久久精品国产v日韩v亚洲| 国产精品久久久久久久久粉嫩av| 亚洲天堂开心观看| 国产精品福利久久久| 91精品国产综合久久久久久久久| 日韩亚洲欧美中文高清在线| 一区二区三区无码高清视频| 92裸体在线视频网站| 在线视频亚洲欧美| 国产精品私拍pans大尺度在线| 中文字幕国内精品| 国产欧美日韩亚洲精品| 国产日韩av在线| 久久精品视频在线播放| 日韩免费av片在线观看| 97视频在线观看免费高清完整版在线观看| 97精品欧美一区二区三区| 日韩亚洲国产中文字幕| 日韩电影视频免费| 狠狠躁18三区二区一区| 欧美日韩中文字幕日韩欧美| 日韩最新在线视频| 欧美另类在线播放| 国产剧情日韩欧美| 日韩av在线播放资源| 亚洲日韩中文字幕在线播放| 国产日韩欧美影视| 日韩欧美国产免费播放| 欧美另类极品videosbest最新版本| xxxxx成人.com| 国产精彩精品视频| 亚洲无限乱码一二三四麻| 黑人欧美xxxx| 欲色天天网综合久久|