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: use Peach\Util\Map;
30: use Peach\Util\ArrayMap;
31:
32: /**
33: * DATETIME 型の時間オブジェクトです.
34: * このクラスは年・月・日・時・分のフィールドをサポートします.
35: */
36: class Datetime extends Date
37: {
38: /**
39: * 時を表す整数(0~23)です.
40: * @var int
41: * @ignore
42: */
43: protected $hour = 0;
44:
45: /**
46: * 分を表す整数(0~59)です.
47: * @var int
48: * @ignore
49: */
50: protected $minute = 0;
51:
52: /**
53: * 現在時刻の Datetime オブジェクトを返します.
54: *
55: * @param Clock $clock 現在時刻を取得するための Clock オブジェクト
56: * @return Datetime 現在時刻をあらわす Datetime
57: */
58: public static function now(Clock $clock = null)
59: {
60: if ($clock === null) {
61: return self::now(DefaultClock::getInstance());
62: }
63:
64: return $clock->getTimestamp()->toDatetime();
65: }
66:
67: /**
68: * 指定されたテキストを解析して Datetime オブジェクトに変換します.
69: * $format が指定されていない場合は {@link W3cDatetimeFormat::getInstance}
70: * を使って解析を行います.
71: * ("YYYY-MM-DD hh:mm" 形式の文字列を受理します.
72: * 日付と時刻のセパレータは, 数字以外の ASCII 1 文字であれば何でも構いません.)
73: *
74: * @param string $text 変換対象の文字列
75: * @param Format $format 変換に使用するフォーマット
76: * @return Datetime 変換結果
77: */
78: public static function parse($text, Format $format = null)
79: {
80: if (!isset($format)) {
81: $format = W3cDatetimeFormat::getInstance();
82: }
83: return $format->parseDatetime($text);
84: }
85:
86: /**
87: * 与えられた時刻を表現する Datetime オブジェクトを構築します.
88: *
89: * @param int $year 年
90: * @param int $month 月
91: * @param int $date 日
92: * @param int $hour 時
93: * @param int $min 分
94: */
95: public function __construct($year, $month, $date, $hour, $min)
96: {
97: $fields = new ArrayMap();
98: $fields->put(self::$YEAR, intval($year));
99: $fields->put(self::$MONTH, intval($month));
100: $fields->put(self::$DATE, intval($date));
101: $fields->put(self::$HOUR, intval($hour));
102: $fields->put(self::$MINUTE, intval($min));
103: $this->init($fields);
104: }
105:
106: /**
107: * このオブジェクトの型 {@link Time::TYPE_DATETIME} を返します.
108: * @return int Time::TYPE_DATETIME
109: */
110: public function getType()
111: {
112: return self::TYPE_DATETIME;
113: }
114:
115: /**
116: * @ignore
117: */
118: protected function init(Map $fields)
119: {
120: parent::init($fields);
121: $this->hour = $fields->get(self::$HOUR);
122: $this->minute = $fields->get(self::$MINUTE);
123: }
124:
125: /**
126: * 時刻の不整合を調整します.
127: * @ignore
128: */
129: protected function adjust(Map $fields)
130: {
131: parent::adjust($fields);
132: $hourAd = $this->getHourAdjuster();
133: $minAd = $this->getMinuteAdjuster();
134: $hour = $fields->get(self::$HOUR);
135: $min = $fields->get(self::$MINUTE);
136:
137: if ($hour < 0) {
138: $hourAd->moveDown($fields);
139: } else if (23 < $hour) {
140: $hourAd->moveUp($fields);
141: } else if ($min < 0) {
142: $minAd->moveDown($fields);
143: } else if (59 < $min) {
144: $minAd->moveUp($fields);
145: } else {
146: return;
147: }
148:
149: $this->adjust($fields);
150: }
151:
152: /**
153: * (non-PHPdoc)
154: *
155: * @return Datetime
156: * @see AbstractTime::newInstance
157: * @ignore
158: */
159: protected function newInstance(Map $fields)
160: {
161: $year = $fields->get(self::$YEAR);
162: $month = $fields->get(self::$MONTH);
163: $date = $fields->get(self::$DATE);
164: $hour = $fields->get(self::$HOUR);
165: $min = $fields->get(self::$MINUTE);
166: return new self($year, $month, $date, $hour, $min);
167: }
168:
169: /**
170: * この時間と指定された時間を比較します.
171: *
172: * この型の時間フィールドと引数の型の時間フィールドのうち,
173: * 共通しているフィールド同士を比較します.
174: *
175: * 引数がこのクラスを継承したオブジェクトではない場合,
176: * 引数のオブジェクトに対して get("year"), get("month"), get("date"), get("hour"), get("minute")
177: * を呼び出した結果を比較対象のフィールドとします.
178: *
179: * @param Time 比較対象の時間
180: * @return int この時間のほうが過去の場合は負の値, 未来の場合は正の値, それ以外は 0
181: * @ignore
182: */
183: protected function compareFields(Time $time)
184: {
185: $c = parent::compareFields($time);
186: if ($c !== 0) {
187: return $c;
188: }
189:
190: $className = __CLASS__;
191: if ($time instanceof $className) {
192: if ($this->hour !== $time->hour) {
193: return $this->hour - $time->hour;
194: }
195: if ($this->minute !== $time->minute) {
196: return $this->minute - $time->minute;
197: }
198: return 0;
199: }
200: else {
201: $h = $time->get("hour");
202: $m = $time->get("minute");
203: if ($this->hour !== $h) {
204: return (isset($h) ? $this->hour - $h : 0);
205: }
206: if ($this->minute !== $m) {
207: return (isset($m) ? $this->minute - $m : 0);
208: }
209: return 0;
210: }
211: }
212:
213: /**
214: * @ignore
215: */
216: protected function handleFormat(Format $format)
217: {
218: return $format->formatDatetime($this);
219: }
220:
221: /**
222: * このオブジェクトの時刻部分の文字列を "hh:mm" 形式で返します.
223: *
224: * @return string "hh:mm" 形式の文字列
225: */
226: public function formatTime()
227: {
228: $hour = str_pad($this->hour, 2, '0', STR_PAD_LEFT);
229: $min = str_pad($this->minute, 2, '0', STR_PAD_LEFT);
230: return $hour . ":" . $min;
231: }
232:
233: /**
234: * このオブジェクトの文字列表現です.
235: * "YYYY-MM-DD hh:mm" 形式の文字列を返します.
236: *
237: * @return string W3CDTF に則った文字列表現
238: */
239: public function __toString()
240: {
241: $date = parent::__toString();
242: return $date . ' ' . $this->formatTime();
243: }
244:
245: /**
246: * このオブジェクトを Datetime 型にキャストします.
247: * 返り値はこのオブジェクトのクローンです.
248: *
249: * @return Datetime このオブジェクトのクローン
250: */
251: public function toDatetime()
252: {
253: return new self($this->year, $this->month, $this->date, $this->hour, $this->minute);
254: }
255:
256: /**
257: * このオブジェクトを Timestamp 型にキャストします.
258: * この時刻の 0 秒を表す Timestamp オブジェクトを返します.
259: *
260: * @return Timestamp このオブジェクトの timestamp 表現
261: */
262: public function toTimestamp()
263: {
264: return new Timestamp($this->year, $this->month, $this->date, $this->hour, $this->minute, 0);
265: }
266:
267: /**
268: * 「時」フィールドを調整する Adjuster です
269: * @return FieldAdjuster
270: * @codeCoverageIgnore
271: */
272: private function getHourAdjuster()
273: {
274: static $adjuster = null;
275: if ($adjuster === null) {
276: $adjuster = new FieldAdjuster(self::$HOUR, self::$DATE, 0, 23);
277: }
278: return $adjuster;
279: }
280:
281: /**
282: * 「分」フィールドを調整する Adjuster です
283: * @return FieldAdjuster
284: * @codeCoverageIgnore
285: */
286: private function getMinuteAdjuster()
287: {
288: static $adjuster = null;
289: if ($adjuster === null) {
290: $adjuster = new FieldAdjuster(self::$MINUTE, self::$HOUR, 0, 59);
291: }
292: return $adjuster;
293: }
294: }
295: