[競技プログラミング][C言語][AtCoder]割り切れる日付 | DevAchieveをPHPで解き直した。回答
AtCoder/arc002_2.php at master · wada811/AtCoder今回はC言語みたいに計算でやらずにPHPの関数で頑張りました。
とりあえず2種類の方法で通したので両方載せる。
<?php
fscanf(STDIN, "%s", $date);
while(true){
$splits = explode("/", $date);
$year = $splits[0];
$month = $splits[1];
$day = $splits[2];
$quotient = $year / $month / $day;
if(floor($quotient) == ceil($quotient)){
break;
}
$date = date("Y/m/d", mktime(0, 0, 0, $month, $day, $year) + 86400);
}
echo $date."\n";
?>explode関数で文字列を分割して年月日をそれぞれ取得する。割り算を計算して、割り切れない場合は商が小数になるので
floor関数とceil関数で小数点以下を切り捨て/切り上げした結果が異なる。
その場合はmktime関数でUNIXTIMEに変換して一日(24*60*60=86400秒)を足す。
新しいUNIXTIMEに対してdate関数でフォーマットを指定して日付を生成して繰り返す。
これを割り切れるまで(商が整数になりfloor関数とceil関数の結果が同じになるまで)やります。
UNIX時間 - Wikipedia
UNIX時間(ユニックスじかん)またはUNIX時刻(ユニックスじこく、UNIX time、POSIX time)とはコンピューターシステム上で日時を表す単位。UTCでの1970年1月1日真夜中(0時0分0秒)からの経過秒数(閏秒を加味しない)で表される。
UNIX系オペレーティングシステムだけでなく、他の多くのオペレーティングシステムにおいてもこの単位が用いられている。システム内部では32ビットまたは64ビットの符号付整数(signed int)で扱われていることが普通であり、特に32ビットで扱われている場合においては符号付整数が取れる最大値 2,147,483,647 を超える時点で時刻を扱えなくなるという問題がある。これを2038年問題という。
ということでUNIXTIMEで計算してるとそのうち面倒な事になるんじゃないの?ってことで違う方法でも解いてみた。
<?php
fscanf(STDIN, "%s", $input);
$splits = explode("/", $input);
$date = new DateTime();
$date->setDate($splits[0], $splits[1], $splits[2]);
while(true){
$year = $date->format("Y");
$month = $date->format("m");
$day = $date->format("d");
$quotient = $year / $month / $day;
if(floor($quotient) == ceil($quotient)){
break;
}
$date->add(new DateInterval("P1D"));
}
echo $date->format("Y/m/d") . PHP_EOL;
?>ロジックは同じ。DateTimeオブジェクトのインスタンスを生成して、setDateメソッドで年月日をセットする。フォーマットを指定してformatメソッドで値を取得する。
日付の加算はaddメソッドの引数にDateIntervalオブジェクトを渡して行う。
DateIntervalの引数の書式はPHP: DateInterval::__construct - Manualを参照のこと。
どこでも動いたほうがいいよねってことでそのプラットフォームでの改行コードを表すPHP_EOLも使ってみた。
PHP 逆引きレシピ (PROGRAMMER’S RECiPE)も良かったけど日付関連が前者のやり方だったので
後者のやり方を解説しているというパーフェクトPHP(PERFECT SERIES 3)が欲しい。
参考
手を動かして覚えるPHP 5.3新機能 日付(DateTime,DateInterval)編 | Act as Professional
PHP 5.3 の DateTime オブジェクト関連の便利な新機能 - 肉とご飯と甘いもの @ sotarok
追記(2012/09/01):DateTime::createFromFormatの方が簡潔だった
<?php
fscanf(STDIN, "%s", $input);
$date = DateTime::createFromFormat('Y/m/d', trim($input), new DateTimeZone('Asia/Tokyo'));
while(true){
$year = $date->format("Y");
$month = $date->format("m");
$day = $date->format("d");
$quotient = $year / $month / $day;
if(floor($quotient) == ceil($quotient)){
break;
}
$date->add(new DateInterval("P1D"));
}
echo $date->format("Y/m/d") . PHP_EOL;
?>まだまだ修行が足りない。PHP力が低いなードキュメントは見るようにしてたのだけども…。パーフェクトPHP (PERFECT SERIES 3)