PHP Classes

File: src/MomentPHP/MomentPHP.php

Recommend this page to a friend!
  Classes of Ladislav Vondracek   PHP Moment Date   src/MomentPHP/MomentPHP.php   Download  
File: src/MomentPHP/MomentPHP.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP Moment Date
Parse, manipulate and format dates
Author: By
Last change: Update of src/MomentPHP/MomentPHP.php
Date: 11 months ago
Size: 23,369 bytes
 

Contents

Class file image Download
<?php /** * MomentPHP is date library for parsing, validating, manipulating, and formatting dates. * It's inspired by the JavaScript library Moment.js, see http://momentjs.com/ * * @author Ladislav Vondráček */ namespace MomentPHP; class MomentPHP { const VERSION = '1.1'; const SECONDS = 'seconds'; const MINUTES = 'minutes'; const HOURS = 'hours'; const DAYS = 'days'; const MONTHS = 'months'; const YEARS = 'years'; /** @var \DateTime */ private $dateTime; /** @var array */ public $lang = array( 'relativeTime' => array( 'future' => 'in %s', 'past' => '%s ago', 's' => '%d seconds', 'i' => 'a minute', 'i+' => '%d minutes', 'h' => 'an hour', 'h+' => '%d hours', 'd' => 'a day', 'd+' => '%d days', 'm' => 'a month', 'm+' => '%d months', 'y' => 'a year', 'y+' => '%d years', ), ); /** * @param \DateTime|MomentPHP|string|int|null $dateTime Instance of classes \DateTime or MomentPHP or string representing the time or timestamp or null for now. * @param array|string|null $format Field formats or simple formatting options, see http://php.net/manual/en/datetime.createfromformat.php * @param \DateTimeZone|string|null $timeZone Supported Timezones, see http://php.net/manual/en/timezones.php * @throws InvalidArgumentException */ public function __construct($dateTime = null, $format = null, $timeZone = null) { $this->validateDateTime($dateTime); $this->validateFormat($format); $this->validateTimeZone($timeZone); $timeZone = $this->createDateTimeZone($timeZone); try { // set dateTime by type if (!isset($dateTime)) { $this->dateTime = new \DateTime('now', $timeZone); } elseif ($dateTime instanceof \DateTime) { $this->dateTime = $dateTime; } elseif ($dateTime instanceof MomentPHP) { $this->dateTime = $dateTime->dateTime; } elseif (is_string($dateTime)) { $this->dateTime = $this->fromFormat($dateTime, $format, $timeZone); } elseif (is_int($dateTime)) { $this->dateTime = $this->fromFormat($dateTime, 'U', $timeZone); } } catch (\Exception $e) { throw new InvalidArgumentException($e->getMessage()); } $error = $this->dateTime->getLastErrors(); if ($error['warning_count'] > 0) { $msg = 'WARNINGS: ' . join('; ', $error['warnings']); throw new InvalidArgumentException($msg); } if ($error['error_count'] > 0) { $msg = 'ERRORS: ' . join('; ', $error['errors']); throw new InvalidArgumentException($msg); } } /** * @return MomentPHP */ public function __clone() { $this->dateTime = clone $this->dateTime; } /** * @return \DateTime */ public function getDateTime() { return $this->dateTime; } /************************************ DISPLAY ************************************/ /** * Return formatted date time. * * @param string $format * @return string * @throws InvalidArgumentException */ public function format($format) { if (!is_string($format)) { throw new InvalidArgumentException('Type of format is invalid.'); } $stringDatetime = $this->dateTime->format($format); return $stringDatetime; } /** * Seconds from the Unix Epoch (January 1 1970 00:00:00 GMT) to date time. * * @return int */ public function timestamp() { $timestamp = $this->format('U'); return (int)$timestamp; } /** * Seconds of date time with leading zeros. * * @return string */ public function seconds() { $seconds = $this->dateTime->format('s'); return $seconds; } /** * Alias for method seconds(). * * @inherit */ public function second() { return $this->seconds(); } /** * Minutes of date time with leading zeros. * * @return string */ public function minutes() { $minutes = $this->format('i'); return $minutes; } /** * Alias for method minutes(). * * @inherit */ public function minute() { return $this->minutes(); } /** * 24-hour format of an hour of date time with leading zeros. * * @return string */ public function hours() { $hours = $this->format('H'); return $hours; } /** * Alias for method hours(). * * @inherit */ public function hour() { return $this->hours(); } /** * Days of date time with leading zeros. * * @return string */ public function days() { $days = $this->format('d'); return $days; } /** * Alias for method days(). * * @inherit */ public function day() { return $this->days(); } /** * ISO-8601 week number of year, weeks starting on Monday. * * @return string */ public function weeks() { $weeks = $this->format('W'); return $weeks; } /** * Alias for method weeks(). * * @inherit */ public function week() { return $this->weeks(); } /** * Numeric representation of a month of date time with leading zeros. * * @return string */ public function months() { $months = $this->format('m'); return $months; } /** * Alias for method months(). * * @inherit */ public function month() { return $this->months(); } /** * A full numeric representation of a year of date time. * * @return string */ public function years() { $years = $this->format('Y'); return $years; } /** * Alias for method years(). * * @inherit */ public function year() { return $this->years(); } /** * ISO-8601 numeric representation of the day of the week. 1 (for Monday) through 7 (for Sunday). * * @return string */ public function dayOfWeek() { $ofWeek = $this->format('N'); return $ofWeek; } /** * The day of the year (starting from 1). * * @return string */ public function dayOfYear() { $ofYear = $this->format('z'); // transform starting from 1 $ofYear++; // back to string settype($ofYear, 'string'); return $ofYear; } /** * A textual representation of the day of week, three letters. * * @return string */ public function nameOfDayShort() { $name = $this->format('D'); return $name; } /** * A full textual representation of the day of the week. * * @return string */ public function nameOfDayLong() { $name = $this->format('l'); return $name; } /** * English ordinal suffix for the day of the month, 2 characters, st, nd, rd or th. * * @return string */ public function dayWithSuffix() { $suffix = $this->format('S'); $day = $this->format('j'); return $day . $suffix; } /** * Number of days in the given month, 28 through 31. * * @return string */ public function daysInMonth() { $count = $this->format('t'); return $count; } /** * A short textual representation of a month, three letters. * * @return string */ public function nameOfMonthShort() { $name = $this->format('M'); return $name; } /** * A full textual representation of a month. * * @return string */ public function nameOfMonthLong() { $name = $this->format('F'); return $name; } /** * 12-hour format of an hour AM or PM suffix. * * @return string */ public function hourWithSuffix() { $hour = $this->format('gA'); return $hour; } /** * ISO 8601 format date. * * @return string */ public function isoDate() { $isoDate = $this->format('c'); return $isoDate; } /** * Timezone identifier. * * @return string */ public function nameOfTimezone() { $name = $this->format('e'); return $name; } /** * Timezone offset in seconds, -43200 through 50400. * * @return int */ public function timezoneOffset() { $seconds = $this->format('Z'); return (int)$seconds; } /** * Return the difference in seconds. * * @param MomentPHP|\DateTime|string|int $dateTime * @param string $unit * @param bool $asFloat * @return int * @throws InvalidArgumentException */ public function diff($dateTime, $unit = self::SECONDS, $asFloat = false) { if ($dateTime instanceof MomentPHP) { $diffMoment = $dateTime; } elseif ($dateTime instanceof \DateTime || is_string($dateTime) || is_int($dateTime)) { $diffMoment = new self($dateTime); } else { throw new InvalidArgumentException('Invalid type of datetime to difference.'); } $unit = $this->normalizeUnits($unit); if ($unit === self::YEARS || $unit === self::MONTHS) { // average number of days in the months in the given dates $avgSecondsInMonth = ((int)$this->daysInMonth() + (int)$diffMoment->daysInMonth()) / 2 * 24 * 60 * 60; $differenceMonths = (((int)$this->years() - (int)$diffMoment->years()) * 12) + ((int)$this->months() - (int)$diffMoment->months()); $cloneThis = clone $this; $cloneDiffMoment = clone $diffMoment; $differenceDays = (($this->timestamp() - $cloneThis->startOf(self::MONTHS)->timestamp()) - ($diffMoment->timestamp() - $cloneDiffMoment->startOf(self::MONTHS)->timestamp())) / $avgSecondsInMonth; $differenceTimezone = (($this->timezoneOffset() - $cloneThis->startOf(self::MONTHS)->timezoneOffset()) - ($diffMoment->timezoneOffset() - $cloneDiffMoment->startOf(self::MONTHS)->timezoneOffset())) / $avgSecondsInMonth; $difference = $differenceMonths + $differenceDays - $differenceTimezone; if ($unit === self::YEARS) { $difference /= 12; } } else { $difference = $this->timestamp() - $diffMoment->timestamp(); switch ($unit) { case self::MINUTES: $difference /= 60; break; case self::HOURS: $difference /= (60 * 60); break; case self::DAYS: $difference /= (24 * 60 * 60); break; } } $difference = $asFloat ? round($difference, 2) : (int)floor($difference); return $difference; } /** * The DateTime object as array. Field contains years, months, days, hours, minutes, second and timezone offset. * * @return array */ public function asArray() { $dateField = array( self::SECONDS => $this->seconds(), self::MINUTES => $this->minutes(), self::HOURS => $this->hours(), self::DAYS => $this->days(), self::MONTHS => $this->months(), self::YEARS => $this->years(), 'timezoneOffset' => $this->timezoneOffset(), ); return $dateField; } /** * Return relation time from other time. * * @param MomentPHP|\DateTime|string|int $datetime * @param bool $withoutSuffix * @return string */ public function from($datetime, $withoutSuffix = false) { $diffMoment = new self($datetime); $diff = $this->diff($diffMoment); $negation = ($diff < 0); $diff = abs($diff); $unit = self::SECONDS; // display seconds from 0 to 44 seconds if ($diff >= 45) { $diff = abs($this->diff($diffMoment, self::MINUTES, true)); $unit = self::MINUTES; } // display minutes from 45 to 89 minutes if ($diff >= 45 && $unit == self::MINUTES) { $diff = abs($this->diff($diffMoment, self::HOURS, true)); $unit = self::HOURS; } // display hours from 22 to 36 hours if ($diff >= 22 && $unit == self::HOURS) { $diff = abs($this->diff($diffMoment, self::DAYS, true)); $unit = self::DAYS; } // display months from 25 to 345 days (to 1.5 year) if ($diff >= 25 && $diff < 345 && $unit == self::DAYS) { $diff = abs($this->diff($diffMoment, self::MONTHS, true)); $unit = self::MONTHS; } // display years from 345 days elseif ($diff >= 345 && $unit == self::DAYS) { $diff = abs($this->diff($diffMoment, self::YEARS, true)); $unit = self::YEARS; } $diff = round($diff); $keys = array( self::SECONDS => 's', self::MINUTES => 'i', self::HOURS => 'h', self::DAYS => 'd', self::MONTHS => 'm', self::YEARS => 'y', ); $key = $keys[$unit]; if ($diff > 1 && $unit != self::SECONDS) { $key .= '+'; } $lang = $this->lang['relativeTime']; $output = sprintf($lang[$key], $diff); if (!$withoutSuffix) { $output = $negation ? sprintf($lang['future'], $output) : sprintf($lang['past'], $output); } return $output; } /** * Return relation time from now. * * @param bool $withoutSuffix * @return string */ public function fromNow($withoutSuffix = false) { $now = new self; $output = $now->from($this, $withoutSuffix); return $output; } /************************************ MANIPULATE ************************************/ /** * Adds an amount of days, months, years, hours, minutes and seconds. * * @param \DateInterval|array|int $number * @param string $unit * @return $this */ public function add($number, $unit = null) { if ($number instanceof \DateInterval) { $interval = $number; } elseif (is_array($number)) { $expression = $this->getIntervalExpressionFromArray($number); $interval = \DateInterval::createFromDateString($expression); } elseif (is_int($number)) { $expression = $this->getIntervalExpression($number, $unit); $interval = \DateInterval::createFromDateString($expression); } $this->dateTime->add($interval); return $this; } /** * Subtracts an amount of days, months, years, hours, minutes and seconds. * * @param \DateInterval|array|int $number * @param string|null $unit * @return $this */ public function sub($number, $unit = null) { if ($number instanceof \DateInterval) { $interval = $number; } elseif (is_array($number)) { $expression = $this->getIntervalExpressionFromArray($number); $interval = \DateInterval::createFromDateString($expression); } elseif (is_int($number)) { $expression = $this->getIntervalExpression($number, $unit); $interval = \DateInterval::createFromDateString($expression); } $this->dateTime->sub($interval); return $this; } /** * Mutates the original moment by setting it to the start of a unit of time. * * @param string $unit * @return $this */ public function startOf($unit) { $unit = $this->normalizeUnits($unit); $dateField = $this->asArray(); switch ($unit) { case self::YEARS: $dateField[self::MONTHS] = '01'; case self::MONTHS: $dateField[self::DAYS] = '01'; case self::DAYS: $dateField[self::HOURS] = '00'; case self::HOURS: $dateField[self::MINUTES] = '00'; case self::MINUTES: $dateField[self::SECONDS] = '00'; } $this->modifyDateTime($dateField); return $this; } /** * Mutates the original moment by setting it to the end of a unit of time. * * @param string $unit * @return $this */ public function endOf($unit) { $unit = $this->normalizeUnits($unit); $dateField = $this->asArray(); switch ($unit) { case self::YEARS: $dateField[self::MONTHS] = '12'; case self::MONTHS: $dateField[self::DAYS] = $this->daysInMonth(); case self::DAYS: $dateField[self::HOURS] = '23'; case self::HOURS: $dateField[self::MINUTES] = '59'; case self::MINUTES: $dateField[self::SECONDS] = '59'; } $this->modifyDateTime($dateField); return $this; } /************************************ QUERY ************************************/ /** * Whether it's a leap year. * * @return bool */ public function isLeapYear() { $isLeap = $this->format('L'); return (bool)$isLeap; } /** * Whether or not the date is in daylight saving time. * * @return bool */ public function isDST() { $isDST = $this->format('I'); return (bool)$isDST; } /** * Check if a moment is before another moment. * * @param MomentPHP|\DateTime|string|int $datetime * @param string $unit * @return bool */ public function isBefore($datetime, $unit = self::SECONDS) { $compareMoment = new self($datetime); $originMoment = clone($this); $compareMoment->startOf($unit); $originMoment->startOf($unit); $difference = $originMoment->diff($compareMoment); return ($difference < 0); } /** * Check if a moment is after another moment. * * @param MomentPHP|\DateTime|string|int $datetime * @param string $unit * @return bool */ public function isAfter($datetime, $unit = self::SECONDS) { $compareMoment = new self($datetime); $originMoment = clone($this); $compareMoment->startOf($unit); $originMoment->startOf($unit); $difference = $originMoment->diff($compareMoment); return ($difference > 0); } /** * Check if a moment is same another moment. * * @param MomentPHP|\DateTime|string|int $datetime * @param string $unit * @return bool */ public function isSame($datetime, $unit = self::SECONDS) { $compareMoment = new self($datetime); $originMoment = clone($this); $compareMoment->startOf($unit); $originMoment->startOf($unit); $difference = $originMoment->diff($compareMoment); return ($difference == 0); } /** * Check if a variable is a MomentPHP object. * * @param mixed $moment * @return bool */ public function isMomentPHP($moment) { return ($moment instanceof MomentPHP); } /************************************ INTERNAL ************************************/ /** * @param mixed $dateTime * @throws InvalidArgumentException */ private function validateDateTime($dateTime) { // invalid if... if ( isset($dateTime) && // ...exists and... !($dateTime instanceof MomentPHP) && // ...not MomentPHP !($dateTime instanceof \DateTime) && // ...not \DateTime !is_string($dateTime) && // ...not string !is_int($dateTime) || // ...not integer (is_string($dateTime) && strlen($dateTime) === 0) || // ...not empty string (is_int($dateTime) && $dateTime < 0) // ...not negative integer ) { throw new InvalidArgumentException('Type of datetime is invalid.'); } } /** * @param mixed $format * @throws InvalidArgumentException */ private function validateFormat($format) { // invalid if... if ( isset($format) && // ...exists and... !is_array($format) && // ...not array !is_string($format) || // ...not string (is_array($format) && count($format) === 0) || // ...not empty array (is_string($format) && strlen($format) === 0) // ...not empty string ) { throw new InvalidArgumentException('Type of format is invalid.'); } } /** * @param mixed $timeZone * @throws InvalidArgumentException */ private function validateTimeZone($timeZone) { // invalid if... if ( isset($timeZone) && // ...exists and... !($timeZone instanceof \DateTimeZone) && // ...not \DateTimeZone !is_string($timeZone) || // ...not string (is_string($timeZone) && strlen($timeZone) === 0) // ...not empty string ) { throw new InvalidArgumentException('Type of timezone is invalid.'); } } /** * Create DateTime * * @param string $dateTime * @param array|string|null $format * @param \DateTimeZone $timeZone * @return \DateTime * @throws ErrorException */ private function fromFormat($dateTime, $format, $timeZone) { // without format if (!isset($format)) { $return = new \DateTime($dateTime, $timeZone); } // simple format elseif (is_string($format)) { $return = \DateTime::createFromFormat($format, $dateTime, $timeZone); } // walk all formats elseif (is_array($format)) { foreach ($format as $item) { $return = \DateTime::createFromFormat($item, $dateTime, $timeZone); // return first acceptable format if ($return instanceof \DateTime) { break; } } } if ($return === false) { throw new ErrorException('DateTime not create. Probably the wrong format.'); } return $return; } /** * @param \DateTimeZone|string|null $timeZone * @return \DateTimeZone */ private function createDateTimeZone($timeZone) { if (!isset($timeZone)) { $defaultTimeZone = date_default_timezone_get(); $return = new \DateTimeZone($defaultTimeZone); } elseif (is_string($timeZone)) { $return = new \DateTimeZone($timeZone); } elseif ($timeZone instanceof \DateTimeZone) { $return = $timeZone; } return $return; } /** * @param array $numbers * @return string * @throws InvalidArgumentException */ private function getIntervalExpressionFromArray(array $numbers) { if (count($numbers) === 0) { throw new InvalidArgumentException('Count items must be nonzero.'); } $expressions = array(); foreach ($numbers as $unit => $number) { $expressions[] = $this->getIntervalExpression($number, $unit); } return join(' ', $expressions); } /** * @param int $number * @param string $unit * @return string * @throws InvalidArgumentException */ private function getIntervalExpression($number, $unit) { if (!is_int($number)) { throw new InvalidArgumentException('The number must be integer.'); } $unit = $this->normalizeUnits($unit); $expression = $number . ' ' . $unit; return $expression; } /** * @param string $unit * @return string mixed * @throws InvalidArgumentException */ private function normalizeUnits($unit) { $validUnits = array( 'sec' => self::SECONDS, 'second' => self::SECONDS, 'seconds' => self::SECONDS, 'min' => self::MINUTES, 'minute' => self::MINUTES, 'minutes' => self::MINUTES, 'hour' => self::HOURS, 'hours' => self::HOURS, 'day' => self::DAYS, 'days' => self::DAYS, 'month' => self::MONTHS, 'months' => self::MONTHS, 'year' => self::YEARS, 'years' => self::YEARS ); if (!array_key_exists($unit, $validUnits)) { $options = array_keys($validUnits); $options = join(', ', $options); throw new InvalidArgumentException('The unit must be from this options: ' . $options); } $unit = $validUnits[$unit]; return $unit; } /** * @param array $fields Array with years, months, days, hours, minutes and seconds as keys. */ public function modifyDateTime(array $fields) { $this->dateTime->setDate($fields[self::YEARS], $fields[self::MONTHS], $fields[self::DAYS]); $this->dateTime->setTime($fields[self::HOURS], $fields[self::MINUTES], $fields[self::SECONDS]); } } class InvalidArgumentException extends \InvalidArgumentException {}; class ErrorException extends \ErrorException {};