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\Equator;
30: use Peach\Util\Values;
31:
32: /**
33: * 時間オブジェクトの比較を行うための Equator です.
34: * このクラスは, 時間オブジェクトをキーとした {@link \Peach\Util\HashMap}
35: * を構築する際に使用してください.
36: */
37: class TimeEquator implements Equator
38: {
39: /**
40: * 比較対象のフィールドの配列です.
41: * array("year", "month", "date")
42: * のような文字列型の配列となります.
43: *
44: * @var array
45: */
46: private $fields;
47:
48: /**
49: * 比較対象のフィールドを指定して, 新しい TimeEquator オブジェクトを作成します.
50: * 引数の指定方法には以下の方法があります.
51: *
52: * <code>
53: * new TimeEquator();
54: * new TimeEquator(array("hour", "minute", "second"));
55: * new TimeEquator("date");
56: * new TimeEquator(Time::TYPE_DATE);
57: * </code>
58: *
59: * 引数なしでオブジェクトを生成した場合, このオブジェクトは
60: * {@link Time::equals()} を使って比較を行います.
61: * 通常は, 引数なしのコンストラクタを使う代わりに
62: * {@link TimeEquator::getDefault()} を使用してください.
63: *
64: * 引数に比較対象のフィールドを配列で指定した場合,
65: * 指定されたフィールドすべてが等しい場合に等価とみなします.
66: *
67: * 比較対象のフィールドが 1 つだけの場合, そのフィールドを文字列で指定することもできます.
68: *
69: * また, 以下の定数を使用することもできます.
70: *
71: * - {@link Time::TYPE_DATE}
72: * - {@link Time::TYPE_DATETIME}
73: * - {@link Time::TYPE_TIMESTAMP}
74: *
75: * それぞれ
76: *
77: * - array("year", "month", "date")
78: * - array("year", "month", "date", "hour", "minute")
79: * - array("year", "month", "date", "hour", "minute", "second")
80: *
81: * を指定した場合と同じになります.
82: *
83: * @param mixed $fields 比較対象のフィールド一覧
84: */
85: public function __construct($fields = null)
86: {
87: $this->fields = $this->initFields($fields);
88: }
89:
90: /**
91: * このオブジェクトの比較対象フィールド一覧を初期化します.
92: *
93: * @param mixed $fields
94: * @return array
95: */
96: private function initFields($fields)
97: {
98: switch ($fields) {
99: case Time::TYPE_DATE:
100: return $this->initFields(array("year", "month", "date"));
101: case Time::TYPE_DATETIME:
102: return $this->initFields(array("year", "month", "date", "hour", "minute"));
103: case Time::TYPE_TIMESTAMP:
104: return $this->initFields(array("year", "month", "date", "hour", "minute", "second"));
105: }
106:
107: if (is_array($fields)) {
108: return count($fields) ? $fields : null;
109: }
110: if (is_string($fields)) {
111: return array($fields);
112: }
113:
114: return null;
115: }
116:
117: /**
118: * デフォルトの Equator オブジェクトを返します.
119: * このオブジェクトは {@link Time::equals()} を使って等値性を調べます.
120: * @return TimeEquator
121: */
122: public static function getDefault()
123: {
124: static $instance = null;
125: if (!isset($instance)) {
126: $instance = new self();
127: }
128: return $instance;
129: }
130:
131: /**
132: * 指定された 2 つの時間オブジェクトが等しいかどうか調べます.
133: * この Equator に設定されているフィールドについて比較を行い,
134: * 全て等しい場合のみ TRUE を返します.
135: *
136: * @param Time $var1 比較対象の時間オブジェクト
137: * @param Time $var2 比較対象の時間オブジェクト
138: * @return bool 2 つの時間オブジェクトが等しいと判断された場合のみ TRUE
139: * @throws \InvalidArgumentException 引数に Time インスタンス以外の値が指定された場合
140: */
141: public function equate($var1, $var2)
142: {
143: if (!($var1 instanceof Time) || !($var2 instanceof Time)) {
144: $arg1 = Values::getType($var1);
145: $arg2 = Values::getType($var2);
146: throw new \InvalidArgumentException("arguments must be Time instance.({$arg1}, {$arg2})");
147: }
148:
149: $fields = $this->fields;
150: if (isset($fields)) {
151: foreach ($fields as $field) {
152: if ($var1->get($field) !== $var2->get($field)) {
153: return false;
154: }
155: }
156: return true;
157: } else {
158: return $var1->equals($var2);
159: }
160: }
161:
162: /**
163: * 年・月・日・時・分・秒の各フィールドからハッシュ値を算出します.
164: *
165: * @param mixed $var
166: * @return int ハッシュ値
167: * @throws \InvalidArgumentException 引数が Time インスタンスでなかった場合
168: */
169: public function hashCode($var)
170: {
171: if (!($var instanceof Time)) {
172: $type = Values::getType($var);
173: throw new \InvalidArgumentException("The value must be Time instance.({$type})");
174: }
175:
176: return
177: $var->get("year") +
178: $var->get("month") * 31 + // 31^1
179: $var->get("date") * 961 + // 31^2
180: $var->get("hour") * 29791 + // 31^3
181: $var->get("minute") * 923521 + // 31^4
182: $var->get("second") * 28629151; // 31^5
183: }
184: }
185: