00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00021 class Date implements Stringable, DialectString
00022 {
00023 const WEEKDAY_MONDAY = 1;
00024 const WEEKDAY_TUESDAY = 2;
00025 const WEEKDAY_WEDNESDAY = 3;
00026 const WEEKDAY_THURSDAY = 4;
00027 const WEEKDAY_FRIDAY = 5;
00028 const WEEKDAY_SATURDAY = 6;
00029 const WEEKDAY_SUNDAY = 0;
00030
00031 protected $string = null;
00032 protected $int = null;
00033
00034 protected $year = null;
00035 protected $month = null;
00036 protected $day = null;
00037
00041 public static function create($date)
00042 {
00043 return new self($date);
00044 }
00045
00046 public static function today($delimiter = '-')
00047 {
00048 return date("Y{$delimiter}m{$delimiter}d");
00049 }
00050
00054 public static function makeToday()
00055 {
00056 return new self(self::today());
00057 }
00058
00064 public static function makeFromWeek($weekNumber, $year = null)
00065 {
00066 if (!$year)
00067 $year = date('Y');
00068
00069 Assert::isTrue(
00070 ($weekNumber > 0)
00071 && ($weekNumber <= self::getWeekCountInYear($year))
00072 );
00073
00074 $date =
00075 new self(
00076 date(
00077 self::getFormat(),
00078 mktime(
00079 0, 0, 0, 1, 1, $year
00080 )
00081 )
00082 );
00083
00084 $days =
00085 (
00086 (
00087 $weekNumber - 1
00088 + (self::getWeekCountInYear($year - 1) == 53 ? 1 : 0)
00089 )
00090 * 7
00091 ) + 1 - $date->getWeekDay();
00092
00093 return $date->modify("+{$days} day");
00094 }
00095
00096 public static function dayDifference(Date $left, Date $right)
00097 {
00098 return
00099 gregoriantojd(
00100 $right->getMonth(),
00101 $right->getDay(),
00102 $right->getYear()
00103 )
00104 - gregoriantojd(
00105 $left->getMonth(),
00106 $left->getDay(),
00107 $left->getYear()
00108 );
00109 }
00110
00111 public static function compare(Date $left, Date $right)
00112 {
00113 if ($left->int == $right->int)
00114 return 0;
00115 else
00116 return ($left->int > $right->int ? 1 : -1);
00117 }
00118
00119 public static function getWeekCountInYear($year)
00120 {
00121 return date('W', mktime(0, 0, 0, 12, 31, $year));
00122 }
00123
00124 public function __construct($date)
00125 {
00126 if (is_int($date) || is_numeric($date)) {
00127 $this->string = date($this->getFormat(), $date);
00128 } elseif ($date && is_string($date))
00129 $this->stringImport($date);
00130
00131 if ($this->string === null) {
00132 throw new WrongArgumentException(
00133 "strange input given - '{$date}'"
00134 );
00135 }
00136
00137 $this->import($this->string);
00138 $this->buildInteger();
00139 }
00140
00141 public function toStamp()
00142 {
00143 return $this->int;
00144 }
00145
00146 public function toDate($delimiter = '-')
00147 {
00148 return
00149 $this->year
00150 .$delimiter
00151 .$this->month
00152 .$delimiter
00153 .$this->day;
00154 }
00155
00156 public function getYear()
00157 {
00158 return $this->year;
00159 }
00160
00161 public function getMonth()
00162 {
00163 return $this->month;
00164 }
00165
00166 public function getDay()
00167 {
00168 return $this->day;
00169 }
00170
00171 public function getWeek()
00172 {
00173 return date('W', $this->int);
00174 }
00175
00176 public function getWeekDay()
00177 {
00178 return strftime('%w', $this->int);
00179 }
00180
00184 public function spawn($modification = null)
00185 {
00186 $child = new $this($this->string);
00187
00188 if ($modification)
00189 return $child->modify($modification);
00190
00191 return $child;
00192 }
00193
00198 public function modify($string)
00199 {
00200 try {
00201 $time = strtotime($string, $this->int);
00202
00203 if ($time === false)
00204 throw new WrongArgumentException(
00205 "modification yielded false '{$string}'"
00206 );
00207
00208 $this->int = $time;
00209 $this->string = date($this->getFormat(), $time);
00210 $this->import($this->string);
00211 } catch (BaseException $e) {
00212 throw new WrongArgumentException(
00213 "wrong time string '{$string}'"
00214 );
00215 }
00216
00217 return $this;
00218 }
00219
00220 public function getDayStartStamp()
00221 {
00222 return
00223 mktime(
00224 0, 0, 0,
00225 $this->month,
00226 $this->day,
00227 $this->year
00228 );
00229 }
00230
00231 public function getDayEndStamp()
00232 {
00233 return
00234 mktime(
00235 23, 59, 59,
00236 $this->month,
00237 $this->day,
00238 $this->year
00239 );
00240 }
00241
00245 public function getFirstDayOfWeek($weekStart = Date::WEEKDAY_MONDAY)
00246 {
00247 return $this->spawn(
00248 '-'.((7 + $this->getWeekDay() - $weekStart) % 7).' days'
00249 );
00250 }
00251
00255 public function getLastDayOfWeek($weekStart = Date::WEEKDAY_MONDAY)
00256 {
00257 return $this->spawn(
00258 '+'.((13 - $this->getWeekDay() + $weekStart) % 7).' days'
00259 );
00260 }
00261
00262 public function toString()
00263 {
00264 return $this->string;
00265 }
00266
00267 public function toDialectString(Dialect $dialect)
00268 {
00269
00270 return $dialect->quoteValue($this->toString());
00271 }
00272
00276 public function toIsoString()
00277 {
00278 return $this->toString();
00279 }
00280
00284 public function toTimestamp()
00285 {
00286 return Timestamp::create($this->toStamp());
00287 }
00288
00289 protected static function getFormat()
00290 {
00291 return 'Y-m-d';
00292 }
00293
00294 protected function import($string)
00295 {
00296 list($this->year, $this->month, $this->day) =
00297 explode('-', $string, 3);
00298
00299 if (!$this->month || !$this->day)
00300 throw new WrongArgumentException(
00301 'month and day must not be zero'
00302 );
00303
00304 $this->string =
00305 sprintf(
00306 '%04d-%02d-%02d',
00307 $this->year,
00308 $this->month,
00309 $this->day
00310 );
00311
00312 list($this->year, $this->month, $this->day) =
00313 explode('-', $this->string, 3);
00314 }
00315
00316 protected function stringImport($string)
00317 {
00318 $matches = array();
00319
00320 if (
00321 preg_match('/^(\d{1,4})-(\d{1,2})-(\d{1,2})$/', $string, $matches)
00322 ) {
00323 if (checkdate($matches[2], $matches[3], $matches[1]))
00324 $this->string = $string;
00325
00326 } elseif (($stamp = strtotime($string)) !== false)
00327 $this->string = date($this->getFormat(), $stamp);
00328 }
00329
00330 protected function buildInteger()
00331 {
00332 $this->int =
00333 mktime(
00334 0, 0, 0,
00335 $this->month,
00336 $this->day,
00337 $this->year
00338 );
00339 }
00340 }
00341 ?>