[Form] Fixed DateTimeToStringTransformer parsing on PHP < 5.3.8
This commit is contained in:
parent
c6bd807726
commit
ad29df5efd
@ -39,23 +39,38 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
|
|||||||
*/
|
*/
|
||||||
private $parseFormat;
|
private $parseFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to parse by appending a pipe "|" to the parse format.
|
||||||
|
*
|
||||||
|
* This only works as of PHP 5.3.8.
|
||||||
|
*
|
||||||
|
* @var Boolean
|
||||||
|
*/
|
||||||
|
private $parseUsingPipe;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a \DateTime instance to a string
|
* Transforms a \DateTime instance to a string
|
||||||
*
|
*
|
||||||
* @see \DateTime::format() for supported formats
|
* @see \DateTime::format() for supported formats
|
||||||
*
|
*
|
||||||
* @param string $inputTimezone The name of the input timezone
|
* @param string $inputTimezone The name of the input timezone
|
||||||
* @param string $outputTimezone The name of the output timezone
|
* @param string $outputTimezone The name of the output timezone
|
||||||
* @param string $format The date format
|
* @param string $format The date format
|
||||||
|
* @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
|
||||||
*
|
*
|
||||||
* @throws UnexpectedTypeException if a timezone is not a string
|
* @throws UnexpectedTypeException if a timezone is not a string
|
||||||
*/
|
*/
|
||||||
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s')
|
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null)
|
||||||
{
|
{
|
||||||
parent::__construct($inputTimezone, $outputTimezone);
|
parent::__construct($inputTimezone, $outputTimezone);
|
||||||
|
|
||||||
$this->generateFormat = $this->parseFormat = $format;
|
$this->generateFormat = $this->parseFormat = $format;
|
||||||
|
|
||||||
|
// The pipe in the parser pattern only works as of PHP 5.3.8
|
||||||
|
$this->parseUsingPipe = null === $parseUsingPipe
|
||||||
|
? version_compare(phpversion(), '5.3.8', '>=')
|
||||||
|
: $parseUsingPipe;
|
||||||
|
|
||||||
// See http://php.net/manual/en/datetime.createfromformat.php
|
// See http://php.net/manual/en/datetime.createfromformat.php
|
||||||
// The character "|" in the format makes sure that the parts of a date
|
// The character "|" in the format makes sure that the parts of a date
|
||||||
// that are *not* specified in the format are reset to the corresponding
|
// that are *not* specified in the format are reset to the corresponding
|
||||||
@ -64,7 +79,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
|
|||||||
// where the time corresponds to the current server time.
|
// where the time corresponds to the current server time.
|
||||||
// With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
|
// With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
|
||||||
// which is at least deterministic and thus used here.
|
// which is at least deterministic and thus used here.
|
||||||
if (false === strpos($this->parseFormat, '|')) {
|
if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) {
|
||||||
$this->parseFormat .= '|';
|
$this->parseFormat .= '|';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,6 +140,70 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
|
|||||||
$outputTz = new \DateTimeZone($this->outputTimezone);
|
$outputTz = new \DateTimeZone($this->outputTimezone);
|
||||||
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
|
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
|
||||||
|
|
||||||
|
// On PHP versions < 5.3.8 we need to emulate the pipe operator
|
||||||
|
// and reset parts not given in the format to their equivalent
|
||||||
|
// of the UNIX base timestamp.
|
||||||
|
if (!$this->parseUsingPipe) {
|
||||||
|
list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s'));
|
||||||
|
|
||||||
|
// Check which of the date parts are present in the pattern
|
||||||
|
preg_match(
|
||||||
|
'/(' .
|
||||||
|
'(?<day>[djDl])|' .
|
||||||
|
'(?<month>[FMmn])|' .
|
||||||
|
'(?<year>[Yy])|' .
|
||||||
|
'(?<hour>[ghGH])|' .
|
||||||
|
'(?<minute>i)|' .
|
||||||
|
'(?<second>s)|' .
|
||||||
|
'(?<dayofyear>z)|' .
|
||||||
|
'(?<timestamp>U)|' .
|
||||||
|
'[^djDlFMmnYyghGHiszU]' .
|
||||||
|
')*/',
|
||||||
|
$this->parseFormat,
|
||||||
|
$matches
|
||||||
|
);
|
||||||
|
|
||||||
|
// preg_match() does not guarantee to set all indices, so
|
||||||
|
// set them unless given
|
||||||
|
$matches = array_merge(array(
|
||||||
|
'day' => false,
|
||||||
|
'month' => false,
|
||||||
|
'year' => false,
|
||||||
|
'hour' => false,
|
||||||
|
'minute' => false,
|
||||||
|
'second' => false,
|
||||||
|
'dayofyear' => false,
|
||||||
|
'timestamp' => false,
|
||||||
|
), $matches);
|
||||||
|
|
||||||
|
// Reset all parts that don't exist in the format to the
|
||||||
|
// corresponding part of the UNIX base timestamp
|
||||||
|
if (!$matches['timestamp']) {
|
||||||
|
if (!$matches['dayofyear']) {
|
||||||
|
if (!$matches['day']) {
|
||||||
|
$day = 1;
|
||||||
|
}
|
||||||
|
if (!$matches['month']) {
|
||||||
|
$month = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$matches['year']) {
|
||||||
|
$year = 1970;
|
||||||
|
}
|
||||||
|
if (!$matches['hour']) {
|
||||||
|
$hour = 0;
|
||||||
|
}
|
||||||
|
if (!$matches['minute']) {
|
||||||
|
$minute = 0;
|
||||||
|
}
|
||||||
|
if (!$matches['second']) {
|
||||||
|
$second = 0;
|
||||||
|
}
|
||||||
|
$dateTime->setDate($year, $month, $day);
|
||||||
|
$dateTime->setTime($hour, $minute, $second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$lastErrors = \DateTime::getLastErrors();
|
$lastErrors = \DateTime::getLastErrors();
|
||||||
|
|
||||||
if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
|
if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
|
||||||
|
@ -18,18 +18,43 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase
|
|||||||
public function dataProvider()
|
public function dataProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('Y-m-d H:i:s', '2010-02-03 04:05:06', '2010-02-03 04:05:06 UTC'),
|
array('Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'),
|
||||||
array('Y-m-d H:i:00', '2010-02-03 04:05:00', '2010-02-03 04:05:00 UTC'),
|
array('Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'),
|
||||||
array('Y-m-d H:i', '2010-02-03 04:05', '2010-02-03 04:05:00 UTC'),
|
array('Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'),
|
||||||
array('Y-m-d H', '2010-02-03 04', '2010-02-03 04:00:00 UTC'),
|
array('Y-m-d H', '2010-02-03 16', '2010-02-03 16:00:00 UTC'),
|
||||||
array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'),
|
array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'),
|
||||||
array('Y-m', '2010-02', '2010-02-01 00:00:00 UTC'),
|
array('Y-m', '2010-02', '2010-02-01 00:00:00 UTC'),
|
||||||
array('Y', '2010', '2010-01-01 00:00:00 UTC'),
|
array('Y', '2010', '2010-01-01 00:00:00 UTC'),
|
||||||
array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'),
|
array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'),
|
||||||
array('H:i:s', '04:05:06', '1970-01-01 04:05:06 UTC'),
|
array('H:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
|
||||||
array('H:i:00', '04:05:00', '1970-01-01 04:05:00 UTC'),
|
array('H:i:00', '16:05:00', '1970-01-01 16:05:00 UTC'),
|
||||||
array('H:i', '04:05', '1970-01-01 04:05:00 UTC'),
|
array('H:i', '16:05', '1970-01-01 16:05:00 UTC'),
|
||||||
array('H', '04', '1970-01-01 04:00:00 UTC'),
|
array('H', '16', '1970-01-01 16:00:00 UTC'),
|
||||||
|
|
||||||
|
// different day representations
|
||||||
|
array('Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'),
|
||||||
|
array('Y-z', '2010-33', '2010-02-03 00:00:00 UTC'),
|
||||||
|
array('z', '33', '1970-02-03 00:00:00 UTC'),
|
||||||
|
|
||||||
|
// not bijective
|
||||||
|
//array('Y-m-D', '2010-02-Wed', '2010-02-03 00:00:00 UTC'),
|
||||||
|
//array('Y-m-l', '2010-02-Wednesday', '2010-02-03 00:00:00 UTC'),
|
||||||
|
|
||||||
|
// different month representations
|
||||||
|
array('Y-n-d', '2010-2-03', '2010-02-03 00:00:00 UTC'),
|
||||||
|
array('Y-M-d', '2010-Feb-03', '2010-02-03 00:00:00 UTC'),
|
||||||
|
array('Y-F-d', '2010-February-03', '2010-02-03 00:00:00 UTC'),
|
||||||
|
|
||||||
|
// different year representations
|
||||||
|
array('y-m-d', '10-02-03', '2010-02-03 00:00:00 UTC'),
|
||||||
|
|
||||||
|
// different time representations
|
||||||
|
array('G:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
|
||||||
|
array('g:i:s a', '4:05:06 pm', '1970-01-01 16:05:06 UTC'),
|
||||||
|
array('h:i:s a', '04:05:06 pm', '1970-01-01 16:05:06 UTC'),
|
||||||
|
|
||||||
|
// seconds since unix
|
||||||
|
array('U', '1265213106', '2010-02-03 16:05:06 UTC'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +100,24 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider dataProvider
|
* @dataProvider dataProvider
|
||||||
*/
|
*/
|
||||||
public function testReverseTransform($format, $input, $output)
|
public function testReverseTransformBeforePhp538($format, $input, $output)
|
||||||
{
|
{
|
||||||
|
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, false);
|
||||||
|
|
||||||
|
$output = new \DateTime($output);
|
||||||
|
|
||||||
|
$this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataProvider
|
||||||
|
*/
|
||||||
|
public function testReverseTransformAsOfPhp538($format, $input, $output)
|
||||||
|
{
|
||||||
|
if (version_compare(phpversion(), '5.3.8', '<')) {
|
||||||
|
$this->markTestSkipped('Requires PHP 5.3.8 or newer');
|
||||||
|
}
|
||||||
|
|
||||||
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
|
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
|
||||||
|
|
||||||
$output = new \DateTime($output);
|
$output = new \DateTime($output);
|
||||||
@ -95,7 +136,7 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase
|
|||||||
{
|
{
|
||||||
$reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s');
|
$reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s');
|
||||||
|
|
||||||
$output = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
|
$output = new \DateTime('2010-02-03 16:05:06 Asia/Hong_Kong');
|
||||||
$input = $output->format('Y-m-d H:i:s');
|
$input = $output->format('Y-m-d H:i:s');
|
||||||
$output->setTimeZone(new \DateTimeZone('America/New_York'));
|
$output->setTimeZone(new \DateTimeZone('America/New_York'));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user