一道面試題引發的思考

xianyunyehe發表於2018-10-19

最近出了一個面試題,

給一個時間,獲取這個月的結束的日期。比如 輸入'2018-08-04' 輸出'2018-08-31'

這個題目,相應如果熟悉php date 的應該很快能寫出來。但是遇到一些求職者,可能沒思考清楚,於是就開始編寫了。
一個月的結束時間,只要知道這個月有多少天,就能知道最後一天是多少號了?但是這裡你要思考的問題就有很多,因為月份有大小月份(1 3 5 7 8 10 12 則是大月有31天,其餘的月份除了2月,都是小月,每個月有30天),你可能會忽略掉2月這個特殊的月份,因為2月又有29天和28天。假設你已經考慮到2月了,但是你又得需要考慮閏年了,閏年的規則你需要知道吧!
不考慮超大年的情況下的規則(按照曆法 比如 3200 就不是閏年。有興趣的可以查下資料)

普通年:能被4整除但不能被100整除的年份為普通閏年。(如2004年就是閏年,1999年不是閏年);
世紀年:能被400整除的為世紀閏年。(如2000年是閏年,1900年不是閏年);

於是有的求職者上來就寫了一個這種程式碼

方法一

function monthDay($date) {
     $month31 = [1, 3, 5, 7, 8, 10, 12];
    list($year, $month) = explode('-',$date);
    if ($month != 2) {
        if (in_array($month, $month31)) {
            return "{$year}-{$month}-31";
        } else {
            return "{$year}-{$month}-30";
        }
    }
      if (  $year%4==0  && ($year%100!=0 ||  $year%400==0 ) ){
        return "{$year}-{$month}-29";
    }else{
        return "{$year}-{$month}-28";
    }
}

方法二

方法一的程式碼看著沒啥問題,但是可能是一種特別複雜的實現方式,它考慮的因素比較多。
我們可以換種思考的方式,這個月有多少天,我們知道一個月的開始時間和一個月的結束時間 兩者相減,也是等於當月的天數。一月末正好是一個月的開始。而且每個月的開始時間是固定的,都是1號,不會變的。下一個月的月數等於當月+1。
但是有個特殊的情況,如果是年底,那麼12月的下一月就是新的一年的1月。

function endDayOfMonth($date) {
    list($year, $month) = explode('-',$date);
    $nextYear = $year;
    $nexMonth = $month+1;
    //如果是年底12月 下個月就是1月
    if($month == 12) {
        $nexMonth = "01";
        $nextYear = $year+1;
    }
    $begin = "{$year}-{$month}-01 00:00:00";
    $end = "{$nextYear}-{$nexMonth}-01 00:00:00";
    $day = (strtotime($end) - strtotime($begin) )/ (24*60*60);
    return "{$year}-{$month}-{$day}";
}

方法三

方法二的方法其實已經差不多接近了,但是還是可能不夠特別好的。因為我們不需要算天數。我們知道新的一個月的第一天,減去一個1,就是當月的最後一秒。

function endDayOfMonth($date) {
    list($year, $month) = explode('-',$date);
    $nextYear = $year;
    $nexMonth = $month+1;
    //如果是年底12月 下個月就是1月
    if($month == 12) {
        $nexMonth = "01";
        $nextYear = $year+1;
    }
    $end = "{$nextYear}-{$nexMonth}-01 00:00:00";
    $endTimeStamp = strtotime($end) - 1 ;
    return date('Y-m-d',$endTimeStamp);
}

PHP自帶函式實現

其實php自帶的有多種實現的方式,比如date、DateTime、strtotime等

  • php date 函式格式化
    t 指定月份的天數; 如: "28" 至 "31"
    $date = '2018-08-08';
    echo date('Y-m-t',strtotime($date));
  • strtotime 字串時間修飾詞
    last day of this month 時間字元 類似我們常說的 -1 day
    echo date('Y-m-d',strtotime("last day of this month",strtotime('2018-02-01')));
    echo date('Y-m-d',strtotime("last day of 2018-02"));
  • php DateTime類 物件導向方式

    $date = new \DateTime('2000-02-01');
    $date->modify('last day of this month');
    echo $date->format('Y-m-d');

其實這題主要是我們常見的面試題演變的。主要是想看怎麼考慮問題,很多的時候,我們陷入了一個誤區裡,考慮了複雜的實現,其實就是兩個函式的使用,一個是 datestrtotime

求昨天的日期,strtotime('-1 day')

能使用date("Y-m-t") 的這種是最簡單的,題目中沒有提到不用內建函式,所以也考慮思考的方式,是否讀了題目,就跟我們以前考試一樣。做選擇題,從下面選項選出不是的答案,我們看了第一個正確就選了。
想法很重要!

閒雲野鶴

相關文章