PHP学习笔记
2009-8-15_2
主题:输出可变日期函数:generateAlterableTime()
1 要点
1.1 格式化输出日期,且要求形式可变
这次的难度更大,要根据数据库中存的时间距离现在的时间间隔来输出不同形式的时间字符串。要判断出是数秒前,数分钟前,数小时前,昨天,昨天以前,去年,去年以前。具体的思路在注释里面已经写详细了。
1.2 有用的时间函数:mktime()
1.2.1 这次再说说这个mktime(),它有两个很实用的功能
1.2.1.1 它会自动计算超出范围的输入的正确值,比如下面例子中每一行都会产生字符串 "1998-1-1":
<?php
echo date("Y-m-d", mktime(0, 0, 0, 12, 32, 1997));
echo date("Y-m-d ", mktime(0, 0, 0, 13, 1, 1997));
echo date("Y-m-d ", mktime(0, 0, 0, 1, 1, 1998));
echo date("Y-m-d ", mktime(0, 0, 0, 1, 1, 98));
?>
1.2.1.2 这个月的最后一天 = 下个月的第0天
任何给定月份的最后一天都可以被表示为下个月的第 "0" 天,而不是 -1 天。下面两个例子都会产生字符串 "The last day in Feb 2000 is: 29"。
<?php
$lastday = mktime(0, 0, 0, 3, 0, 2000);
echo strftime("Last day in Feb 2000 is: %d", $lastday);
$lastday = mktime(0, 0, 0, 4, -31, 2000);
echo strftime("Last day in Feb 2000 is: %d", $lastday);
?>
我又试了一下
$lastday = mktime(0, 0, 0, 3, -1, 2000);
echo strftime("Last day in Feb 2000 is: %d", $lastday);
结果输出的是Last day in Feb 2000 is: 28 。
顺便说一下strftime() ,PHP手册中是这样描述的:
strftime — 根据区域设置格式化本地时间/日期
说明
string strftime ( string $format [, int $timestamp] )
返回用给定的格式字串对给出的 timestamp 进行格式输出后的字符串。如果没有给出时间戳则用当前的本地时间。月份和星期几以及其它和语言有关的字符串写法和用 setlocale() 设定的当前的区域有关。
格式字串能识别下列转换标记:
- %a - 当前区域星期几的简写
- %A - 当前区域星期几的全称
- %b - 当前区域月份的简写
- %B - 当前区域月份的全称
- %c - 当前区域首选的日期时间表达
- %C - 世纪值(年份除以 100 后取整,范围从 00 到 99)
- %d - 月份中的第几天,十进制数字(范围从 01 到 31)
- %D - 和 %m/%d/%y 一样
- %e - 月份中的第几天,十进制数字,一位的数字前会加上一个空格(范围从 ' 1' 到 '31')
- %g - 和 %G 一样,但是没有世纪
- %G - 4 位数的年份,符合 ISO 星期数(参见 %V)。和 %V 的格式和值一样,只除了如果 ISO 星期数属于前一年或者后一年,则使用那一年。
- %h - 和 %b 一样
- %H - 24 小时制的十进制小时数(范围从 00 到 23)
- %I - 12 小时制的十进制小时数(范围从 00 到 12)
- %j - 年份中的第几天,十进制数(范围从 001 到 366)
- %m - 十进制月份(范围从 01 到 12)
- %M - 十进制分钟数
- %n - 换行符
- %p - 根据给定的时间值为 `am' 或 `pm',或者当前区域设置中的相应字符串
- %r - 用 a.m. 和 p.m. 符号的时间
- %R - 24 小时符号的时间
- %S - 十进制秒数
- %t - 制表符
- %T - 当前时间,和 %H:%M:%S 一样
- %u - 星期几的十进制数表达 [1,7],1 表示星期一
2 总结
2.1 写注释太重要了,现在麻烦一点,以后轻松一点,不然过一段时间再回过头来看这些没注释的代码我肯定昏头。
2.2 怎么感觉写的注释很累赘啊?最近总觉得表达能力有所退步,今天早上练习英译汉也是的,一句“太阳从升起的地方落下,从落下的地方升起”,我居然就这么照着字面意思翻译了,结果你猜怎么着,人家四个字就解决了——“西升东落”!彻底囧掉了。
小孙:是不是最近天气热造成的啊?
妈妈:居然以客观原因作为借口!拖走拖走!!
小孙(惨叫):NO!
3 源代码
//格式化日期产生函数generateAlterableTime
/*
1 思路说明:
返回值是以$timeStamp和$timeNow的差值决定的
1.1 今年、去年、去年以前的判断:将两个时间戳以Y格式即四位数的年份输出并比较大小,差值大于1则是去年以前,差值等于1则是去年,差值等于0则是今年
1.2 在今年内,今天、昨天、昨天以前的判断:这个时候再比较日(“j”)的大小就不太好了,因为会出现昨天是上月月末而今天是本月月初的情况,
因此需要获得今天及昨天的0点0分0秒的时间戳($timeTodayMidnight和$timeYesterdayMidnight),两者结合作为标准可以判断$timeStamp是在今天、昨天还是昨天以前
1.2.1 $timeStamp >= $timeTodayMidnight则是今天
1.2.2 $timeStamp < $timeTodayMidnight && $timeStamp >= $timeYesterdayMidnight则是昨天
1.2.3 $timeStamp < $timeYesterdayMidnight则是昨天以前
1.3 在今天内,又分为1分钟内、1分钟到1小时内、1小时以前,这时可以通过$timeStamp和$timeNow的秒数差($timeSub)来判断了
1.3.1 $timeSub < 60 1分钟内
1.3.2 $timeSub >= 60 && $timeSub < 3600 1分钟到1小时内
1.3.3 $timeSub > 3600 1小时以前
2 参数说明:
$timeStamp表示要格式化输出的时间戳,就是从数据库中取出的记事的创建时间或最后修改时间
另一个参数$timeNow表示现在的时间,一般就用函数time()
3 返回值说明:
根据差值的不同,返回格式化后的时间字符串,格式可变:
3.1 在去年以前则返回:Y年n月j日
3.2 在去年则返回:去年n月j日
3.3 在今年,且是昨天以前,则返回:n月j日
3.4 在今年,且是昨天,则返回:昨天H:i
3.5 在今年,且是今天,1小时以前写的记事,则返回:H:i
3.6 在今年,且是今天,1分钟以前但不超过1小时写的记事,则返回:(int)($timeSub / 60)分钟前(强制类型转换)
3.7 在今年,且是今天,1分钟以内则返回:$timeSub秒前
*/
function generateAlterableTime($timeStamp, $timeNow)
{
$timeResult = "以前";//初始化用于返回值的变量
if($timeNow >= $timeStamp)//满足这个条件才能计算出正确的时间值
{
if(date("Y", $timeNow) - date("Y", $timeStamp) > 1)//去年以前则返回:X年X月X日
{
$timeResult = date("Y年n月j日", $timeStamp);
//return $timeResult;
}
else if(date("Y", $timeNow) - date("Y", $timeStamp) == 1)//恰好是去年则返回:去年X月X日
{
$timeResult = date("去年n月j日", $timeStamp);
//return $timeResult;
}
else//时间就在今年,也就是date("Y", $timeNow) - date("Y", $timeStamp) == 0,
//或者说date("Y", $timeNow) == date("Y", $timeStamp),因为前面有条件保证$timeNow >= $timeStamp,
//所以不可能出现date("Y", $timeNow) - date("Y", $timeStamp) < 0,
//亦即date("Y", $timeNow) < date("Y", $timeStamp)的情况
{
//获得当天及昨天的0点0分0秒的时间戳,两者结合作为标准可以判断$timeStamp是在当天、昨天还是昨天以前
$timeTodayMidnight = mktime(0, 0, 0, date("n"), date("j"), date("Y"));//获得当天0点0分0秒的时间戳
$timeYesterdayMidnight = $timeTodayMidnight - 24 * 3600;//获得昨天0点0分0秒的时间戳
if($timeStamp >= $timeTodayMidnight)//在当天
{
$timeSub = $timeNow - $timeStamp;//根据时间差来决定显示什么样格式的时间
if($timeSub < 60)//60秒以内则返回:X秒前
{
$timeResult = $timeSub."秒前";
}
else if($timeSub >= 60 && $timeSub < 3600)//1小时以内则返回:X分钟前
{
$timeResult = ((int)($timeSub / 60))."分钟前";//强制类型转换,否则结果是浮点数
}
else//1小时以上则返回:时:分
{
$timeResult = date("H:i", $timeStamp);
}
//return $timeResult;
}
else if($timeStamp < $timeTodayMidnight && $timeStamp >= $timeYesterdayMidnight)//在昨天则返回:昨天 时:分
{
$timeResult = "昨天".date("H:i", $timeStamp);
}
else//在昨天以前则返回:X月X日
{
$timeResult = date("n月j日", $timeStamp);
}
}
}
else//$timeNow < $timeStamp则输出generateDateWeekTime($timeStamp)(这种情况应该不会发生,除非系统时间出了问题)
{
return generateDateWeekTime($timeStamp);
}
return $timeResult;
}