1: <?php
2: /*
3: * Copyright (c) 2014 @trashtoy
4: * https://github.com/trashtoy/
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy of
7: * this software and associated documentation files (the "Software"), to deal in
8: * the Software without restriction, including without limitation the rights to use,
9: * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10: * Software, and to permit persons to whom the Software is furnished to do so,
11: * subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in all
14: * copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18: * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19: * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20: * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21: * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22: */
23: /**
24: * PHP class file.
25: * @auhtor trashtoy
26: * @since 2.0.0
27: */
28: namespace Peach\DT;
29:
30: /**
31: * システム内部の時差とフォーマットの時差を自動で調整するためのフォーマットです.
32: * 「閲覧しているユーザーのタイムゾーンに合わせて表示する時刻を調整したい」
33: * といったケースで, 既存の Format オブジェクトを上書きする形で利用します.
34: *
35: * サンプルとして, 日本語のサイトがニューヨークのサーバーで管理されているというシナリオを考えます.
36: * サーバー側ではタイムゾーンを America/New_York (UTC-5) として時間の管理をしているが,
37: * ブラウザに出力する際は Asia/Tokyo (UTC+9) のタイムゾーンで表示させたいとします.
38: *
39: * <code>
40: * // php.ini で timezone = America/New_York が設定されているものとする
41: *
42: * // 表示用の時刻を UTC+9 とする (-540 分のオフセットを指定する)
43: * $f = new ShiftFormat(new SimpleFormat("Y/m/d H:i:s"), -540);
44: *
45: * // 日本のユーザーが入力した時刻をサーバー内部の時刻に変換する
46: * $d = Timestamp::parse("2012/05/21 07:30:45", $f);
47: * echo $d; // "2012-05-20 17:30:45" (UTC+9 から UTC-5 に変換)
48: *
49: * // サーバで管理されている時刻を日本のユーザー向けに変換する
50: * $d = new Timestamp(2012, 1, 1, 0, 0, 0);
51: * echo $d->format($f); // "2012/01/01 14:00:00" (UTC-5 から UTC+9 に変換)
52: * </code>
53: *
54: * このクラスの parseDate と formatDate は時差の変換を行いません.
55: * オリジナルの実行結果をそのまま返します.
56: *
57: * ちなみに {@link W3cDatetimeFormat} と {@link HttpDateFormat}
58: * に関しては, 自身でタイムゾーンの変換機能をサポートしているため,
59: * このクラスを使う必要はありません.
60: */
61: class ShiftFormat extends FormatWrapper
62: {
63: /**
64: * システム時刻の時差です (単位は分)
65: * @var int
66: */
67: private $internalOffset;
68:
69: /**
70: * フォーマットの時差です (単位は分)
71: * @var int
72: */
73: private $externalOffset;
74:
75: /**
76: * フォーマットの時差とシステム時刻の時差を指定して,
77: * 新しい ShiftFormat を構築します.
78: * 引数の単位は分です. UTC+1 以降の場合は負の値,
79: * UTC-1 以前の場合は正の値を指定してください.
80: *
81: * @param Format $original 調整対象のフォーマット
82: * @param int $externalOffset フォーマットの時差 (単位は分)
83: * @param int $internalOffset システム時刻の時差 (単位は分, 省略した場合はシステム設定の値を使用)
84: */
85: public function __construct(Format $original, $externalOffset, $internalOffset = null)
86: {
87: parent::__construct($original);
88: $this->externalOffset = Util::cleanTimeZoneOffset($externalOffset);
89: $this->internalOffset = Util::cleanTimeZoneOffset($internalOffset);
90: }
91:
92: /**
93: * オリジナルの parseDatetime で得られた結果をシステム時刻に変換して返します.
94: * @param string $format 解析対象の文字列
95: * @return Time 変換結果
96: */
97: public function parseDatetime($format)
98: {
99: return $this->adjustFromParse(parent::parseDatetime($format));
100: }
101:
102: /**
103: * オリジナルの parseTimestamp で得られた結果をシステム時刻に変換して返します.
104: * @param string $format 解析対象の文字列
105: * @return Time 変換結果
106: */
107: public function parseTimestamp($format)
108: {
109: return $this->adjustFromParse(parent::parseTimestamp($format));
110: }
111:
112: /**
113: * parse 系メソッドから呼ばれる変換処理です.
114: * @param Time $d parse された時間オブジェクト
115: * @return Time 表示と内部の時差だけ「分」を移動させた時間オブジェクト
116: */
117: private function adjustFromParse(Time $d)
118: {
119: return $d->add("minute", $this->externalOffset - $this->internalOffset);
120: }
121:
122: /**
123: * 変換対象の時間オブジェクトを表示用のタイムゾーンに変換してから,
124: * オリジナルの formatDatetime を実行します.
125: * @param Datetime $d 変換対象の時間オブジェクト
126: * @return string 変換結果
127: */
128: public function formatDatetime(Datetime $d)
129: {
130: return parent::formatDatetime($this->adjustFromFormat($d));
131: }
132:
133: /**
134: * 変換対象の時間オブジェクトを表示用のタイムゾーンに変換してから,
135: * オリジナルの formatTimestamp を実行します.
136: * @param Timestamp $d 変換対象の時間オブジェクト
137: * @return string 変換結果
138: */
139: public function formatTimestamp(Timestamp $d)
140: {
141: return parent::formatTimestamp($this->adjustFromFormat($d));
142: }
143:
144: /**
145: * format 系メソッドから呼ばれる変換処理です.
146: * @param Time $d 変換対象の時間オブジェクト
147: * @return Time 表示と内部の時差だけ「分」を移動させた時間オブジェクト
148: */
149: private function adjustFromFormat(Time $d)
150: {
151: return $d->add("minute", $this->internalOffset - $this->externalOffset);
152: }
153: }
154: