PHP で指定時刻が現在時刻から「〇(年 or 月 or 日 or 時 or 分 or 秒)(前 or 後)」なのかを自動算出する

PHP じゃなくてもすぐに真似できそうな簡単な関数ですが、意外と業務で使うことが多いので記事にしてみました。
ある投稿が現在から5分前なのか10ヶ月前なのかを表示したいケースに有用です。

指定時刻・現在時刻のUNIXタイムスタンプが用意できることが条件です。
現在時刻から見て未来と過去、加えて負のタイムスタンプ(1970年より過去)にも対応しています。

# 変換結果例

現在時刻: 2019年05月31日 16時40分58秒(タイムスタンプ: 1559288458)
指定時刻: 2019年05月31日 16時45分50秒(タイムスタンプ: 1559288750)
結果: __5分後__

現在時刻: 2019年05月31日 18時00分15秒(タイムスタンプ: 1559293215)
指定時刻: 2019年05月31日 16時45分50秒(タイムスタンプ: 1559288750)
結果: __1時間前__

現在時刻: 2019年05月31日 18時01分06秒(タイムスタンプ: 1559293266)
指定時刻: 2018年10月12日 05時12分30秒(タイムスタンプ: 1539288750)
結果: __7ヶ月前__

現在時刻: 2019年05月31日 18時01分47秒(タイムスタンプ: 1559293307)
指定時刻: 2015年08月11日 19時25分50秒(タイムスタンプ: 1439288750)
結果: __3年前__

現在時刻: 2019年05月31日 18時03分39秒(タイムスタンプ: 1559293419)
指定時刻: 2286年11月21日 02時46分39秒(タイムスタンプ: 9999999999)
結果: __268年後__

現在時刻: 2019年05月31日 18時18分00秒(タイムスタンプ: 1559294280)
指定時刻: 1589年09月26日 11時40分00秒(タイムスタンプ: -12000000000)
結果: __429年前__

1970-01-01 09:00:00

# コード

ただの関数です。PHP は 7 系じゃないと動きません。

```php
/**
   * $timeとtime()の差分を「○秒」「○週」等に成型して返す
   * 単位の種類は $unites で指定可能
   * その場合は値に単位文言、キーに1単位を秒換算した数値(単位が「時間」だったら1時間 = 3600)を指定
   * デフォルトの単位種類は「年」「ヶ月」「日」「時間」「分」「秒」
   * @param int $time
   * @param array $unites
   * @return string
   */
function time_difference_with_unit(int $time, ?array $unites = NULL): string
{
	//現在時刻
	$now = time();
	
	//$units が falsy な値だったらデフォルトの定義を使用
	$unites = $unites 
		? $unites 
		: array(
			31536000 => '年',
			2678400 => 'ヶ月',
			604800 => '週間',
			86400 => '日',
			3600 => '時間',
			60 => '分',
			1 => '秒'
		);

	//定義をキーで降順ソート
	krsort($unites);

	//差を秒で取得(絶対値にすることで未来に対応)
	$diff = abs(time() - $time);

	//単位ごとに条件へ合致するか判定する
	foreach ($unites as $second => $unit)
	{
		//もし参照中の1単位を秒に変換した数値未満だったらスルー
		if ($diff < $second)
		{
			continue;
		}

		//差秒を単位時間で割って端数を丸めた数値に単位文字列を付けて返す
		return $now > $time 
			? floor($diff / $second).$unit.'前'
			: ceil($diff / $second).$unit.'後';
	}

	//差が0以下なので「0 + 最小単位 + 前」文字列を返す
	return '0'.$unites[array_keys($unites)[count($unites) - 1]].'前';
}

```

# お試しコード

```index.php
<?php
function time_difference_with_unit(int $time, ?array $unites = NULL): string
{
  //略
}

?>
<form action="" method="post">
	<div>
		<label>タイムスタンプ: <input type="number" name="time" value="<?php echo $_POST['time'] ?? time(); ?>"></label>
	</div>
	<div>
		<label><input type="submit" value="変換"></label>
	</div>
</form>
<?php if (isset($_POST['time'])): ?>
<p>現在時刻: <?php echo date('Y年m月d日 H時i分s秒'); ?>(タイムスタンプ: <?php echo time(); ?>)</p>
<p>指定時刻: <?php echo date('Y年m月d日 H時i分s秒', (int)$_POST['time']); ?>(タイムスタンプ: <?php echo (int)$_POST['time']; ?>)</p>
<p>結果: <strong><?php echo time_difference_with_unit((int)$_POST['time']); ?></strong></p>
<?php endif; ?>

```

上記ページを開くとタイムスタンプ入力欄フォームが出てくるので、入力後「変換」ボタンを押すと上記の「[#変換結果例](#変換結果例)」と同じ結果が出力されます。

# 定義に「刻」・「フォートナイト」・「世紀」を追加

年月日時分秒では定義が足りない場合は追加ができます。

[時間の単位 - Wikipedia](https://ja.wikipedia.org/wiki/%E6%99%82%E9%96%93%E3%81%AE%E5%8D%98%E4%BD%8D)
より、

 - 刻: 15分
 - フォートナイト: 2週間
 - 世紀: 100年

を定義に追加してみましょう。

```index.php
<?php
function time_difference_with_unit(int $time, ?array $unites = NULL): string
{
  //略
}

?>
<form action="" method="post">
  <div>
    <label>タイムスタンプ: <input type="number" name="time" value="<?php echo $_POST['time'] ?? time(); ?>"></label>
  </div>
  <div>
    <label><input type="submit" value="変換"></label>
  </div>
</form>
<?php if (isset($_POST['time'])): ?>
<p>現在時刻: <?php echo date('Y年m月d日 H時i分s秒'); ?>(タイムスタンプ: <?php echo time(); ?>)</p>
<p>指定時刻: <?php echo date('Y年m月d日 H時i分s秒', (int)$_POST['time']); ?>(タイムスタンプ: <?php echo (int)$_POST['time']; ?>)</p>
<p>結果: <strong><?php echo time_difference_with_unit((int)$_POST['time'], array(
  3153600000 => '世紀',
  31536000 => '年',
  2678400 => 'ヶ月',
  1209600 => 'フォートナイト',
  604800 => '週間',
  86400 => '日',
  3600 => '時間',
  900 => '刻',
  60 => '分',
  1 => '秒'
)); ?></strong></p>
<?php endif; ?>

```

現在時刻: 2019年06月01日 03時57分13秒(タイムスタンプ: 1559329033)
指定時刻: 2019年06月01日 03時07分15秒(タイムスタンプ: 1559326035)
結果: __3刻前__

現在時刻: 2019年06月01日 03時57分58秒(タイムスタンプ: 1559329078)
指定時刻: 2019年06月17日 08時00分35秒(タイムスタンプ: 1560726035)
結果: __2フォートナイト後__

現在時刻: 2019年06月01日 03時55分35秒(タイムスタンプ: 1559328935)
指定時刻: 2458年11月26日 12時45分30秒(タイムスタンプ: 15428288730)
結果: __5世紀後__

独自の時間単位を持ったファンタジーゲームなんかにもどうぞ。