GO FOR IT(1)人生の時計

Sonyのソフトウェアスペシャリスト認定コンテストの問題をやってみました。
5問あるのですが今日やったのは1番目の「人生の時計」という問題。
問題は以下になります。

ちょっとわかりにくいのですが、問題の「n歳まで生きる(n歳のときは生きていてn+1歳にはなれない)」は81歳になるギリギリ直前まで生きているということだと思います。


はじめは日付の計算も自分でやろうと思っていたのですが、月によって最大日数が変わるし、閏年もあるやらで超面倒だったので用意されている関数を使いました。
ただし、phpのタイムスタンプの有効範囲は、32ビット環境の場合1901年〜2038年までです。64ビットだと無制限で使えるみたいです。
僕の環境は32ビットなので上記の問題をやろうとするとできなくなります。
ですのでここでは、誕生日を僕の誕生日(1987年5月26日)にして、寿命を40年として解きました。

アルゴリズム

"産まれてから死ぬまでの日数"、"産まれてから今日までの日数"を出す

前者を分母、後者を分子にとり、比を算出する

一生を24時間にたとえたとき、比が1のときの時刻は24時0分0秒。比が0.5のときの時刻は12時0分0秒になるので、比を基準に考えた時、1時間=1/24、1分=1/24*60、1秒=1/24*60*60になることがわかる。
なので、先程求めた比の中に1時間が何個あるか、比からその差をとったものの中に1分が何個あるか、さらにその差をとったものの中に1秒が何個あるのか求めれば一生を24時間にたとえたときの時刻がでる。

プログラム

<?php
$birth_year = 1987;
$birth_month = 5;
$birth_day = 26;

$death_year = $birth_year + 40;
$death_month = $birth_month;
$death_day = $birth_day;

$birthdate = $birth_year."-".$birth_month."-".$birth_day; 
$deathdate = $death_year."-".$death_month."-".$death_day; 
$todaydate = strftime("%Y-%m-%d"); 

//産まれてから死ぬまでの日数
$from_birth_to_death = (strtotime($deathdate)-strtotime($birthdate))/(3600*24);
//産まれてから今日までの日数
$from_birth_to_today = (strtotime($todaydate)-strtotime($birthdate))/(3600*24);

//産まれてから死ぬまでの日数と産まれてから今日までの日数の比
$fraction = $from_birth_to_today/$from_birth_to_death;

// 1/24=1時間
$life_hour = floor($fraction/(1/24));
// 1/24*60=1分
$life_minute = floor(($fraction - $life_hour*(1/24))/(1/(24*60))); 
// 1/24*60*60=1秒
$life_second = floor(($fraction - $life_hour*(1/24)-$life_minute*(1/(24*60)))/(1/(24*60*60)));
print $life_hour."".$life_minute."".$life_second.""

結果

14時49分19秒

感想

15時前っておい。後悔のないよう生きようと思いました。

追記

id:Kshi_Kshiのようにクラス作ったほうが使いまわししやすいですね。また明日やってみようと思います。(サラっとクラス書けるようになりたいものです)

プログラム修正ver

<?php
date_default_timezone_set('Asia/Tokyo');
class TimeSet{
	public $year;
	public $month;
	public $day;

	public function __construct($year,$month,$day){
		$this->year = $year;
		$this->month = $month;
	        $this->day = $day;	
	}

	public function getDate(){
		return $this->year."-".$this->month."-".$this->day;
	}
}
	$n = 40;
	$birthdateObj = new Timeset(1987,5,26);
	$deathdateObj = new Timeset(1987+$n,5,26);
	$birthdate = $birthdateObj->getDate();
	$deathdate = $deathdateObj->getDate();
	$todaydate = strftime("%Y-%m-%d"); 

	//産まれてから死ぬまでの日数
	$from_birth_to_death = (strtotime($deathdate)-strtotime($birthdate))/(3600*24);
	//産まれてから今日までの日数
	$from_birth_to_today = (strtotime($todaydate)-strtotime($birthdate))/(3600*24);

	//産まれてから死ぬまでの日数と産まれてから今日までの日数の比
	$fraction = $from_birth_to_today/$from_birth_to_death;

	// 1/24=1時間
	$life_hour = floor($fraction/(1/24));
	// 1/24*60=1分
	$life_minute = floor(($fraction - $life_hour*(1/24))/(1/(24*60))); 
	// 1/24*60*60=1秒
	$life_second = floor(($fraction - $life_hour*(1/24)-$life_minute*(1/(24*60)))/(1/(24*60*60)));
	print $life_hour."".$life_minute."".$life_second."";