UNIXTIMEを使おう!
昔から自分が欲しいものがあります。
「unixtime腕時計」
デジタル時計なんだけど表示はunixtime!ステキ!
だれかつくって!
はい。
unixtime(ゆにっくすたいむ)とは、1970年1月1日 09:00:00(日本時間)からの経過秒数です。
たとえば2012/10/22 00:00:00は1350831600になるわけですが、まぁぶっちゃけパッと見てもワケワカメです。
しかし単純に数字で表せるということにシビれたりあこがれたりするとかしないとか。
プログラムで普段日付や時間を取り扱うときにdate型やdatetime型は、視認性はよくて便利ですが、一度文字列にしてしまうとプログラム上で操作するのに何かと不便です。
具体的には、たとえば基準となる日付の翌日を表示したい場合、
基準の日付が文字列(YYYY/MM/DD)で渡されてunixtime使わないしばりで処理するとこんなかんじ?
とまぁあえてunixtime使わないで頑張ったので極端な例ですが、これがunixtimeで処理できるとこんなかんじになります。
特に言語側に用意された日付関数でもunixtimeを渡すものが多いと思うので、使って損は無いとおもいます。
ちなみに最初の例の様に文字列で元データが引き渡された場合でも、
phpにはstrtotimeという文字列形式の日付時間をなんとなく解釈してunixtimeに戻してくれるというとても便利な関数があるので、そのときの気分でどっちでも扱えますが、もちょっとガチムチな言語だとそんなものは無かったりします。というかphp以外にあるのこれ。
そんなわけで自分の場合は、プログラム上(modelやcontroller/action)では極力unixtimeでデータを操作しつつ、最後の最後で表示するときだけ(viewとか)date関数とか使って読める形にします。
unixtimeを使い出すと勝手に覚えてしまう数字たち。
ちょっと使っていれば1日=86400秒なんて自然と出てくるようになります。
あまりにunixtimeを使っていると、データベースに保存したり取り出したりするときにいちいちdatetime型に直すのが面倒になるのが世の常。
・・・もうそのままint系で保存しちゃいましょう!
でも、実際MySQLの場合にデータタイプごとの記憶容量を比較した場合、
なので、ちょっとスリム化できます。
2038年問題を考慮しても、しっかりUNSIGNED INTとしてカラム定義しておけば、2106年まで使えるのでとりあえず生きているうちは安心です。
でも32ビットOSだとOS側がついていけなかったりするかもしらんです。
あ、全体的にMySQLのおはなしです。
特定の日付にデータ修正したいときもターミナルとかでunixtime作ってからコピペしたり。
変換式が入っちゃうので当然INDEXもなにも無いわけで、データ出すために自分でSQL打つとかなら問題ないですが、実際にサービスとして使う分にはびみょう。
実際に使うとしたら、特に普段操作したりしない作成日、更新日みたいなカラムが適当でしょうか。
ぶっちゃけデメリットの方がおおいかもしれない・・・。
それでも私はunixtime
プログラム上でならunixtimeは非常に便利ですので使い倒して損はないと思います。
データベースまで手を伸ばすのは・・・まぁ趣味もしくはできるだけスリム化したいときですかね・・。
エクセルで表示される時刻は、内部処理としてシリアル値というものが利用されています。
こちらはunixtimeと考え方は似てるけどちょっと違いまして、
それぞれ表示します。
たとえば、2012/10/20 12:00:00 は 41202.5 になります。
日と時間がそれぞれ切り離されてるのでunixtimeよりかはちょっとは可読性ありますし、パッと見て一日のうちのどの辺かくらいまではわかりますが、まぁこれも人間が認識するデータじゃないですな(´ω`)
「unixtime腕時計」
デジタル時計なんだけど表示はunixtime!ステキ!
だれかつくって!
はい。
unixtime(ゆにっくすたいむ)とは、1970年1月1日 09:00:00(日本時間)からの経過秒数です。
たとえば2012/10/22 00:00:00は1350831600になるわけですが、まぁぶっちゃけパッと見てもワケワカメです。
しかし単純に数字で表せるということにシビれたりあこがれたりするとかしないとか。
■ いつ使うのよこれ
プログラムで普段日付や時間を取り扱うときにdate型やdatetime型は、視認性はよくて便利ですが、一度文字列にしてしまうとプログラム上で操作するのに何かと不便です。
具体的には、たとえば基準となる日付の翌日を表示したい場合、
基準の日付が文字列(YYYY/MM/DD)で渡されてunixtime使わないしばりで処理するとこんなかんじ?
$date='yyyy/mm/dd'; // 実際は数字入ってると思ってくだされ
$lastDay=array(1=>31,28,31,30,31,30,31,31,30,31,30,31); // 最終日リスト
$year=(int)substr($date,0,4);
$month=(int)substr($date,5,2);
$day=(int)substr($date,8,2);
if($lastDay[$month]==$day) // 最終日だったら翌月にする
{
$day=1;
$month++;
}
else
$day++;
if($month==13) // 年末越えたら翌年にする
{
$year++;
$month=1;
}
printf("%4d/%02d/%02d\n",$year,$month,$day);本当は閏年判定まで必要になるんであら面倒ね。とまぁあえてunixtime使わないで頑張ったので極端な例ですが、これがunixtimeで処理できるとこんなかんじになります。
$date=nnnnnnnnnn; // unixtimeが入ってると思ってくだされ
$date+=86400;
echo date('Y/m/d',$date);こんなんで一発なわけです。(86400が何かは後述で。)特に言語側に用意された日付関数でもunixtimeを渡すものが多いと思うので、使って損は無いとおもいます。
ちなみに最初の例の様に文字列で元データが引き渡された場合でも、
$utime=mktime(0,0,0,substr($date,5,2),substr($date,8,2),substr($date,0,4))ってやればunixtimeに変換できます。phpにはstrtotimeという文字列形式の日付時間をなんとなく解釈してunixtimeに戻してくれるというとても便利な関数があるので、そのときの気分でどっちでも扱えますが、もちょっとガチムチな言語だとそんなものは無かったりします。というかphp以外にあるのこれ。
そんなわけで自分の場合は、プログラム上(modelやcontroller/action)では極力unixtimeでデータを操作しつつ、最後の最後で表示するときだけ(viewとか)date関数とか使って読める形にします。
■ 覚えていると便利な数字
unixtimeを使い出すと勝手に覚えてしまう数字たち。
| 1分 | 3600秒 | 60x60 秒 |
|---|---|---|
| 1日 | 86400秒 | 60x60x24 秒 |
■ データベースにも手を出す
あまりにunixtimeを使っていると、データベースに保存したり取り出したりするときにいちいちdatetime型に直すのが面倒になるのが世の常。
・・・もうそのままint系で保存しちゃいましょう!
でも、実際MySQLの場合にデータタイプごとの記憶容量を比較した場合、
| INT | 4 バイト |
|---|---|
| DATETIME | 8 バイト |
2038年問題を考慮しても、しっかりUNSIGNED INTとしてカラム定義しておけば、2106年まで使えるのでとりあえず生きているうちは安心です。
でも32ビットOSだとOS側がついていけなかったりするかもしらんです。
■ データベースにも手を出したときのデメリット
あ、全体的にMySQLのおはなしです。
視認性ワロシ
直でSQL打ったりしてデータ取り出したときは完全に数字の羅列なので全く何が何やらわかりません!特定の日付にデータ修正したいときもターミナルとかでunixtime作ってからコピペしたり。
いちいち変換が必要なので面倒!
常にFROM_UNIXTIMEというSQL関数がつきまといます。日や月等でGROUP BYしたい場合はさらに面倒!
年月でGROUPしたいときはDATE_FORMAT(FROM_UNIXTIME(createTime,'%Y%m')) みたいなものが出てきます。変換式が入っちゃうので当然INDEXもなにも無いわけで、データ出すために自分でSQL打つとかなら問題ないですが、実際にサービスとして使う分にはびみょう。
実際に使うとしたら、特に普段操作したりしない作成日、更新日みたいなカラムが適当でしょうか。
ぶっちゃけデメリットの方がおおいかもしれない・・・。
それでも私はunixtime
■ 総評
プログラム上でならunixtimeは非常に便利ですので使い倒して損はないと思います。
データベースまで手を伸ばすのは・・・まぁ趣味もしくはできるだけスリム化したいときですかね・・。
■ おまけ
エクセルで表示される時刻は、内部処理としてシリアル値というものが利用されています。
こちらはunixtimeと考え方は似てるけどちょっと違いまして、
日付
1900年1月1日を1としてそこからの経過日数を整数部として。時間
24時間表記での割合を小数部で(12時が0.5、18時が0.75とか)。それぞれ表示します。
たとえば、2012/10/20 12:00:00 は 41202.5 になります。
日と時間がそれぞれ切り離されてるのでunixtimeよりかはちょっとは可読性ありますし、パッと見て一日のうちのどの辺かくらいまではわかりますが、まぁこれも人間が認識するデータじゃないですな(´ω`)
集計用のモデルを作るとイカすかもしれない話
自分はサービスっていうよりは、わりとツールつくりが好きなので、ユーザ数やデータの増加数などを月ごと日ごと等統計した結果を表示するものを社内で作っていたりするのですが、そういったデータマインニングとかをするときのお話。
とりあえずこんなかんじのシンプルなUGC(日記とかブログとかみたいなコンテンツ)的なデータのテーブルをイメージしてみましょう。
これを日付ごとに何件投稿があったか統計して出力するツールを作ってみようと思ったとき、直接、controller (action)に直感的に処理を書こうとすると、たぶんこんなかんじ
指定の月のデータを日ごとに集計するっていう処理ね。
まぁ、ツッコミやら細かな流儀やらいろいろあると思いますが、
たぶんこんなものをゴリゴリ書いてた過去の自分に乾杯。
これをデータ集計&出力用のモデルクラスをひとつ作って処理をラップすると、たぶんこんなメリットが!
・contoller側の処理がスッキリする
・view側の処理がスッキリする(複雑なロジックに名前をつけてラップできる)
・便利になる
これを読む頃にはきっといろんな虜に!
こういうのは自分やお仕事に合った作り方すれば良いと思うので、これだけじゃなくてもオリジナリティつければよいとおもいます。
データの取出しは直接プロパティを触らないようにして、専用のメソッド経由で取り出すようにしましょう。全部の日付にキレイにデータが入っていればいいですが、こうすることで、取り出す時点でデータがあるかどうかチェックした上で返す、みたいなこともできます。これでerror_reportingのレベルをあげても安心!
こういう風に操作に対して名前をつけるメリットは後述で。
最初のほうに書いためんどい処理がこうなります
何を持ってスッキリか、っていうのもありますが、主にこんな利点があると思います
・複雑・煩雑なロジックに名前をつけてラップできる
→ 1つのデータにアクセスする際にもissetチェックをした上で返す、など
・説明的に書ける
→ $data[$day] とか書くよりも、$data->getData($day) とかにした方が意味がわかりやすい
→ 読みやすいコードに
直で配列データ作ったときはview側はたぶんこんなかんじに。
なによりこれに限ります。
ロジックを直書きしたらそこでしか使えないですし、他でも使おうとしたら同じロジックをコピペするとかになってきてしまいますが、クラス化することで、includeするだけでどこからでもパッと使えることによって汎用性がアップ!
それとか、たとえば2つの月を指定して数値を並べて差を出すとかしようとするときも、直でロジック書いてると面倒なこと極まりないですが、クラス化していると、
ここでもし、この比較する処理を本格的に作りたいなら、専用のクラスをまたこしらえても良いかもしれません。
実際は、これからさらに、ユーザ登録数、他のサービスの投稿数なんかがどんどん増えたり、日付ごとの数値だけじゃなくて累計も出したいとか、なんかいろいろ要素が増えてどんどんロジックが複雑怪奇になっていったりしますが、そんなときも慌てず落ち着いてクラスにロジック詰め込んでしまえば、さっくり作れたりもするものです。
なんか最近、新しいロジックのクラス作ってるのが楽しいですw
とりあえずこんなかんじのシンプルなUGC(日記とかブログとかみたいなコンテンツ)的なデータのテーブルをイメージしてみましょう。
DataTable
id int unsigned auto_increment
title varchar(xxx)
content text
date date
UserId int unsignedこれを日付ごとに何件投稿があったか統計して出力するツールを作ってみようと思ったとき、直接、controller (action)に直感的に処理を書こうとすると、たぶんこんなかんじ
$year=$_GET['y'];
$month=$_GET['m'];
$lastDay=date('t',mktime(0,0,0,$month,1,$year));
$sql="SELECT date,COUNT(*) AS numOfData ".
"FROM DataTable ".
"WHERE date BETWEEN \"${year}-${month}-01\" AND \"${year}-${month}-${lastDay}\" ".
"GROUP BY date ".
"ORDER BY date;";
:
・このSQL実行して
・配列に入れて
・viewに渡して
・そっちでもまた云々
:※ なんでも通用するようにとりあえず直でSQL書いてるだけです。指定の月のデータを日ごとに集計するっていう処理ね。
まぁ、ツッコミやら細かな流儀やらいろいろあると思いますが、
たぶんこんなものをゴリゴリ書いてた過去の自分に乾杯。
これをデータ集計&出力用のモデルクラスをひとつ作って処理をラップすると、たぶんこんなメリットが!
・contoller側の処理がスッキリする
・view側の処理がスッキリする(複雑なロジックに名前をつけてラップできる)
・便利になる
これを読む頃にはきっといろんな虜に!
まずは集計用モデルをつくってみよう
こういうのは自分やお仕事に合った作り方すれば良いと思うので、これだけじゃなくてもオリジナリティつければよいとおもいます。
class DataTable
{
public $year;
public $month;
private $_data=array();
public function __construct($year,$month)
{
$this->year=$year;
$this->month=$month;
$this->_loadData();
}
private function _loadData()
{
$sql='さっきのSQLとか';
$result=DAOとかなんとか($sql);
foreach($result as $data)
{
$day=substr($data['date'],8,2); // yyyy-mm-dd のdd部分を取り出す
$this->_data[$day]=$data['numOfData'];
}
}
public function getData($day)
{
return isset($this->_data[$day])?$this->_data[$day]:0;
}
public function getTotal()
{
return array_sum($this->_data);
}
public function getDays()
{
return array_keys($this->_data);
}
}コンストラクタで年・月を渡して、newした時点でデータがロードされるようにしてます。データの取出しは直接プロパティを触らないようにして、専用のメソッド経由で取り出すようにしましょう。全部の日付にキレイにデータが入っていればいいですが、こうすることで、取り出す時点でデータがあるかどうかチェックした上で返す、みたいなこともできます。これでerror_reportingのレベルをあげても安心!
こういう風に操作に対して名前をつけるメリットは後述で。
controller側の処理がスッキリする
最初のほうに書いためんどい処理がこうなります
$year=$_GET['y'];
$month=$_GET['m'];
$data=new DataTable($year,$month);こんだけ!スッキリ!view側の処理がスッキリする
何を持ってスッキリか、っていうのもありますが、主にこんな利点があると思います
・複雑・煩雑なロジックに名前をつけてラップできる
→ 1つのデータにアクセスする際にもissetチェックをした上で返す、など
・説明的に書ける
→ $data[$day] とか書くよりも、$data->getData($day) とかにした方が意味がわかりやすい
→ 読みやすいコードに
直で配列データ作ったときはview側はたぶんこんなかんじに。
<table>
<tr><th>Day</th><th>投稿数</th></tr>
<?php foreach($data as $date=>$numOfData): ?>
<tr>
<th><?php echo substr($date,8,2) ?>日</th>
<td><?php echo $numOfData ?></td>
</tr>
<?php endforeach ?>
<tr>
<th>合計</th><td><?php echo array_sum($data) ?></td>
</tr>
</table>んでもってモデルバージョン<table>
<tr><th>Day</th><th>投稿数</th></tr>
<?php foreach($data->getDays() as $day): ?>
<tr>
<th><?php echo $day ?>日</th>
<td><?php echo $data->getData($day) ?></td>
</tr>
<?php endforeach ?>
<tr>
<th>合計</th><td><?php echo $data->getTotal() ?></td>
</tr>
</table>ほら、なんかちょっと頭良く見える!便利になる
なによりこれに限ります。
ロジックを直書きしたらそこでしか使えないですし、他でも使おうとしたら同じロジックをコピペするとかになってきてしまいますが、クラス化することで、includeするだけでどこからでもパッと使えることによって汎用性がアップ!
それとか、たとえば2つの月を指定して数値を並べて差を出すとかしようとするときも、直でロジック書いてると面倒なこと極まりないですが、クラス化していると、
$data=new DataTable($year,$month);
$pastData=new DataTable($pastYear,$pastMonth);こんな風に気軽に2つ連続でデータを作って並べて表示とかもできちゃいます。ここでもし、この比較する処理を本格的に作りたいなら、専用のクラスをまたこしらえても良いかもしれません。
実際は、これからさらに、ユーザ登録数、他のサービスの投稿数なんかがどんどん増えたり、日付ごとの数値だけじゃなくて累計も出したいとか、なんかいろいろ要素が増えてどんどんロジックが複雑怪奇になっていったりしますが、そんなときも慌てず落ち着いてクラスにロジック詰め込んでしまえば、さっくり作れたりもするものです。
なんか最近、新しいロジックのクラス作ってるのが楽しいですw
おもしろ腕時計なかんじ
自分が普段つけている中途半端にごっつい腕時計ですが、これがまたおもしろガジェットなカンジのアイテムでして、
CITIZENのアイバートMっていうシロモノです。
http://citizen.jp/ivirt/
携帯とbluetooth接続することで、
メール着信や電話着信が腕時計に飛んできたり、
その他マナーモードのON/OFFやらカメラのシャッターやらにも使えたりさらになんかいろいろあるらしい。というなんともウキウキするアイテムです。
とはいえメールは差出人と最初の何十文字か確認できるだけですし、
電話は腕時計側じゃ受け取れないのでw、腕時計からできる操作は保留か切断だけです。
あとbluetooth接続なので、ちょっと離れると接続切れちゃいます。
あ、これ電池は充電式なんですが、地味に充電スタンドがかっこよくて、
なんと非接触式!!
電磁誘導とか書いてあるけど大学で習ったことはもう忘れた!
携帯みたくプラグ差し込んだりはしなくて、専用の台座に引っ掛けるように置くだけで充電されます。
ちょっと近未来っぽい!!
しかしBT接続しっぱなしで約5日、未接続で約1ヶ月ほど電池が持つらしい。
仕方ないんだけど、やはり腕時計としてはびみょい。
実家帰ったときとかヒヤヒヤもんですよ。
そんなこんなで実際に使える場面としては、
・電車の中でポケットやカバンから携帯出せないような状態でもある程度チェックできる
・自転車走行中に着信がわかる
・「キャー!なんかすごいアイテム使ってるー!」と思われる(←思い込み)
といった、機能自体はわりと夢広がりんぐだけどちょっと物足りない、ちょっと惜しいアイテムです。
さらに言うと、対応機種を見ればわかるんですが、
対応しているのはソフバンのガラケーオンリーっぽい。
ぶっちゃけこやつのために携帯機種変する必要までは無いと思うので、
ちょうど対応機種使ってる!っていう様なら折角なので使ってみたら面白いよ!ってカンジですね。
ちなみに自分はJ-PHONE時代からずっとこの系統です!
SIMカードも未だにvodafoneだし、メアドもvodafone。
さっさとsoftbankに統一したいであろうキャリア側にとっては邪魔な人ですな!
CITIZENのアイバートMっていうシロモノです。
http://citizen.jp/ivirt/
携帯とbluetooth接続することで、
メール着信や電話着信が腕時計に飛んできたり、
その他マナーモードのON/OFFやらカメラのシャッターやらにも使えたりさらになんかいろいろあるらしい。というなんともウキウキするアイテムです。
とはいえメールは差出人と最初の何十文字か確認できるだけですし、
電話は腕時計側じゃ受け取れないのでw、腕時計からできる操作は保留か切断だけです。
あとbluetooth接続なので、ちょっと離れると接続切れちゃいます。
あ、これ電池は充電式なんですが、地味に充電スタンドがかっこよくて、
| 使用電池 | 二次電池(専用充電器による非接触充電方式) |
|---|---|
| 充電方式 | 電磁誘導による非接触充電(充電切れからフル充電まで約3時間) |
なんと非接触式!!
電磁誘導とか書いてあるけど大学で習ったことはもう忘れた!
携帯みたくプラグ差し込んだりはしなくて、専用の台座に引っ掛けるように置くだけで充電されます。
ちょっと近未来っぽい!!
しかしBT接続しっぱなしで約5日、未接続で約1ヶ月ほど電池が持つらしい。
仕方ないんだけど、やはり腕時計としてはびみょい。
実家帰ったときとかヒヤヒヤもんですよ。
そんなこんなで実際に使える場面としては、
・電車の中でポケットやカバンから携帯出せないような状態でもある程度チェックできる
・自転車走行中に着信がわかる
・「キャー!なんかすごいアイテム使ってるー!」と思われる(←思い込み)
といった、機能自体はわりと夢広がりんぐだけどちょっと物足りない、ちょっと惜しいアイテムです。
さらに言うと、対応機種を見ればわかるんですが、
対応しているのはソフバンのガラケーオンリーっぽい。
ぶっちゃけこやつのために携帯機種変する必要までは無いと思うので、
ちょうど対応機種使ってる!っていう様なら折角なので使ってみたら面白いよ!ってカンジですね。
ちなみに自分はJ-PHONE時代からずっとこの系統です!
SIMカードも未だにvodafoneだし、メアドもvodafone。
さっさとsoftbankに統一したいであろうキャリア側にとっては邪魔な人ですな!

