灵活使用PHP和MySQL处理时间

PHP的时间函数很多,用法也多样,而MySQL也有丰富的日期和时间类型进行相应的支持,因此在用PHP和MySQL处理时间时可以灵活一点,尽可能提高代码的可重用性和降低耦合度。

MySQL常用的时间数据类型

在使用MySQL数据库存储时间变量时字段类型尽量使用MySQL已有的时间数据类型,更方便而且效率更高。MySQL常用的时间数据类型如下:

时间类型 存储空间 时间格式
datetime 8 bytes YYYY-MM-DD HH:MM:SS
timestamp 4 bytes YYYY-MM-DD HH:MM:SS
date 3 bytes YYYY-MM-DD
time 3 bytes HH:MM:SS

一般来说,如果需要在数据库存储时间信息,最好把日期和具体时间都纪录下来,即使产品经理提的需求只是日期或者具体时间,以防后面会用到,比如说按时间排序,或者需要以时间为条件查找某些数据,因此最好使用datetime数据类型或者timestamp。代码如下:

1
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'

灵活使用PHP时间函数

有时候产品经理提的需求可能不需要显示完整的日期或者时间信息,比如”11-26 10:00:01”的时间格式,我们在MySQL数据库中存储时间数据时是不是就不能用时间数据类型了呢,而是改用字符串类型等等?大可不必,还是可以用,后面需要显示什么样的时间格式可以由PHP时间函数来完成,譬如显示”11-26 10:00:01”的时间格式可以这样做:

1
$time = date('m-d H:i:s',strtotime($datetime));

将时间变量设为常量以提高代码的可重用性

当然不只是时间变量,只要是用的多的变量都应该设置成常量,要修改只需要修改常量的值即可,而不需要修改所有用到这些变量的代码。我最近写了一个爱视恒恩免费录课活动的后台,因为该活动分为几期进行,我写的第一期,为了提高代码可重用性,将活动开始时间和结束时间等时间变量都设为常量,后面几期活动只需要修改活动开始时间和结束时间即可,其它代码都可以直接搬过来用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
const START_TIME = '2015-11-28 10:00:00';          //活动开始时间
const END_TIME = '2015-12-06 23:59:59'; //活动结束时间
const EVERYDAY_TIME = '10:00:00'; //活动期间每天的开始时间

$start_time = date('Y-m-d')." ".(self::EVERYDAY_TIME); //活动期间每天完整的开始时间
$time = time();
if($time<strtotime(self::START_TIME)){
$join_status = 1; //未到活动开始日期
} elseif($time>strtotime(self::END_TIME)){
$join_status = 2; //活动已经结束
} elseif($time<strtotime($start_time)){
$join_status = 7; //在活动期间,但是没到当天的开始时间
}

获取起始日期和结束日期的日期序列

因为在开发过程中需要按天来取数据库中的数据,因此需要获取从起始日期到结束日期的日期序列,我最开始的做法是直接计算总天数,然后将intval(date(‘d’))加一,这样在下个月的时候intval(date(‘d’))与这个月的intval(date(‘d’))不连续,还要进行判断,代码的耦合度很高,不利于重复利用,正确的姿势应该是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static function getDateSeq($start_date, $end_date) {
$te = strtotime($end_date);
$ts = strtotime($start_date);
if ($te < $ts) { //如果结束日期小于起始日期,则交换
$tmp = $ts;
$ts = $te;
$te = $tmp;
}
$seq = [];
for ($i = $ts; $i <= $te;) {
$currDate = date('Y-m-d', $i);
$i = strtotime("+1 day {$currDate}"); //i自增一天
$seq[] = $currDate;
}
return $seq;
}

或者使用PHP自带的时间类:

1
2
3
4
5
6
7
8
9
10
11
12
public static function getDateRange($start_date, $end_date, $format = 'Y-m-d') {
$begin = new \DateTime($start_date);
$end = new \DateTime($end_date);
$end->modify('+1 day'); // 这个period不包含结束时间
$interval = new \DateInterval('P1D');
$date_range = new \DatePeriod($begin, $interval, $end);
$range = [];
foreach ($date_range as $date) {
$range[] = $date->format($format);
}
return $range;
}