この記事では主にPHP strtotime関数の使い方、実装原理、ソースコード分析を紹介し、strtotime関数の使い方、strtotime関数の実装の基本原理、 strtotime( "-1 month") 評価失敗の理由やその他のコンテンツは、必要な友達が参照できるようにします
ソースコードの場所: 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 *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) {
/* 初期タイムスタンプがあります */
現在 = 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);
今->tz_info = tzi;
現在->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) {
/* 初期タイムスタンプはありません */
現在 = timelib_time_ctor();
今->tz_info = tzi;
現在->zone_type = TIMELIB_ZONETYPE_ID;
timelib_unixtime2local(now, (timelib_sll) time(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 = error->error_count;
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 (error1 || error2) {
RETURN_FALSE;
} 他 {
RETURN_LONG(ts);
}
}
/* }}} */
strtotime(“-1 month”) を使用して前月の今日の日を検索する場合、strtotime 関数にはいくつかの問題が発生します。
ということでこの記事を書きました
この記事には以下の内容が含まれています。1) strtotime関数の使用例
2) strtotime関数実装の基本原則
3) .strtotime(“-1 month”) の評価に失敗した理由
strtotime関数の使用例
1. strtotime(“JAN”) と strtotime(“Monday”)
これら 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.最初のキーワード
最初は補助キーワードで、2011 年の最初の日曜日を見つけるなど、確認値を指定できる平日、日などのキーワードと組み合わせて使用できます。
コードは次のとおりです:echo date("Y-m-d H:i:s", strtotime("第二日曜日", strtotime("2011-01-01"))), "
";
コードは次のとおりです:
switch (time->relative.first_last_day_of) {
ケース 1: /* 最初 */
時間->d = 1;
休憩;
ケース 2: /* 最後 */
時間->d = 0;
時間->m++;
休憩;
}
3. 前後のキーワード
最初と同様に、前のキーワードを週と日と組み合わせて使用して、指定した時刻の曜日または前日を示すことができます。コードは次のとおりです:
コードをコピーします。コードは次のとおりです:
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"))), "
";
最初、前、最後、およびこのキーワードは、re ファイル内の同じグループに属します。
5. 裏と表のキーワード
これら 2 つのキーワードは、その日の時間帯の順方向および逆方向の操作であり、その呼び出し形式は次のとおりです。
コードは次のとおりです:echo date("Y-m-d H:i:s", strtotime("back of 24", strtotime("2011-02-01"))), "
";
";
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 struct Scanner {
int fd;
uchar *lim、*str、*ptr、*cur、*tok、*pos;
unsigned int line、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; /* 時、分、秒 */
Double 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 intzone_type; /* 1 回のオフセット、
* 3 TimeZone識別子、
* 2 TimeZone の略称 */
} timelib_time;
typedef struct timelib_rel_time {
timelib_sll y、m、d; /* 年、月、日 */
timelib_sll h、i、s; /* 時、分、秒 */
int 平日; /* 日を「次の月曜日」に格納します */
int Weekday_behavior; /* 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 ではこのように実現されます。要求によってこの方法を使用できないことが決定されたため、これを要求損失と呼びます。
私はその実現プロセスを観察しましたが、2 番目のパラメータがないため、プログラムは承認された現在の時間を使用しています。 :代码如下:
reltextunit = (('秒'|'秒'|'分'|'分'|'時'|'日'|'二週間'|'フォースナイト'|'月'|'年') 's'?) | '週' |曜日テキスト;
relnumber = ([+-]*[ t]*[0-9]+);
relative = relnumber 空間? (reltextunit | '週' );
一連の操作に関連して、プログラムは前の -1 と次の月の文字列を認識し、月は操作の種類: TIMELIB_MONTH に対応します。 :
代码如下:
case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier;休憩;
上のコードのように、これは直接月の相対値です。ただし、3 月 31 日のような場合、2 月には 31 号がなく、プログラムが自動的に次の月に計算します。
http://www.bkjia.com/PHPjc/952852.html