Permalink
Browse files

Properly implement interval + rounding for minutes.

  • Loading branch information...
1 parent 0f913b9 commit aeab312a880cd8472ef0ad84ea1e0ea535cf7fb9 @markstory markstory committed Jan 23, 2014
Showing with 186 additions and 24 deletions.
  1. +62 −17 src/View/Input/DateTime.php
  2. +124 −7 tests/TestCase/View/Input/DateTimeTest.php
@@ -99,7 +99,7 @@ public function render(array $data) {
'second' => [],
];
- $selected = $this->_deconstuctDate($data['val']);
+ $selected = $this->_deconstuctDate($data['val'], $data);
$templateOptions = [];
foreach ($this->_selects as $select) {
@@ -130,9 +130,10 @@ public function render(array $data) {
* Deconstructs the passed date value into all time units
*
* @param string|integer|array|DateTime $value
+ * @param array $options Options for conversion.
* @return array
*/
- protected function _deconstuctDate($value) {
+ protected function _deconstuctDate($value, $options) {
if (empty($value)) {
return [
'year' => '', 'month' => '', 'day' => '',
@@ -152,7 +153,12 @@ protected function _deconstuctDate($value) {
$date->setTime($value['hour'], $value['minute'], $value['second']);
}
} else {
- $date = $value;
+ $date = clone $value;
+ }
+
+ if (isset($options['minute']['interval'])) {
+ $change = $this->_adjustValue($date->format('i'), $options['minute']);
+ $date->modify($change > 0 ? "+$change minutes" : "$change minutes");
}
return [
@@ -166,6 +172,29 @@ protected function _deconstuctDate($value) {
}
/**
+ * Adjust $value based on rounding settings.
+ *
+ * @param int $value The value to adjust.
+ * @param array The options containing interval and possibly round.
+ * @return integer The amount to adjust $value by.
+ */
+ protected function _adjustValue($value, $options) {
+ $options += ['interval' => 1, 'round' => null];
+ $changeValue = $value * (1 / $options['interval']);
+ switch ($options['round']) {
+ case 'up':
+ $changeValue = ceil($changeValue);
+ break;
+ case 'down':
+ $changeValue = floor($changeValue);
+ break;
+ default:
+ $changeValue = round($changeValue);
+ }
+ return ($changeValue * $options['interval']) - $value;
+ }
+
+/**
* Generates a year select
*
* @param array $options
@@ -279,12 +308,21 @@ public function minuteSelect($options = []) {
$options += [
'name' => '',
'val' => null,
+ 'interval' => 1,
+ 'round' => 'up',
'leadingZeroKey' => true,
'leadingZeroValue' => true,
- 'options' => $this->_generateNumbers(1, 60)
];
+ if (empty($options['options'])) {
+ $options['options'] = $this->_generateNumbers(0, 59, $options);
+ }
- unset($options['leadingZeroKey'], $options['leadingZeroValue']);
+ unset(
+ $options['leadingZeroKey'],
+ $options['leadingZeroValue'],
+ $options['interval'],
+ $options['round']
+ );
return $this->_select->render($options);
}
@@ -343,30 +381,37 @@ protected function _getMonthNames($leadingZero = false) {
/**
* Generates a range of numbers
*
+ * ### Options
+ *
+ * - leadingZeroKey - Set to true to add a leading 0 to single digit keys.
+ * - leadingZeroValue - Set to true to add a leading 0 to single digit values.
+ * - interval - The interval to generate numbers for. Defaults to 1.
+ *
* @param integer $start Start of the range of numbers to generate
* @param integer $end End of the range of numbers to generate
* @param array $options
* @return array
*/
- protected function _generateNumbers($start = 1, $end = 31, $options = []) {
+ protected function _generateNumbers($start, $end, $options = []) {
$options += [
'leadingZeroKey' => true,
'leadingZeroValue' => true,
+ 'interval' => 1
];
$numbers = [];
- for ($i = $start; $i <= $end; $i++) {
- $key = $i;
- $value = $i;
- if ($i < 10) {
- if ($options['leadingZeroKey'] === true) {
- $key = '0' . $key;
- }
- if ($options['leadingZeroValue'] === true) {
- $value = '0' . $value;
- }
+ $i = $start;
+ while ($i <= $end) {
+ $key = (string)$i;
+ $value = (string)$i;
+ if ($options['leadingZeroKey'] === true) {
+ $key = sprintf('%02d', $key);
+ }
+ if ($options['leadingZeroValue'] === true) {
+ $value = sprintf('%02d', $value);
}
- $numbers[(string)$key] = (string)$value;
+ $numbers[$key] = $value;
+ $i += $options['interval'];
}
return $numbers;
}
@@ -491,7 +491,7 @@ public function testRenderMinuteWidget() {
]);
$this->assertContains('<select name="date[minute]" data-foo="test">', $result);
$this->assertContains(
- '<option value="01">01</option>',
+ '<option value="00">00</option>',
$result,
'contains 1'
);
@@ -506,22 +506,134 @@ public function testRenderMinuteWidget() {
'selected value present'
);
$this->assertContains(
- '<option value="60">60</option>',
+ '<option value="59">59</option>',
$result,
- 'contains 60'
+ 'contains 59'
);
- $this->assertNotContains('value="0"', $result, 'No zero value');
- $this->assertNotContains('value="61"', $result, 'No 61 value');
+ $this->assertNotContains('value="60"', $result, 'No 60 value');
}
+/**
+ * Test minutes with interval values.
+ *
+ * @return void
+ */
public function testRenderMinuteWidgetInterval() {
- $this->markTestIncomplete();
+ $now = new \DateTime('2010-09-09 13:23:00');
+ $result = $this->DateTime->render([
+ 'name' => 'date',
+ 'year' => false,
+ 'month' => false,
+ 'day' => false,
+ 'hour' => false,
+ 'minute' => [
+ 'interval' => 5
+ ],
+ 'second' => false,
+ 'val' => $now,
+ ]);
+ $this->assertContains('<select name="date[minute]">', $result);
+ $this->assertContains(
+ '<option value="00">00</option>',
+ $result,
+ 'contains 0'
+ );
+ $this->assertContains(
+ '<option value="05">05</option>',
+ $result,
+ 'contains 05'
+ );
+ $this->assertContains(
+ '<option value="25" selected="selected">25</option>',
+ $result,
+ 'selected value present'
+ );
+ $this->assertContains(
+ '<option value="55">55</option>',
+ $result,
+ 'contains 59'
+ );
+ $this->assertNotContains('value="2"', $result, 'No 2 value');
+ $this->assertNotContains('value="23"', $result, 'No 23 value');
+ $this->assertNotContains('value="58"', $result, 'No 58 value');
+ $this->assertNotContains('value="59"', $result, 'No 59 value');
+ $this->assertNotContains('value="60"', $result, 'No 60 value');
}
+/**
+ * Test rounding up and down.
+ *
+ * @return void
+ */
public function testRenderMinuteWidgetIntervalRounding() {
- $this->markTestIncomplete();
+ $now = new \DateTime('2010-09-09 13:22:00');
+ $data = [
+ 'name' => 'date',
+ 'year' => false,
+ 'month' => false,
+ 'day' => false,
+ 'hour' => false,
+ 'minute' => [
+ 'interval' => 5,
+ 'round' => 'up',
+ ],
+ 'second' => false,
+ 'val' => $now,
+ ];
+ $result = $this->DateTime->render($data);
+ $this->assertContains(
+ '<option value="25" selected="selected">25</option>',
+ $result,
+ 'selected value present'
+ );
+ $this->assertNotContains('value="23"', $result, 'No 23 value');
+
+ $data['minute']['round'] = 'down';
+ $result = $this->DateTime->render($data);
+ $this->assertContains(
+ '<option value="20" selected="selected">20</option>',
+ $result,
+ 'selected value present'
+ );
+ $this->assertNotContains('value="23"', $result, 'No 23 value');
+ }
+
+/**
+ * Test that minute interval rounding can effect hours and days.
+ *
+ * @return void
+ */
+ public function testMinuteIntervalHourRollover() {
+ $now = new \DateTime('2010-09-09 23:58:00');
+ $result = $this->DateTime->render([
+ 'name' => 'date',
+ 'year' => false,
+ 'month' => false,
+ 'minute' => [
+ 'interval' => 5,
+ 'round' => 'up',
+ ],
+ 'second' => false,
+ 'val' => $now,
+ ]);
+
+ $this->assertContains(
+ '<option value="00" selected="selected">00</option>',
+ $result,
+ 'selected minute present'
+ );
+ $this->assertContains(
+ '<option value="10" selected="selected">10</option>',
+ $result,
+ 'selected day present'
+ );
}
+/**
+ * Test render seconds basic.
+ *
+ * @return void
+ */
public function testRenderSecondsWidget() {
$now = new \DateTime('2010-09-09 13:00:25');
$result = $this->DateTime->render([
@@ -561,6 +673,11 @@ public function testRenderSecondsWidget() {
$this->assertNotContains('value="61"', $result, 'No 61 value');
}
+/**
+ * Test the merdian select.
+ *
+ * @return void
+ */
public function testRenderMeridianWidget() {
$this->markTestIncomplete();
}

0 comments on commit aeab312

Please sign in to comment.