From feb03f5443329252eb5d975ed925b7ab4f1b5970 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Fri, 28 Jun 2013 16:45:33 +1200 Subject: [PATCH] BUG Fixed issue where time value was being parsed incorrectly in some locales --- forms/TimeField.php | 35 +++++++++++++++++++++++++++++++---- tests/forms/TimeFieldTest.php | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/forms/TimeField.php b/forms/TimeField.php index 14fc9709e..173f34d79 100644 --- a/forms/TimeField.php +++ b/forms/TimeField.php @@ -76,6 +76,33 @@ class TimeField extends TextField { public function Type() { return 'time text'; } + + /** + * Parses a time into a Zend_Date object + * + * @param string $value Raw value + * @param string $format Format string to check against + * @param string $locale Optional locale to parse against + * @param boolean $exactMatch Flag indicating that the date must be in this + * exact format, and is unchanged after being parsed and written out + * + * @return Zend_Date Returns the Zend_Date, or null if not in the specified format + */ + protected function parseTime($value, $format, $locale = null, $exactMatch = false) { + // Check if the date is in the correct format + if(!Zend_Date::isDate($value, $format)) return null; + + // Parse the value + $valueObject = new Zend_Date($value, $format, $locale); + + // For exact matches, ensure the value preserves formatting after conversion + if($exactMatch && ($value !== $valueObject->get($format))) { + return null; + } else { + return $valueObject; + } + } + /** * Sets the internal value to ISO date format. @@ -83,6 +110,7 @@ class TimeField extends TextField { * @param String|Array $val */ public function setValue($val) { + // Fuzzy matching through strtotime() to support a wider range of times, // e.g. 11am. This means that validate() might not fire. // Note: Time formats are assumed to be less ambiguous than dates across locales. @@ -99,13 +127,12 @@ class TimeField extends TextField { $this->valueObj = null; } // load ISO time from database (usually through Form->loadDataForm()) - else if(Zend_Date::isDate($val, $this->getConfig('datavalueformat'))) { - $this->valueObj = new Zend_Date($val, $this->getConfig('datavalueformat')); + // Requires exact format to prevent false positives from locale specific times + else if($this->valueObj = $this->parseTime($val, $this->getConfig('datavalueformat'), null, true)) { $this->value = $this->valueObj->get($this->getConfig('timeformat')); } // Set in current locale (as string) - else if(Zend_Date::isDate($val, $this->getConfig('timeformat'), $this->locale)) { - $this->valueObj = new Zend_Date($val, $this->getConfig('timeformat'), $this->locale); + else if($this->valueObj = $this->parseTime($val, $this->getConfig('timeformat'), $this->locale)) { $this->value = $this->valueObj->get($this->getConfig('timeformat')); } // Fallback: Set incorrect value so validate() can pick it up diff --git a/tests/forms/TimeFieldTest.php b/tests/forms/TimeFieldTest.php index b8050a6d7..6bd2b1861 100644 --- a/tests/forms/TimeFieldTest.php +++ b/tests/forms/TimeFieldTest.php @@ -100,4 +100,36 @@ class TimeFieldTest extends SapphireTest { $field->setValue(''); $this->assertEquals($field->dataValue(), ''); } + + /** + * Test that AM/PM is preserved correctly in various situations + */ + public function testPreserveAMPM() { + + // Test with timeformat that includes hour + + // Check pm + $f = new TimeField('Time', 'Time'); + $f->setConfig('timeformat', 'h:mm:ss a'); + $f->setValue('3:59 pm'); + $this->assertEquals($f->dataValue(), '15:59:00'); + + // Check am + $f = new TimeField('Time', 'Time'); + $f->setConfig('timeformat', 'h:mm:ss a'); + $f->setValue('3:59 am'); + $this->assertEquals($f->dataValue(), '03:59:00'); + + // Check with ISO date/time + $f = new TimeField('Time', 'Time'); + $f->setConfig('timeformat', 'h:mm:ss a'); + $f->setValue('15:59:00'); + $this->assertEquals($f->dataValue(), '15:59:00'); + + // ISO am + $f = new TimeField('Time', 'Time'); + $f->setConfig('timeformat', 'h:mm:ss a'); + $f->setValue('03:59:00'); + $this->assertEquals($f->dataValue(), '03:59:00'); + } }