ホームページ >バックエンド開発 >PHPチュートリアル >PHP strtotime 関数の使用法、実装原理とソース コード分析、strtotime 関数_PHP チュートリアル

PHP strtotime 関数の使用法、実装原理とソース コード分析、strtotime 関数_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 10:08:02822ブラウズ

PHP strtotime関数の使い方、実装原理とソースコード分析、strtotime関数

ソースコードの場所: extdatephp_date.c

コードをコピーします コードは次のとおりです:

/* {{{ proto int strtotime(string time [, int now ])
日付と時刻の文字列表現をタイムスタンプに変換します */
PHP_FUNCTION(strtotime)
{
char *times, *initial_ts;
int time_len, error1, error2;
struct timelib_error_container *エラー;
ロングプリセット_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) {
/* 初期タイムスタンプがあります */
今 = 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) /* これは失敗しないはずなので、ここではエラーを無視します */
Timelib_update_ts(t, tzi);
now->tz_info = tzi;
now->zone_type = TIMELIB_ZONETYPE_ID;
Timelib_unixtime2local(今、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) {
/* 初期タイムスタンプがありません */
今 = timelib_time_ctor();
now->tz_info = tzi;
now->zone_type = TIMELIB_ZONETYPE_ID;
Timelib_unixtime2local(現在、(timelib_sll) 時間(NULL));
} その他 {
RETURN_FALSE;
}

if (!time_len) {
Timelib_time_dtor(現在)
RETURN_FALSE;
}

t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
error1 = エラー->エラー数;
Timelib_error_container_dtor(エラー);
Timelib_fill_holes(t、今、TIMELIB_NO_CLONE);
Timelib_update_ts(t, tzi);
ts = timelib_date_to_int(t, &error2);

timelib_time_dtor(現在);
Timelib_time_dtor(t);

if (エラー 1 || エラー 2) {
RETURN_FALSE;
} その他 {
RETURN_LONG(ts);
}
}
/* }}} */


strtotime("-1 month") を使用して前月の今日の日を検索する場合、strtotime 関数にはいくつかの問題が発生します。

これは、次の内容を含むこの記事を書くきっかけにもなりました:

1) .strtotime 関数の使用例
2) strtotime関数実装の基本原則
3) .strtotime(“-1 month”) の評価に失敗した理由

strtotime関数の使用例

1. strtotime(「JAN」) と strtotime(「1 月」)

これら 2 つの使用法の効果はどちらも同じです。指定した月に今日がない場合は、次の月に延期されます。 たとえば、2 月が 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 は補助キーワードであり、2011 年の最初の日曜日を検索するなど、確認値を指定できる曜日、曜日などのキーワードと組み合わせて使用​​できます。

コードをコピーします コードは次のとおりです:
echo date("Y-m-d H:i:s", strtotime("第 2 日曜日", strtotime("2011-01-01"))), "
";

PHP ソース コードでは、first、week、day の組み合わせは別々に使用されます。つまり、first day は処理操作に対応し、最終的な C 実装では、day の値は 1、つまり d フィールドに指定されます。時間構造体の は 1 として指定されます。次のコード:

コードをコピーします コードは次のとおりです:
switch (時間->相対.first_last_day_of) {
ケース 1: /* 最初 */
時間->d = 1;
休憩;
ケース 2: /* 最後 */
時間>d = 0;
時間->m++;
休憩;
}

3. 前後のキーワード
first と同様に、前のキーワードは、week および day と組み合わせて使用​​して、指定した時刻の曜日または前日を示すことができます。コードは次のとおりです:


コードをコピーします コードは次のとおりです:
echo date("Y-m-d H:i:s", strtotime("前の日曜日", strtotime("2011-02-01"))), "
";

プログラムは次のように出力します: 2011-01-30 00:00:00
プログラムは 2011 年 2 月 1 日より前の日曜日を探します。
次のキーワードは前のキーワードの逆で、次の曜日または翌日を意味します。

4. 最後のキーワード

最後のキーワードは、前または最後のキーワードとして使用できます。先週の日曜日の日付が必要な場合:


コードをコピーします コードは次のとおりです:
echo date("Y-m-d H:i:s", strtotime("最後の日曜日", strtotime("2011-02-05"))), "
";

プログラムは次のように出力します: 2011-01-30 00:00:00
プログラムが最後として使用される場合、その適用シナリオは指定された日付が位置する月の最終日であり、これは date("t") の結果と同等です。 2000 年 2 月の最後の日についてお問い合わせください:


コードをコピーします コードは次のとおりです:
echo date("Y-m-d H:i:s", strtotime("最終日", strtotime("2000-02-01"))), "
";

first、previous、last、および this キーワードは、re ファイル内の同じグループに属します。
5. 裏と表のキーワード

これら 2 つのキーワードは、その日の時間帯の順方向および逆方向の操作であり、その呼び出し形式は次​​のとおりです:


コードをコピーします コードは次のとおりです:
echo date("Y-m-d H:i:s", strtotime("back of 24", strtotime("2011-02-01"))), "
";
echo date("Y-m-d H:i:s", strtotime("front of 24", strtotime("2011-02-01"))), "
";

back は、指定した時の値の 15 分後に時刻を設定することを意味します。 24:00の場合は翌日の0:15までカウントされます。
「front」は、指定された時間値の 45 分前に時間を設定することを意味します。 0時なら前日の23時45分として計算されます。
上記のコードは、2011-02-02 00:15:00 2011-02-01 23:45:00 を出力します。 配列の後に後部と前部が続く場合は、0 以上、24 以下である必要があります。

strtotime関数実装の基本原則
公式ドキュメントでは、strtotime 関数について次のように説明しています: この関数は、米国英語の日付形式を含む文字列を受け入れ、それを Unix タイムスタンプ (1970 年 1 月 1 日 00:00:00 GMT からの秒数) に解析しようとします。 、その値は、now パラメータで指定された時刻を基準としています。このパラメータが指定されていない場合は、現在のシステム時刻が使用されます。

これは、PHP4 から存在する標準の PHP 組み込み関数です。 strtotime 関数は拡張機能としてロードされ、その完全な実装は ext/date ディレクトリで入手できます。 標準の組み込み関数として、その定義形式も次のように標準です。


コードをコピーします コードは次のとおりです:

PHP_FUNCTION(strtotime)
// 2 番目のパラメーターがあるかどうかに関係なく、入力を処理します

// 関連関数を呼び出して文字列の解析と結果の計算を実装します

// 結果を返す
}


入力処理では、まず両方のパラメータが存在する状況が識別されて処理され、この状態にない場合は、2 番目のパラメータが存在しない状況が処理され、どちらのパラメータも存在しない場合はエラーが報告され、FALSE が返されます。 。

strtotime 関数の最初のパラメータは文字列です。この文字列は複雑であるため、PHP は字句解析と同じツール re2c を使用します。 /ext/date/lib ディレクトリでは、parse_date.re ファイルから元の re ファイルを確認できます。 ユーザーがパラメータの形式で文字列を渡すと、その文字列は処理のためにこのプログラムに渡され、異なる文字列に応じて異なる処理関数が照合されます。 たとえば、strtotime("yesterday") が呼び出された場合、文字列を分析するときに、昨日の文字列が照合されます。この文字列に対応する関数は次のとおりです。

コードをコピーします コードは次のとおりです:
「昨日」
{
DEBUG_OUTPUT("昨日");
TIMELIB_INIT;
TIMELIB_HAVE_RELATIVE();
TIMELIB_UNHAVE_TIME();
s->time->relative.d = -1;

TIMELIB_DEINIT;
TIMELIB_RELATIVE を返します;
}

以下にいくつかの主要な構造を示します:

コードをコピーします コードは次のとおりです:

typedef 構造体スキャナー {
    int fd;
    uchar *lim、*str、*ptr、*cur、*tok、*pos;
    unsigned int 行、len;
    struct timelib_error_container *エラー;

struct timelib_time *time;
    const timelib_tzdb *tzdb;
スキャナ;

typedef struct timelib_time {
    timelib_sll y、m、d;     /* 年、月、日 */
    timelib_sll h、i、s;     /* 時、分、秒 */
    ダブル f;           /* 分数 */
    int z;           /* GMT オフセット (分単位) */
    char *tz_abbr;     /* タイムゾーンの省略形 (表示のみ) */
    timelib_tzinfo *tz_info;     /* タイムゾーン構造 */
    signed int dst;         /* DST ゾーンを解析しているかどうかを示すフラグ */
    timelib_rel_time 相対時間;

timelib_sll sse;         /* エポックからの秒数 */

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

unsigned int sse_uptodate; /* !0 sse メンバーの日付/時刻メンバーが最新の場合 */
    unsigned int tim_uptodate; /* 日時メンバーが sse メンバーと最新の場合は !0 */
    unsigned int is_localtime; /* 現在の構造体が現地時間を表す場合は 1、GMT の場合は 0 */
    unsigned int zone_type;    /* 1 回のオフセット、
                                  * 3 タイムゾーン識別子、
                                  * 2 タイムゾーンの略称 */
} timelib_time;

typedef struct timelib_rel_time {
    timelib_sll y、m、d; /* 年、月、日 */
    timelib_sll h、i、s; /* 時、分、秒 */

int 平日; /* 日を「次の月曜日」に格納します */
    int 平日の動作; /* 0: 前に進むときに、現在の日は「カウントされません」。 1: 現在の日を*カウントする必要があります*/

int first_last_day_of;
    int 反転; /* 差を反転する必要があるかどうか */
    timelib_sll 日。 /* Y-M-D の差ではなく、*日* の数が含まれます */

timelib_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 か月の文字列であり、この文字列に対応するファイル内の正確な値は次のとおりです。 :


复制代码代码如下:
reltextunit = (('秒'|'秒'|'分'|'分'|'時'|'日'|'二週間'|'昨夜'|'月'|'年') 's'?) | '週' |曜日テキスト;

relnumber = ([+-]*[t]*[0-9]+); 相対 = relnumber スペース? (reltextunit | '週' );



最終的に、相対は一連の操作に対応し、プログラムは先頭の -1 と後ろの月文字列を認識します: TIMELIB_MONTH。 この後、次のコードに示すように、識別された番号と操作の種類に基づいて操作を実行します。

コードをコピーします コードは次のとおりです:
case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier;

上記のコードは、月から 1 を引いた相対値を直接記録します。 ただし、2 月に 31 日がない 3 月 31 日のような状況では、プログラムは自動的に翌月までの日付を計算します。

http://www.bkjia.com/PHPjc/953146.htmlwww.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/953146.html技術記事 PHP strtotime 関数の使用法、実装原理とソース コード分析、strtotime 関数のソース コードの場所: extdatephp_date.c 次のようにコードをコピーします: /* {{{ proto int strtotime(string time [, i...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。