diff --git a/ajax/editActivity.php b/ajax/editActivity.php index 57b01f7a5..4fc434654 100755 --- a/ajax/editActivity.php +++ b/ajax/editActivity.php @@ -65,9 +65,7 @@ $activityHour = trim(urldecode($_POST['hour'])); $activityMinute = trim(urldecode($_POST['minute'])); -$dateFormatFlag = $_SESSION['CATS']->isDateDMY() - ? DATE_FORMAT_DDMMYY - : DATE_FORMAT_MMDDYY; +$dateFormatFlag = $_SESSION['CATS']->getDateFormat(); if (!DateUtility::validate('-', $activityDate, $dateFormatFlag)) { diff --git a/installwizard.php b/installwizard.php index 7466d0ab5..05a282556 100755 --- a/installwizard.php +++ b/installwizard.php @@ -375,6 +375,7 @@
- - + + + diff --git a/modules/reports/ReportsUI.php b/modules/reports/ReportsUI.php index 6fdc296e5..ade0e12b6 100755 --- a/modules/reports/ReportsUI.php +++ b/modules/reports/ReportsUI.php @@ -397,7 +397,7 @@ private function customizeJobOrderReport() $reportParameters['periodLine'] = sprintf( '%s - %s', strtok($data['dateCreated'], ' '), - DateUtility::getAdjustedDate('m-d-y') + DateUtility::getAdjustedDate(DateUtility::getPhpDateFormat()) ); $reportParameters['dataSet1'] = $data['pipeline']; diff --git a/modules/settings/Localization.tpl b/modules/settings/Localization.tpl index d3f62685d..4cb51f5f9 100755 --- a/modules/settings/Localization.tpl +++ b/modules/settings/Localization.tpl @@ -34,8 +34,9 @@
diff --git a/modules/settings/NewInstallWizard.tpl b/modules/settings/NewInstallWizard.tpl index 9ad5f5f38..30a0af11f 100755 --- a/modules/settings/NewInstallWizard.tpl +++ b/modules/settings/NewInstallWizard.tpl @@ -83,6 +83,7 @@ diff --git a/modules/settings/SettingsUI.php b/modules/settings/SettingsUI.php index 272bb98f8..8d002c6ec 100755 --- a/modules/settings/SettingsUI.php +++ b/modules/settings/SettingsUI.php @@ -2414,7 +2414,7 @@ private function administration() } $this->_template->assign('timeZone', $_SESSION['CATS']->getTimeZone()); - $this->_template->assign('isDateDMY', $_SESSION['CATS']->isDateDMY()); + $this->_template->assign('dateFormat', $_SESSION['CATS']->getDateFormat()); $this->_template->assign('isTimeFormat24', $_SESSION['CATS']->isTimeFormat24()); // Default phone country calling code for the localization settings page. @@ -2564,20 +2564,12 @@ private function onAdministration() } //FIXME: Validation (escaped at lib level anyway) $timeZone = $_POST['timeZone']; - $dateFormat = $_POST['dateFormat']; - if ($dateFormat == 'mdy') - { - $isDMY = false; - } - else - { - $isDMY = true; - } + $dateFormat = DateUtility::getDateFormatFromFormValue($_POST['dateFormat']); $isTimeFormat24 = (isset($_POST['timeFormat']) && $_POST['timeFormat'] === '24'); $site = new Site(); - $site->setLocalization($timeZone, $isDMY, $isTimeFormat24); + $site->setLocalization($timeZone, $dateFormat, $isTimeFormat24); // Default phone country calling code (E.164) for the site. if (isset($_POST['defaultPhoneCountryCodeDigits'])) @@ -2620,23 +2612,15 @@ private function onAspLocalization() // FIXME: Input validation! $timeZone = $_POST['timeZone']; - $dateFormat = $_POST['dateFormat']; - if ($dateFormat == 'mdy') - { - $isDMY = false; - } - else - { - $isDMY = true; - } + $dateFormat = DateUtility::getDateFormatFromFormValue($_POST['dateFormat']); $isTimeFormat24 = (isset($_POST['timeFormat']) && $_POST['timeFormat'] === '24'); $site = new Site(); - $site->setLocalization($timeZone, $isDMY, $isTimeFormat24); + $site->setLocalization($timeZone, $dateFormat, $isTimeFormat24); /* Reload the new data for the session. */ - $_SESSION['CATS']->setTimeDateLocalization($timeZone, $isDMY, $isTimeFormat24); + $_SESSION['CATS']->setTimeDateLocalization($timeZone, $dateFormat, $isTimeFormat24); $this->_template->assign('inputType', 'conclusion'); $this->_template->assign('title', 'Localization Settings Saved!'); @@ -3042,20 +3026,12 @@ private function wizard_localization() } $timeZone = $_GET['timeZone']; - $dateFormat = $_GET['dateFormat']; - if ($dateFormat == 'mdy') - { - $isDMY = false; - } - else - { - $isDMY = true; - } + $dateFormat = DateUtility::getDateFormatFromFormValue($_GET['dateFormat']); $isTimeFormat24 = (isset($_GET['timeFormat']) && $_GET['timeFormat'] === '24'); $site = new Site(); - $site->setLocalization($timeZone, $isDMY, $isTimeFormat24); + $site->setLocalization($timeZone, $dateFormat, $isTimeFormat24); $site->setLocalizationConfigured(); echo 'Ok'; diff --git a/modules/wizard/WizardUI.php b/modules/wizard/WizardUI.php index e4f787296..6f3409ee1 100755 --- a/modules/wizard/WizardUI.php +++ b/modules/wizard/WizardUI.php @@ -44,7 +44,7 @@ public function __construct() '); $this->addPage('Localization', './modules/wizard/WizardIntroLocalization.tpl', ' $this->_template->assign(\'timeZone\', $_SESSION[\'CATS\']->getTimeZone()); - $this->_template->assign(\'isDateDMY\', $_SESSION[\'CATS\']->isDateDMY()); + $this->_template->assign(\'dateFormat\', $_SESSION[\'CATS\']->getDateFormat()); $this->_template->assign(\'isTimeFormat24\', $_SESSION[\'CATS\']->isTimeFormat24()); '); diff --git a/src/OpenCATS/Tests/IntegrationTests/ChartDataTest.php b/src/OpenCATS/Tests/IntegrationTests/ChartDataTest.php index 31015bb2e..8a5662c3f 100644 --- a/src/OpenCATS/Tests/IntegrationTests/ChartDataTest.php +++ b/src/OpenCATS/Tests/IntegrationTests/ChartDataTest.php @@ -11,6 +11,7 @@ public function testExistingQueriesAndChartDataAcrossRangesAndFilters() public function getUserID() { return 1; } public function isLoggedIn() { return false; } public function isDateDMY() { return true; } + public function getDateFormat() { return DATE_FORMAT_DDMMYY; } public function isTimeFormat24() { return true; } public function getTimeZoneOffset() { return 0; } }; diff --git a/src/OpenCATS/Tests/IntegrationTests/EntityDeleteCleanupTest.php b/src/OpenCATS/Tests/IntegrationTests/EntityDeleteCleanupTest.php index a612e3b4e..441a2dd98 100644 --- a/src/OpenCATS/Tests/IntegrationTests/EntityDeleteCleanupTest.php +++ b/src/OpenCATS/Tests/IntegrationTests/EntityDeleteCleanupTest.php @@ -43,6 +43,11 @@ public function isDateDMY() return false; } + public function getDateFormat() + { + return DATE_FORMAT_MMDDYY; + } + public function isTimeFormat24() { return false; diff --git a/src/OpenCATS/Tests/UnitTests/DateUtilityTest.php b/src/OpenCATS/Tests/UnitTests/DateUtilityTest.php index aaf6bf8b6..c9d0656a1 100644 --- a/src/OpenCATS/Tests/UnitTests/DateUtilityTest.php +++ b/src/OpenCATS/Tests/UnitTests/DateUtilityTest.php @@ -242,6 +242,47 @@ function testGetDateTimeFormat() $this->assertSame('d-m-Y H:i', DateUtility::getDateTimeFormat('d-m-Y', true)); } + /* Tests for date format flag mapping. */ + function testDateFormatMapping() + { + $formats = array( + /* site value, form value, flag, JS format, PHP format */ + array(0, 'mdy', DATE_FORMAT_MMDDYY, 'MM-DD-YY', 'm-d-y'), + array(1, 'dmy', DATE_FORMAT_DDMMYY, 'DD-MM-YY', 'd-m-y'), + array(2, 'ymd', DATE_FORMAT_YYYYMMDD, 'YYYY-MM-DD', 'Y-m-d'), + ); + + foreach ($formats as $value) + { + $this->assertSame($value[2], DateUtility::getDateFormatFromSiteValue($value[0])); + $this->assertSame($value[0], DateUtility::getSiteValueFromDateFormat($value[2])); + $this->assertSame($value[2], DateUtility::getDateFormatFromFormValue($value[1])); + $this->assertSame($value[3], DateUtility::getJsDateFormat($value[2])); + $this->assertSame($value[4], DateUtility::getPhpDateFormat($value[2])); + } + + /* Unknown values fall back to M-D-Y. */ + $this->assertSame(DATE_FORMAT_MMDDYY, DateUtility::getDateFormatFromSiteValue(null)); + $this->assertSame(DATE_FORMAT_MMDDYY, DateUtility::getDateFormatFromFormValue('invalid')); + + /* Legacy boolean D-M-Y values are accepted. */ + $this->assertSame(DATE_FORMAT_DDMMYY, DateUtility::normalizeDateFormat(true)); + $this->assertSame(DATE_FORMAT_MMDDYY, DateUtility::normalizeDateFormat(false)); + $this->assertSame(DATE_FORMAT_YYYYMMDD, DateUtility::normalizeDateFormat(DATE_FORMAT_YYYYMMDD)); + } + + /* Tests for formatStoredDate(). */ + function testFormatStoredDate() + { + $this->assertSame('12-31-05', DateUtility::formatStoredDate('12-31-05', DATE_FORMAT_MMDDYY)); + $this->assertSame('31-12-05', DateUtility::formatStoredDate('12-31-05', DATE_FORMAT_DDMMYY)); + $this->assertSame('2005-12-31', DateUtility::formatStoredDate('12-31-05', DATE_FORMAT_YYYYMMDD)); + + /* Empty and invalid values are returned unchanged. */ + $this->assertSame('', DateUtility::formatStoredDate('', DATE_FORMAT_YYYYMMDD)); + $this->assertSame('invalid', DateUtility::formatStoredDate('invalid', DATE_FORMAT_DDMMYY)); + } + /* Tests for normalizeActivityTime(). */ function testNormalizeActivityTime() { diff --git a/src/OpenCATS/Tests/UnitTests/SessionDateFormatTest.php b/src/OpenCATS/Tests/UnitTests/SessionDateFormatTest.php new file mode 100644 index 000000000..a8e157bb8 --- /dev/null +++ b/src/OpenCATS/Tests/UnitTests/SessionDateFormatTest.php @@ -0,0 +1,43 @@ +setTimeDateLocalization(0, true); + $this->assertSame(DATE_FORMAT_DDMMYY, $session->getDateFormat()); + $this->assertTrue($session->isDateDMY()); + + $session->setTimeDateLocalization(0, false); + $this->assertSame(DATE_FORMAT_MMDDYY, $session->getDateFormat()); + + $session->setTimeDateLocalization(0, DATE_FORMAT_YYYYMMDD); + $this->assertSame(DATE_FORMAT_YYYYMMDD, $session->getDateFormat()); + } + + /* A session serialized before the upgrade stores a boolean _dateDMY; + * _dateFormat then keeps its M-D-Y default until __wakeup() runs. */ + function testLegacySessionKeepsDateFormat() + { + foreach (array(1 => DATE_FORMAT_DDMMYY, 0 => DATE_FORMAT_MMDDYY) as $isDMY => $expected) + { + $serialized = str_replace( + '_dateDMY";N;', + '_dateDMY";b:' . $isDMY . ';', + serialize(new CATSSession()) + ); + $this->assertStringContainsString('_dateDMY";b:', $serialized); + $session = unserialize($serialized); + + $this->assertSame($expected, $session->getDateFormat()); + $this->assertStringNotContainsString('_dateDMY";b:', serialize($session)); + } + } +} +?> diff --git a/test/features/activities.feature b/test/features/activities.feature index 55b455937..c7791d193 100644 --- a/test/features/activities.feature +++ b/test/features/activities.feature @@ -152,9 +152,10 @@ Feature: Activities Then I should see "Activities combined fixture" Examples: - | format | clock | date | hour | - | MDY | 12 | 06-12-31 | 9 | - | DMY | 24 | 12-06-31 | 21 | + | format | clock | date | hour | + | MDY | 12 | 06-12-31 | 9 | + | DMY | 24 | 12-06-31 | 21 | + | YMD | 24 | 2031-06-12 | 21 | @javascript @activities_form Scenario: Schedule an all-day private event without logging an activity diff --git a/test/features/bootstrap/ActivitiesSteps.php b/test/features/bootstrap/ActivitiesSteps.php index df347cd36..9e0276e59 100644 --- a/test/features/bootstrap/ActivitiesSteps.php +++ b/test/features/bootstrap/ActivitiesSteps.php @@ -43,7 +43,7 @@ public function activitiesFormats($dateFormat, $timeFormat) { $db = DatabaseConnection::getInstance(); $this->activitiesFormats = $db->getAllAssoc('SELECT site_id, date_format_ddmmyy, time_format_24 FROM site'); - $db->query('UPDATE site SET date_format_ddmmyy = ' . ($dateFormat === 'DMY' ? 1 : 0) + $db->query('UPDATE site SET date_format_ddmmyy = ' . array('MDY' => 0, 'DMY' => 1, 'YMD' => 2)[$dateFormat] . ', time_format_24 = ' . ($timeFormat === '24' ? 1 : 0)); } diff --git a/test/features/bootstrap/FeatureContext.php b/test/features/bootstrap/FeatureContext.php index ae4a82898..655734b29 100644 --- a/test/features/bootstrap/FeatureContext.php +++ b/test/features/bootstrap/FeatureContext.php @@ -151,7 +151,7 @@ public function calendarUsesFormats($dateFormat, $timeFormat) $this->calendarSiteFormats = $db->getAllAssoc( 'SELECT site_id, date_format_ddmmyy, time_format_24 FROM site' ); - $db->query('UPDATE site SET date_format_ddmmyy = ' . ($dateFormat === 'DMY' ? 1 : 0) + $db->query('UPDATE site SET date_format_ddmmyy = ' . array('MDY' => 0, 'DMY' => 1, 'YMD' => 2)[$dateFormat] . ', time_format_24 = ' . ($timeFormat === '24' ? 1 : 0)); } diff --git a/test/features/calendar.feature b/test/features/calendar.feature index 2176023d2..55b8cb8f6 100644 --- a/test/features/calendar.feature +++ b/test/features/calendar.feature @@ -22,7 +22,7 @@ Feature: Calendar And I select "Meeting" from "type" And I select "Jun" from "dateAdd_Month_ID" And I select "12" from "dateAdd_Day_ID" - And I fill in "dateAdd_Year_ID" with "30" + And I fill in "dateAdd_Year_ID" with "" And I select "09" from "hour" And I select "15" from "minute" And I fill in "description" with "Calendar workflow details" @@ -53,7 +53,7 @@ Feature: Calendar Then the "#calendarMonth" element should contain "Calendar workflow event" When I click on the element "#calendarMonth .calendarEntry" And I press "Edit Event" - Then the "dateEdit_Year_ID" field should contain "30" + Then the "dateEdit_Year_ID" field should contain "" And the "minuteEdit" field should contain "15" And Calendar panel "sendEmailTDEdit" should be "visible" When I uncheck "reminderToggleEdit" @@ -79,9 +79,10 @@ Feature: Calendar Then I should see "My Upcoming Events / Calls" Examples: - | dateFormat | timeFormat | - | MDY | 12 | - | DMY | 24 | + | dateFormat | timeFormat | year | + | MDY | 12 | 30 | + | DMY | 24 | 30 | + | YMD | 24 | 2030 | Scenario Outline: Navigate beyond cached months and select a date to create an event Given Calendar AJAX is ""