美文网首页跟兄弟连学PHP
15.PHP的日期和时间

15.PHP的日期和时间

作者: 乐乐凡凡 | 来源:发表于2019-12-07 22:43 被阅读0次

    在Web程序开发时,时间发挥着重要的作用。不仅在数据存储和显示时需要日期和时间的参与,很多功能模块的开发,时间通常都是至关重要的。

    1.UNIX时间戳

    • 以32位的整数表示格林尼治标准时间,例如,使用整数11230499325表示当前时间的时间戳。
    • UNIX时间戳是从1970年1月1日零点(UTC/GMT的午夜)开始起到当前时间所经过的秒数。
    • 1970年1月1日零点作为所有日期计算的基础,这个日期通常称为UNIX纪元。

    因为UNIX时间戳是一个32位的数字格式,所以特别适用于计算机处理,例如计算两个时间点之间相差的天数。

    另外,由于文化和地区的差异,存在不同的时间格式,以及时区的问题。

    所以UNIX时间戳也是根据一个时区进行标准化而设计的一种通用格式,并且这种格式可以很容易地转换为任何格式。

    也因为UNIX时间戳是一个32位的整数表示的,所以在处理1970年以前或2038年以后的事件时,将会遇到一些问题。

    另外,在Windows系统下,由于时间戳不能为负数,如果使用PHP中提供的时间戳函数处理1970年之前的日期,就会发生错误。要使PHP代码具有可移植性,必须记住这一点。

    1.1. 将日期和时间转变成UNIX时间戳

    mktime()

    原型:

    mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )
    

    作用:将日期和时间转为UNIX时间戳

    详情:https://www.php.net/manual/zh/function.mktime.php

    该函数中所有参数都是可选的,如果参数为空,默认将当前时间转变成UNIX时间戳。

    这样,和直接调用time()函数获取当前的UNIX时间戳功能相同。

    参数也可以从右向左省略,任何省略的参数会被设置成本地日期和时间的当前值。

    如果只想转变日期,对具体的时间不在乎,可以将前三个转变时间的参数都设置为0。

    mktime()函数对于日期运算和验证非常有用,它可以自动校正越界的输入。如下所示:

    //日期超过31天,计算后输出Jan-05-2008
    echo date("M-d-Y", mktime(0, 0, 0, 12, 36, 2007))."\n";  
    //月份超过12月,计算后输出Feb-01-2009
    echo date("M-d-Y", mktime(0, 0, 0, 14, 1, 2008))."\n";   
    //没有问题的转变,输出结果 Jan-01-2009
    echo date("M-d-Y", mktime(0, 0, 0, 1, 1, 2009))."\n"; 
    //会将99年转变为1999年, Jan-01-1999
    echo date("M-d-Y", mktime(0, 0, 0, 1, 1, 99))."\n";      
    

    strtotime()

    原型:

    int strtotime( string $time[, int $now = time()] )
    

    作用: 将任何英文文本的日期时间描述直接解析为UNIX时间戳 。

    1.2.日期的计算

    在PHP中,计算两个日期之间相隔的长度,最简单的方法就是通过计算两个UNIX时间戳之差来获得。例如,在PHP脚本中接收来自HTML表单用户提交的出生日期,计算这个用户的年龄。代码如下所示:

    image-20191207221437140.png

    在以上脚本中,调用mktime()函数将从用户出生日期转变为UNIX时间戳,再调用time()函数获取当前时间的UNIX时间戳。因为这个日期的格式都是使用整数表示的,所以可以将它们相减。又将计算后获取的UNIX时间戳除以一年的秒数,将UNIX时间戳转变为以年度量的单位。

    2.在PHP中获取日期和时间

    PHP提供了多种获取日期和时间的函数 。

    2.1. 调用getdate()函数取得日期/时间信息

    2.2. 日期和时间格式化输出date()

    当日期和时间需要保存或计算时,应该使用UNIX时间戳作为标准格式,这可以作为一条重要的规则。但UNIX时间戳的格式可读性比较差,所以要把时间戳格式化为可读性更好的日期和时间,或格式化为其他软件需要的格式。在PHP中可以调用date()函数格式化一个本地日期和时间 。

    3.修改PHP的默认时区

    每个地区都有自己的本地时间,在网上及无线电通信中,时间的转换问题显得格外突出。

    整个地球分为24个时区,每个时区都有自己的本地时间。

    在国际无线电或网络通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(Universal Time Coordinated,UTC),是由世界时间标准设定的全球标准时间。UTC原先也被称为格林尼治标准时间(Greenwich Mean Time,GMT),都与英国伦敦的本地时间相同。

    PHP默认的时区设置是UTC时间,而北京正好位于时区的东八区,领先UTC 8个小时。所以在使用PHP中像time()等获取当前时间的函数时,得到的时间总是不对,其表现是和北京时间相差8个小时。如果希望正确地显示北京时间,就需要修改默认的时区设置。可以通过以下两种方式完成。

    • 如果使用的是独立的服务器,有权限修改配置文件,设置时区就可以通过修改php.ini中的date.timezone属性完成。我们可以将这个属性的值设置为Asia/Shang、Asia/Chongqing、Etc/GMT-8或PRC等中的一个,再在PHP脚本中获取的当前时间就是北京时间。
    • 如果使用的是共享服务器,没有权限修改配置文件php.ini,并且PHP版本又在5.1.0以上,也可以在输出时间之前调用date_default_timezone_set()函数设置时区。该函数需要提供一个时区标识符作为参数,和配置文件中date.timezone属性的值相同。

    4. 使用微秒计算PHP脚本执行时间

    在PHP中,大多数的时间格式都是以UNIX时间戳表示的,而UNIX时间戳是以s(秒)为最小的计量时间的单位。这对某些应用程序来说不够精确,所以可以调用microtime()函数返回当前UNIX时间戳和微秒数。该函数的原型如下:

    mixed microtime([ bool $get_as_float] )
    

    可以为该函数提供一个可选的布尔型参数,如果在调用时不提供这个参数,本函数以“msec sec”的格式返回一个字符串。其中sec是自UNIX纪元起到现在的秒数,而msec是微秒部分,字符串的两部分都是以秒为单位返回的。

    如果给出了get_as_float参数并且其值等价于TRUE,则microtime()函数将返回一个浮点数。

    在小数点前面还是以时间戳的格式表示,而小数点后面则表示微秒的值。

    但要注意参数get_as_float是在PHP 5中新加的,所以在PHP 5以前的版本中,不能直接使用该参数请求一个浮点数。

    在下面的例子中通过两次调用microtime()函数,计算运行PHP脚本所需的时间。代码如下所示:

    class Timer {                              //声明一个计算脚本运行时间的类
        private $startTime;                //保存脚本开始执行时的时间(以微秒的形式保存)
        private $stopTime;                 //保存脚本结束执行时的时间(以微秒的形式保存)
        
        function __construct(){            //构造方法,在创建对象时初使化成员属性
            $this->startTime=0;        //初使化成员属性startTime的值为0
            $this->stopTime=0;         //初使化成员属性stopTime的值为0
        }
            
        function start(){                           //在脚本开始处调用获取脚本开始时间的微秒值
            $this->startTime = microtime(true);     //将获取的时间赋给成员属性$startTime
        }
    
        function stop(){                            //在脚本结束处调用获取脚本结束时间的微秒值
            $this->stopTime= microtime(true);       //将获取的时间赋给成员属性$stopTime
        }
        function spent(){                           //返回同一脚本中两次获取时间的差值
            return round(($this->stopTime- $this->startTime) , 4);  //计算后以4舍5入保留4位返回
        }
    }
    
    $timer = new Timer();                //创建Timer类的对象
    $timer->start();                     //在脚本文件开始执行时调用这个方法
    usleep(1000);                        //脚本的主体内容,这里以休眠一毫秒为例
    $timer->stop();                      //在脚本文件结尾处调用这个方法
    echo "执行该脚本用时<b>".$timer->spent()."</b>秒";     //输出页面执行时运行的时间
    
    

    5.日历类

    说到对日期和时间的处理,就一定要介绍一下日历程序的编写。但一提起编写日历,大多数读者都会认为日历的作用只是为了在页面上显示当前的日期,其实日历在我们的开发中有着更重要的作用。

    例如,我们开发一个“记事本”就需要通过日历设定日期,在一些系统中需要按日期去安排任务也需要日历,等等。

    本例涉及的日期和时间函数并不是很多,都是前面介绍的内容,主要是通过一个日历类的编写,巩固一下前面介绍过的面向对象的语法知识,以及时间函数应用,最主要的是可以提升初学者的思维逻辑和程序设计能力。

    将日历类Calendar声明在文件calendar.class.php中,代码如下所示:

    /*
        file:calendar.class.php 日历类原文件
        声明一个日历类,名称为Calendar,用来显示一个可以设置日期的日历
    */
    class Calendar {
        private $year;                    //当前的年
        private $month;                   //当前的月
        private $start_weekday;           //当月的第一天对应的是周几,作为当月开始遍历日期的开始
        private $days;                    //当前月一总天数
    
        /* 构造方法,用来初使化一些日期属性  */
        function __construct(){
            /* 如果用户没有设置年份数,则使用当前系统时间的年份 */
            $this->year = isset($_GET["year"]) ? $_GET["year"] : date("Y");
            /* 如果用户没有设置月份数,则使用当前系统时间的用份 */
            $this->month = isset($_GET["month"]) ? $_GET["month"] : date("m");
            /* 通过具体的年份和月份,利用date()函数的w参数获取当月第一天对应的是周几 */
            $this->start_weekday = date("w", mktime(0, 0, 0, $this->month, 1, $this->year));
            /* 通过具体的年份和月份,利用date()函数的t参数获取当月的天数 */
            $this->days = date("t", mktime(0, 0, 0, $this->month, 1, $this->year));
        }
        
        /* 魔术方法用于打印整个日历 */
        function __toString(){
            $out .= '<table align="center">'; //日历以表格形式打印
            $out .= $this->chageDate();       //调用内部私有方法用于用户自己设置日期
            $out .= $this->weeksList();       //调用内部私有方法打印“周”列表
            $out .= $this->daysList();        //调用内部私有方法打印“日”列表
            $out .= '</table>';               //表格结束
            return $out;                      //返回整个日历输出需要的全部字符串
        }
        
        /* 内部调用的私有方法,用于输出周列表 */
        private function weeksList(){
            $week = array('日','一','二','三','四','五','六');
    
            $out .= '<tr>';
            for($i = 0; $i < count($week); $i++)
                $out .= '<th class="fontb">'.$week[$i].'</th>'; //第一行以表格<th>形式输出周列表
    
            $out .= '</tr>';
            return $out;                      //返回周列表字符串  
        }
        
        /* 内部调用的私有方法,用于输出日列表 */
        private function daysList(){
            $out .= '<tr>';
            /* 输出空格(当前一月第一天前面要空出来) */
            for($j = 0; $j < $this->start_weekday; $j++)
                $out .= '<td>&nbsp;</td>';
    
            /* 将当月的所有日期循环遍历出来,如果是当前日期,为其设置深色背景 */
            for($k = 1; $k <= $this->days; $k++){
                $j++;
                if($k == date('d'))
                    $out .= '<td class="fontb">'.$k.'</td>';
                else
                    $out .= '<td>'.$k.'</td>';
                
                if($j%7 == 0)                        //每输出7个日期,就换一行
                    $out .= '</tr><tr>';             //输出行结束和下一行开始
            }
    
            while($j%7 !== 0){                       //遍历完日期后,将后面用空格补齐 
                $out .= '<td>&nbsp;</td>';           //使用空格去补
                $j++;
            }
    
            $out .= '</tr>';
            return $out;                             //返回当月日期列表
        }
        
        /* 内部调用的私有方法,用于处理当前年份的上一年需要的数据 */
        private function prevYear($year, $month){
            $year = $year-1;                         //上一年是当前年减1
            
            if($year < 1970)                         //如果设置的年份小于1970年
                $year = 1970;                        //年份设置最小值是1970年
    
            return "year={$year}&month={$month}";    //返回最终的年份和月份设置参数
        }
    
        /* 内部调用的私有方法,用于处理当前月份的上一月份的数据 */
        private function prevMonth($year, $month){
            if($month == 1) {                       //如果月份已经是1月
                $year = $year -1;                   //则上一个月份,就是上一年的最后一月
        
                if($year < 1970)                    //和前面一样,上一年如果是最1970年
                    $year = 1970;                   //最小年数不能小于1970年
    
                $month=12;                          //如果月是1月,上一月就是上一年的最后一月
            }else{
                $month--;                           //上一月就是当前月减1
            }
    
            return "year={$year}&month={$month}";   //返回最终的年份和月份设置参数
        }
    
        /* 内部调用的私有方法,用于处理当前年份的下一年份的数据 */
        private function nextYear($year, $month){
            $year = $year + 1;                       //下一年是当前年加1
    
            if($year > 2038)                         //如果设置的年份大于2038年
                $year = 2038;                        //最大年份不能超过2038年
    
            return "year={$year}&month={$month}";    //返回最终的年份和月份设置参数
        }
    
        /* 内部调用的私有方法,用于处理当前月份的下一个月份的数据 */
        private function nextMonth($year, $month){
            if($month == 12){                        //如果已经是当年的最后一个月
                $year++;                             //下一个月就是下一年的第一个月,让年份加1年
    
                if($year > 2038)                     //如果设置的年份大于2038年
                    $year = 2038;                    //最大年份不能超过2038年
    
                $month = 1;                          //设置月份为下一年的第1月
            }else{
                $month++;                            //其它月份的下一个月都是当前月份加1即可
            }
            
            return "year={$year}&month={$month}";    //返回最终的年份和月份设置参数
        }
    
        //内部调用的私有方法,用于用户操作去调整年份和月份的设置
        private function chageDate($url="index.php"){
            $out .= '<tr>';
            $out .= '<td><a href="'.$url.'?'.$this->prevYear($this->year, $this->month).'">'.'<<'.'</a></td>';
            $out .= '<td><a href="'.$url.'?'.$this->prevMonth($this->year, $this->month).'">'.'<'.'</a></td>';
            
            $out .= '<td colspan="3">';
            $out .= '<form>';
            $out .= '<select name="year" onchange="window.location=\''.$url.'?year=\'+this.options[selectedIndex].value+\'&month='.$this->month.'\'">';
            for($sy=1970; $sy <= 2038; $sy++){
                $selected = ($sy==$this->year) ? "selected" : "";
                $out .= '<option '.$selected.' value="'.$sy.'">'.$sy.'</option>';
            }
            $out .= '</select>';
            $out .= '<select name="month"  onchange="window.location=\''.$url.'?year='.$this->year.'&month=\'+this.options[selectedIndex].value">';
            for($sm=1; $sm<=12; $sm++){
                $selected1 = ($sm==$this->month) ? "selected" : "";
                $out .= '<option '.$selected1.' value="'.$sm.'">'.$sm.'</option>';
            }
            $out .= '</select>';
            $out .= '</form>';  
            $out .= '</td>';
    
            $out .= '<td><a href="'.$url.'?'.$this->nextYear($this->year, $this->month).'">'.'>>'.'</a></td>';
            $out .= '<td><a href="'.$url.'?'.$this->nextMonth($this->year, $this->month).'">'.'>'.'</a></td>';
            $out .= '</tr>';
            return $out;                              //返回调整日期的表单
        }
    }
    

    在主程序中还需要先设置一下日历输出的样式,代码如下所示:

    <html>
        <head>
            <title>《细说PHP》日历示例</title>
            <style>
                table { border:1px solid #050;}            /*给表格加一个外边框*/
                .fontb { color:white; background:blue;}    /*设置周列表的背景和字体颜色*/
                th { width:30px;}                          /*设置单元格子的宽度*/
                td,th { height:30px;text-align:center;}    /*设置单元高度,和字段显示位置*/
                form { margin:0px;padding:0px; }           /*清除表单原有的样式*/
            </style>
        </head>
        <body>
            <?php
                require "calendar.class.php";    //加载日历类
                echo  new Calendar;              //直接输出日历对象,自动调用魔术方法__toString()打印日历
            ?>
        </body>
    </html>
    

    6.小结

    本章必须掌握的知识点

    • UNIX时间戳。
    • 将其他格式的日期转成UNIX时间戳的格式。
    • 基于UNIX时间戳的日期计算。
    • 获取并格式化输出日期。
    • 修改PHP的默认时间。
    • 微秒的使用。

    本章需要了解的内容

    • 日历程序编写。
    • 本章没有介绍到的其他和日期及时间有关的函数。
    • 以同样的学习方法去扩展PHP的一些相似函数库学习,例如数学函数库。

    本章的学习建议

    多通过实例编写,熟练掌握日期和时间函数的应用,并可以灵活地在项目中使用。

    相关文章

      网友评论

        本文标题:15.PHP的日期和时间

        本文链接:https://www.haomeiwen.com/subject/djspgctx.html