dateTime = new DateTime();
} else {
$this->dateTime = $dateTime;
}
}
/**
* @param $dateString
* @return Iso8601Date
* @throws ExceptionBadSyntax if the format is not supported
*/
public static function createFromString(string $dateString): Iso8601Date
{
$original = $dateString;
$dateString = trim($dateString);
/**
* Time ?
* (ie only YYYY-MM-DD)
*/
if (strlen($dateString) <= 10) {
/**
* We had the time to 00:00:00
* because {@link DateTime::createFromFormat} with a format of
* Y-m-d will be using the actual time otherwise
*
*/
$dateString .= "T00:00:00";
}
/**
* Space as T
*/
$dateString = str_replace(" ", "T", $dateString);
if (strlen($dateString) <= 13) {
/**
* We had the time to 00:00:00
* because {@link DateTime::createFromFormat} with a format of
* Y-m-d will be using the actual time otherwise
*
*/
$dateString .= ":00:00";
}
if (strlen($dateString) <= 16) {
/**
* We had the time to 00:00:00
* because {@link DateTime::createFromFormat} with a format of
* Y-m-d will be using the actual time otherwise
*
*/
$dateString .= ":00";
}
/**
* Timezone
*/
if (strlen($dateString) <= 19) {
/**
* Because this text metadata may be used in other part of the application
* We add the timezone to make it whole
* And to have a consistent value
*/
$dateString .= date('P');
}
$dateTime = DateTime::createFromFormat(self::getFormat(), $dateString);
if ($dateTime === false) {
$message = "The date string ($original) is not in a valid date format. (" . join(", ", self::VALID_FORMATS) . ")";
throw new ExceptionBadSyntax($message, self::CANONICAL);
}
return new Iso8601Date($dateTime);
}
public static function createFromTimestamp($timestamp): Iso8601Date
{
$dateTime = new DateTime();
$dateTime->setTimestamp($timestamp);
return new Iso8601Date($dateTime);
}
/**
* And note {@link DATE_ISO8601}
* because it's not the compliant IS0-8601 format
* as explained here
* https://www.php.net/manual/en/class.datetimeinterface.php#datetime.constants.iso8601
* ATOM is
*
* This format is used by Sqlite, Google and is pretty the standard everywhere
* https://www.w3.org/TR/NOTE-datetime
*/
public static function getFormat(): string
{
return DATE_ATOM;
}
/**
*
*/
public static function isValid($value): bool
{
try {
$dateObject = Iso8601Date::createFromString($value);
return $dateObject->isValidDateEntry(); // ??? Validation seems to be at construction
} catch (ExceptionBadSyntax $e) {
return false;
}
}
public function isValidDateEntry(): bool
{
if ($this->dateTime !== false) {
return true;
} else {
return false;
}
}
public static function createFromDateTime(DateTime $dateTime): Iso8601Date
{
return new Iso8601Date($dateTime);
}
public static function createFromNow(): Iso8601Date
{
return new Iso8601Date();
}
/**
* @throws ExceptionNotFound
*/
public static function getInternationalFormatter($constant): int
{
$constantNormalized = trim(strtolower($constant));
switch ($constantNormalized) {
case "none":
return IntlDateFormatter::NONE;
case "full":
return IntlDateFormatter::FULL;
case "relativefull":
return IntlDateFormatter::RELATIVE_FULL;
case "long":
return IntlDateFormatter::LONG;
case "relativelong":
return IntlDateFormatter::RELATIVE_LONG;
case "medium":
return IntlDateFormatter::MEDIUM;
case "relativemedium":
return IntlDateFormatter::RELATIVE_MEDIUM;
case "short":
return IntlDateFormatter::SHORT;
case "relativeshort":
return IntlDateFormatter::RELATIVE_SHORT;
case "traditional":
return IntlDateFormatter::TRADITIONAL;
default:
throw new ExceptionNotFound("The constant ($constant) is not a valid constant", self::CANONICAL);
}
}
public function getDateTime()
{
return $this->dateTime;
}
public function __toString()
{
return $this->getDateTime()->format(self::getFormat());
}
public function toIsoStringMs()
{
return $this->getDateTime()->format("Y-m-d\TH:i:s.u");
}
/**
* Shortcut to {@link DateTime::format()}
* Format only in English
* @param $string
* @return string
* @link https://php.net/manual/en/datetime.format.php
*/
public function format($string): string
{
return $this->getDateTime()->format($string);
}
public function toString()
{
return $this->__toString();
}
/**
* @throws ExceptionBadSyntax
*/
public function formatLocale($pattern = null, $locale = null)
{
/**
* https://www.php.net/manual/en/function.strftime.php
* As been deprecated
* The only alternative with local is
* https://www.php.net/manual/en/intldateformatter.format.php
*
* Based on ISO date
* ICU Date formatter: https://unicode-org.github.io/icu-docs/#/icu4c/udat_8h.html
* ICU Date formats: https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax
* ICU User Guide: https://unicode-org.github.io/icu/userguide/
* ICU Formatting Dates and Times: https://unicode-org.github.io/icu/userguide/format_parse/datetime/
*/
if (strpos($pattern, "%") !== false) {
LogUtility::warning("The date format ($pattern) is no more supported. Why ? Because Php has deprecated strftime. You need to use the Unicode Date Time format", self::CANONICAL);
return strftime($pattern, $this->dateTime->getTimestamp());
}
/**
* This parameters
* are used to format date with the locale
* when the pattern is null
* Doc: https://unicode-org.github.io/icu/userguide/format_parse/datetime/#producing-normal-date-formats-for-a-locale
*
* They may be null by the way.
*
*/
$dateType = self::DATE_FORMATTER_TYPE;
$timeType = self::TIME_FORMATTER_TYPE;
if ($pattern !== null) {
$normalFormat = explode(" ", $pattern);
if (sizeof($normalFormat) === 2) {
try {
$dateType = self::getInternationalFormatter($normalFormat[0]);
$timeType = self::getInternationalFormatter($normalFormat[1]);
$pattern = null;
} catch (ExceptionNotFound $e) {
// ok
}
}
}
/**
* Formatter instantiation
*/
$formatter = datefmt_create(
$locale,
$dateType,
$timeType,
$this->dateTime->getTimezone(),
IntlDateFormatter::GREGORIAN,
$pattern
);
$formatted = datefmt_format($formatter, $this->dateTime);
if ($formatted === false) {
if ($locale === null) {
$locale = "";
}
if ($pattern === null) {
$pattern = "";
}
throw new ExceptionBadSyntax("Unable to format the date with the pattern ($pattern) and locale ($locale)");
}
return $formatted;
}
public function olderThan(DateTime $rightTime): bool
{
$internalMs = DataType::toMilliSeconds($this->dateTime);
$externalMilliSeconds = DataType::toMilliSeconds($rightTime);
if ($externalMilliSeconds > $internalMs) {
return true;
}
return false;
}
public function diff(DateTime $rightTime): \DateInterval
{
// example get the s part of the diff (even if there is day of diff)
// $seconds = $diff->format('%s');
return $this->dateTime->diff($rightTime, true);
}
}