「52週間前」って何月何日?
1年の数字の変化を追うのに、12か月だとばっくりし過ぎていて365日だとギザギザすぎ。
そこで「週単位」にすると、曜日の影響もなくなってスムーズ。
52個の数値の変化がグラフにしたとき見た目にちょうどいい。
そこで、52週分の集計をしようと思ったけど、
- 週単位って、月曜始まり? 日曜始まり?
- 52週前の月曜日って何日?
- どうやって計算するの?
そんなこと、もう悩まなくて大丈夫。偉い人が考えていて「国際規格」にまとめてくれていて、各種プログラミング言語でも標準で使えるようになっています。
この記事は、その国際規格に合わせたコードを、PHP + MySQL + Laravel という環境で、コピペで使えるようにまとめたものです。
ISO-8601 による 週番号
そもそも、馴染みがありませんが、1年を52週に割って、1月から番号を振ったものを「週番号」と言うそうです(そう言われればスケジュール帳には週番号が書いてあります)。
その週番号のカウント方法はいろいろあるのですが、いろいろあるとめんどくさいので、ISOがビシッと定めてくれています。
ISO_8601#年と週と曜日 (wikipedia)
ずばり、
- 月曜始まり
- 1月4日を含む週が第1週(第1週には4日以上含む)
これを MySQL、PHP、Laravelでどう扱うか…。
MySQL
YEARWEEK関数の「モード3」です。
3 - First day of week is Monday and the first week has more than 3 days
とありますが、要するにこれが ISO-8601 ということ。
こうなります。
SELECT YEARWEEK( created_at, 3 ) AS week
PHP
date には W を与えると週番号になります(単にWをそのまま出力したい場合は \W とエスケープする必要があります)。
strtotime では、年と週番号を W を挟んで 'yyyyWww'
という形式で与えます。たとえば '2018W35'
。
date('Y/m/d'); // 今日が 2018/08/29 だとすると…
date('Y\WW',strtotime("-0 weeks")); // 2018W35(1つ目のWはエスケープしてそのまま出力)
date('Y/m/d D',strtotime("2018W35")); // 2018/08/27 Mon
date('Y\WW',strtotime("-52 weeks")); // 2017W35
date('Y/m/d D',strtotime("2017W35")); // 2017/08/28 Mon
-0 weeks だと今日を含む週で、まだ7日経過していないません。
通常は集計対象から外して、集計期間を -52週~-1週 を対象とします。
Laravel
MyOrdersList という Eloquent モデルがあったとして…
// 集計したい週数
$weeks = 52;
// 開始日時をタイムスタンプにしておく
$start_time = strtotime(date('Y\WW',strtotime("-{$weeks} weeks")));
$result = MyOrdersList::select(
DB::raw('YEARWEEK(created_at,3) AS week'),
DB::raw('sum(*) AS price')
)->whereRaw("created_at >= '".date('Y-m-d 00:00:00',$start_time)."'")
->groupBy('week')
->pluck('price','week')
->toArray();
// 歯抜けなしデータにしながらキーをY-m-d形式に
$filled_result = [];
for( $i=$weeks; $i>=1; $i-- ){
$week = date('YW',strtotime("-$i weeks"));
$date = date('Y-m-d',strtotime("-$i weeks"));
$filled_result[$date] = isset($result[$week]) ? $result[$week] : 0;
}
return $filled_result;
=> [
"2017-08-30" => 351,
"2017-09-06" => 0,
"2017-09-13" => 524,
"2017-09-20" => 434,
......
"2018-08-01" => 144,
"2018-08-08" => 264,
"2018-08-15" => 0,
"2018-08-22" => 491,
]
感想
また誰得な記事が出来上がってしまいましたが…。ユーザーが一人でもいればいっか(自分を含めて)、と思うことにしています。
個人的には週始まりは月曜日派ですが、カレンダーは日曜始まりが多いことないですか?(iPhoneのカレンダーアプリも日曜始まり。これは確か言語と地域の設定による)きっとこれが、僕がカレンダーを全然めくらない理由に違いない。