Skip to content

Commit

Permalink
Properly implement interval + rounding for minutes.
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Jan 26, 2014
1 parent 0f913b9 commit aeab312
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 24 deletions.
79 changes: 62 additions & 17 deletions src/View/Input/DateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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' => '',
Expand All @@ -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 [
Expand All @@ -165,6 +171,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
*
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}
Expand Down
131 changes: 124 additions & 7 deletions tests/TestCase/View/Input/DateTimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'
);
Expand All @@ -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([
Expand Down Expand Up @@ -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();
}
Expand Down

0 comments on commit aeab312

Please sign in to comment.