源码位置:\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); } } /* }}} */
因此也引出写这篇文章,本文包括如下内容:
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")));
2、 first关键字
first是一个辅助型的关键字,它可以与星期,天等可以指定确认值的关键字组合使用,如求2011年的第一个星期天:
echo date("Y-m-d H:i:s", strtotime("second sunday", strtotime("2011-01-01"))), "<br />";
switch (time->relative.first_last_day_of) { case 1: /* first */ time->d = 1; break; case 2: /* last */ time->d = 0; time->m++; break; }
与first类似,previous关键字可以与星期,天组合使用,表示指定时间的前一个星期几或前一天。如下所示代码:
echo date("Y-m-d H:i:s", strtotime("previous sunday", strtotime("2011-02-01"))), "<br />";
next关键字与previous相反,它表示下一个星期几或后一天。
4、 last关键字
last关键字既可以作为上一个,也可以作为最后一个。如求上一个星期天的日期:
echo date("Y-m-d H:i:s", strtotime("last sunday", strtotime("2011-02-05"))), "<br />";
当程序作为最后时,其应用场景是指定日期所在月的最后一天,相当于date(“t”)的结果。如求2000年2月的最后一天:
echo date("Y-m-d H:i:s", strtotime("last day", strtotime("2000-02-01"))), "<br />";
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 />";
strtotime函数的实现基本原理
官方文档对于strtotime函数的说明是这样的:本函数预期接受一个包含美国英语日期格式的字符串并尝试将其解析为 Unix 时间戳 (自 January 1 1970 00:00:00 GMT 起的秒数),其值相对于 now 参数给出的时间,如果没有提供此参数则用系统当前时间。
这是一个标准PHP内置函数,从PHP4起就已经存在。strtotime函数是以一个扩展的方式加载进来的,在ext/date目录下有其全部实现。 作为一个标准的内置函数,其定义格式也是标准的,如下:
PHP_FUNCTION(strtotime) // 处理输入,对于是否有第二个参数有没的处理// 调用相关函数,实现字符串的解析和结果计算
// 返回结果 }
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;
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' );
case TIMELIB_MONTH: s->time->relative.m += amount * relunit->multiplier; break;
本文向大家介绍java并发容器CopyOnWriteArrayList实现原理及源码分析,包括了java并发容器CopyOnWriteArrayList实现原理及源码分析的使用技巧和注意事项,需要的朋友参考一下 CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策
本文向大家介绍JS高阶函数原理与用法实例分析,包括了JS高阶函数原理与用法实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JS高阶函数原理与用法。分享给大家供大家参考,具体如下: 如果您正在学习JavaScript,那么您必须遇到高阶函数这个术语。这听起来复杂,其实不然。 使JavaScript适合函数式编程的原因是它接受高阶函数。 高阶函数在JavaScript中广泛使用。如果你
本文向大家介绍jQuery中noconflict函数的实现原理分解,包括了jQuery中noconflict函数的实现原理分解的使用技巧和注意事项,需要的朋友参考一下 jQuery中,noconflict是用来防止变量冲突,用来释放变量控制权的一个重要方法。我们知道,jQuery中对外提供有两个全局变量,$和jQuery,虽然jQuery只产生了两个全局变量,极少情况下才会出现冲突,但是如果网页中
本文向大家介绍全排列算法的原理和实现代码,包括了全排列算法的原理和实现代码的使用技巧和注意事项,需要的朋友参考一下 全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个。现以{1, 2, 3, 4, 5}为例说明如何编写全排列的递归算法。 1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。 由于一个数的全排列就是其本
没用过Hystrix,想知道怎么使用,以及如何掌握? 在分布式开发中Hystrix被经常听到,想知道怎么上手?
paginate 分页 laravel 的分页用起来非常简单,只需要对 query 调用 paginate 函数,把返回的对象扔给前端 blade 文件,在 blade 文件调用函数 render 函数或者 link 函数,就可以得到 上一页、下一页 等等分页特效。 实际上,我们可以简单地把分页服务看作一个前端资源,render 函数或者 link 函数的结果就是分页前端代码。 如果你还对 lar