我们提到strtotime函数在使用strtotime(”-1 month”)求上一个月的今天时会出一些状况,

因此也引出写这篇文章,本文包括如下内容:

  • strtotime函数的一些用法
  • strtotime函数的实现基本原理
  • 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号,程序会自动将日期计算到下一个月。

strtotime那些事相关推荐

  1. 遇事不责怪别人,换位思考能成全更好的自己

    在生活中,有时候有些人做的某些事可能会让你感觉不爽:这时,你最好不要急着去责怪他:试着把自己放在对方的处境,看看别人的生活,你才能看到人间百态,理解他人的难处. 每个人的生长环境不同,心境就不同:有些 ...

  2. 力所能及的做些自己喜欢和有趣的事

    我们每个人都有自己喜欢做的事:在自己可控且力所能及的情况下,在闲时,按自己的意愿去做些自己喜欢和有趣的事,会感觉到这事很有意义.在忙时,要为理想和奋斗而忙:不浪费时间在无意义的事和人身上. 朋友要的是 ...

  3. 不要纠结于过去发生的事

    在这个社会中,有些人很早就经历了一些不好的事,遇到不好的人:让他留了一些阴影.这时,应该学会不要纠结于过去发生的事情了!一件事情已经发生了,不管再怎么后悔也不能改变结局: 对这件事一直有懊悔之心,只会 ...

  4. 【运维学习笔记】生命不息,搞事开始。。。

    001生命不息,搞事不止!!! 这段时间和hexesdesu搞了很多事情! 之前是机械硬盘和固态硬盘的测速,我就在那默默的看着他一个硬盘一个机械测来测去. 坐在他后面,每天都能看到这位萌萌的小男孩,各 ...

  5. 保护嵌入式802.11 Wi-Fi设备时需要考虑的10件事

    保护嵌入式802.11 Wi-Fi设备时需要考虑的10件事 10 things to consider when securing an embedded 802.11 Wi-Fi device 随着 ...

  6. Python爬虫实战糗事百科实例

    爬取糗事百科段子,假设页面的URL是 http://www.qiushibaike.com/8hr/page/1 要求: 使用requests获取页面信息,用XPath / re 做数据提取 获取每个 ...

  7. strtotime 获取当月最后一天的日期

    strtotime('last day of this month', $timestamp); 转载于:https://www.cnblogs.com/jianzhaojing/p/11244177 ...

  8. 关于.NET玩爬虫这些事 【初码干货】

    这几天在微信群里又聊到.NET可以救中国但是案例太少不深的问题,我说.NET玩爬虫简直就是宇宙第一,于是大神朱永光说,你为何不来写一篇总结一下? 那么今天就全面的来总结一下,在.NET生态下,如何玩爬 ...

  9. 《创业维艰分享之五》所有得,有所乐,日事日清,循序渐进。

    这两个月公司连续做了两个大客户紧接着发布新版本再然后又是连续五个小版本迭代计划. 每天16小时的超强度工作,我已经看到兄弟的脸上都写着一个字:累! 我自己又何尝不是,既是客服,又是程序员,还必须是行政 ...

最新文章

  1. 刻意练习:LeetCode实战 -- Task11. 删除链表的倒数第N个节点
  2. 第十八篇:Question Answering问答系统
  3. Post和Get方法区别
  4. 启动Spark Shell,在Spark Shell中编写WordCount程序,在IDEA中编写WordCount的Maven程序,spark-submit使用spark的jar来做单词统计
  5. 【原】Spark Standalone模式
  6. llmp_install.zip
  7. linux中文系统换英文字体,linux系统下肿么切换字体?
  8. 设计模式——3.观察者模式
  9. 不懂这11个隐藏技巧,别说你会用微信
  10. 人人网,微博,QQ空间,朋友圈,常用API调用实现方法
  11. Git-github 的基本应用
  12. 技术篇-HBase Coprocessor 的实现与应用
  13. C# 线程thread
  14. 深入浅出MyBatis:MyBatis解析和运行原理
  15. FastDFS实现原理及流程
  16. qq音乐 android pad版,QQ音乐HD版
  17. 基于杂化材料银-氨基硅烷氧化石墨烯的化学战剂的电化学传感
  18. gwas snp 和_新的高密度玉米SNP芯片可用于基因组选择、GWAS和群体遗传学
  19. java实验——回文是一种“从前向后读”和“从后向前读”都相同的字符串,如“上海自来水来自海上”。设计一个程序,判断字符串是否是回文。
  20. java severlet 获取当前路径_Java 获取当前路径的方法总结

热门文章

  1. 性能测试工具kylinPET的国产化道路
  2. Python之禅——传说中的蛇宗总纲
  3. windows更新错误0x8024401c
  4. 视频教程-网络营销-网站盈利方式/淘宝客网络赚钱/广告联盟-其他
  5. 分布式事务解决方案之2PC(两阶段提交)入门简介
  6. 【计算机基础】-2万字总结《计算机速成课》全集笔记
  7. Django——admin功能、注册模型类、模型管理类
  8. 老慜的A5作业——p5.js 动态、周期、随机、面向对象
  9. 信息安全数学基础——模重复平方计算法(两种方法实现C+JAVA)
  10. nas系统存储服务器,企业搭建NAS存储服务器的三部曲,你都清楚嘛?