diff --git a/application/Espo/Core/Formula/Functions/DatetimeGroup/AddIntervalType.php b/application/Espo/Core/Formula/Functions/DatetimeGroup/AddIntervalType.php index 04af6773df..cfa58b7f3b 100644 --- a/application/Espo/Core/Formula/Functions/DatetimeGroup/AddIntervalType.php +++ b/application/Espo/Core/Formula/Functions/DatetimeGroup/AddIntervalType.php @@ -29,7 +29,10 @@ namespace Espo\Core\Formula\Functions\DatetimeGroup; -use Espo\Core\Di; +use Espo\Core\{ + Di, + Utils\DateTime as DateTimeUtil, +}; use Espo\Core\Formula\{ Functions\BaseFunction, @@ -37,6 +40,7 @@ use Espo\Core\Formula\{ }; use DateTime; +use Exception; abstract class AddIntervalType extends BaseFunction implements Di\DateTimeAware { @@ -80,17 +84,22 @@ abstract class AddIntervalType extends BaseFunction implements Di\DateTimeAware try { $dateTime = new DateTime($dateTimeString); - } catch (\Exception $e) { + } + catch (Exception $e) { $this->log('bad date-time value passed', 'warning'); + return null; } - $dateTime->modify(($interval > 0 ? '+' : '') . strval($interval) . ' ' . $this->intervalTypeString); + $dateTime->modify( + ($interval > 0 ? '+' : '') . strval($interval) . ' ' . $this->intervalTypeString + ); if ($isTime) { - return $dateTime->format($this->dateTime->getInternalDateTimeFormat()); - } else { - return $dateTime->format($this->dateTime->getInternalDateFormat()); + return $dateTime->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); + } + else { + return $dateTime->format(DateTimeUtil::SYSTEM_DATE_FORMAT); } } } diff --git a/application/Espo/Core/Formula/Functions/DatetimeGroup/NowType.php b/application/Espo/Core/Formula/Functions/DatetimeGroup/NowType.php index a957abff71..938b2f1cc6 100644 --- a/application/Espo/Core/Formula/Functions/DatetimeGroup/NowType.php +++ b/application/Espo/Core/Formula/Functions/DatetimeGroup/NowType.php @@ -29,19 +29,17 @@ namespace Espo\Core\Formula\Functions\DatetimeGroup; -use Espo\Core\Di; +use Espo\Core\Utils\DateTime; use Espo\Core\Formula\{ Functions\BaseFunction, ArgumentList, }; -class NowType extends BaseFunction implements Di\DateTimeAware +class NowType extends BaseFunction { - use Di\DateTimeSetter; - public function process(ArgumentList $args) { - return $this->dateTime->getInternalNowString(); + return DateTime::getSystemNowString(); } } diff --git a/application/Espo/Core/Formula/Functions/DatetimeGroup/TodayType.php b/application/Espo/Core/Formula/Functions/DatetimeGroup/TodayType.php index beface7837..81528f4bb1 100644 --- a/application/Espo/Core/Formula/Functions/DatetimeGroup/TodayType.php +++ b/application/Espo/Core/Formula/Functions/DatetimeGroup/TodayType.php @@ -29,19 +29,17 @@ namespace Espo\Core\Formula\Functions\DatetimeGroup; -use Espo\Core\Di; +use Espo\Core\Utils\DateTime; use Espo\Core\Formula\{ Functions\BaseFunction, ArgumentList, }; -class TodayType extends BaseFunction implements Di\DateTimeAware +class TodayType extends BaseFunction { - use Di\DateTimeSetter; - public function process(ArgumentList $args) { - return $this->dateTime->getInternalTodayString(); + return DateTime::getSystemTodayString(); } } diff --git a/application/Espo/Core/Repositories/Event.php b/application/Espo/Core/Repositories/Event.php index 94c50b3e59..4da7c73498 100644 --- a/application/Espo/Core/Repositories/Event.php +++ b/application/Espo/Core/Repositories/Event.php @@ -31,7 +31,10 @@ namespace Espo\Core\Repositories; use Espo\ORM\Entity; -use Espo\Core\Di; +use Espo\Core\{ + Di, + Utils\DateTime as DateTimeUtil, +}; use DateTime; use DateTimeZone; @@ -159,7 +162,7 @@ class Event extends Database implements try { $dt = DateTime::createFromFormat( - $this->getDateTime()->getInternalDateTimeFormat(), + DateTimeUtil::SYSTEM_DATE_TIME_FORMAT, $string, $tz ); @@ -171,7 +174,7 @@ class Event extends Database implements return $dt ->setTimezone($utcTz) - ->format($this->getDateTime()->getInternalDateTimeFormat()); + ->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); } return null; diff --git a/application/Espo/Core/Utils/DateTime.php b/application/Espo/Core/Utils/DateTime.php index 2cefdaecf0..bcfe2fec28 100644 --- a/application/Espo/Core/Utils/DateTime.php +++ b/application/Espo/Core/Utils/DateTime.php @@ -45,37 +45,13 @@ class DateTime public const SYSTEM_DATE_FORMAT = 'Y-m-d'; - protected $dateFormat; + private $dateFormat; - protected $timeFormat; + private $timeFormat; - protected $timezone; + private $timezone; - protected $langauge; - - /** @deprecated */ - public static $systemDateTimeFormat = self::SYSTEM_DATE_TIME_FORMAT; - - /** @deprecated */ - public static $systemDateFormat = self::SYSTEM_DATE_FORMAT; - - protected $internalDateTimeFormat = self::SYSTEM_DATE_TIME_FORMAT; - - protected $internalDateFormat = self::SYSTEM_DATE_FORMAT; - - protected $dateFormats = [ - 'MM/DD/YYYY' => 'm/d/Y', - 'YYYY-MM-DD' => 'Y-m-d', - 'DD.MM.YYYY' => 'd.m.Y', - 'DD/MM/YYYY' => 'd/m/Y', - ]; - - protected $timeFormats = [ - 'HH:mm' => 'H:i', - 'hh:mm A' => 'h:i A', - 'hh:mm a' => 'h:ia', - 'hh:mmA' => 'h:iA', - ]; + private $language; public function __construct( ?string $dateFormat = 'YYYY-MM-DD', @@ -89,48 +65,67 @@ class DateTime $this->language = $language ?? 'en_US'; } + /** + * Get a default date format. + */ public function getDateFormat(): string { return $this->dateFormat; } + /** + * Get a default date-time format. + */ public function getDateTimeFormat(): string { return $this->dateFormat . ' ' . $this->timeFormat; } + /** + * @deprecated Use `SYSTEM_DATE_TIME_FORMAT constant`. + */ public function getInternalDateTimeFormat(): string { - return $this->internalDateTimeFormat; + return self::SYSTEM_DATE_TIME_FORMAT; } + /** + * @deprecated Use `SYSTEM_DATE_FORMAT constant`. + */ public function getInternalDateFormat(): string { - return $this->internalDateFormat; - } - - protected function getPhpDateFormat(): string - { - return $this->dateFormats[$this->dateFormat]; - } - - protected function getPhpDateTimeFormat(): string - { - return $this->dateFormats[$this->dateFormat] . ' ' . $this->timeFormats[$this->timeFormat]; + return self::SYSTEM_DATE_FORMAT; } + /** + * @deprecated Use `convertSystemDate`. + */ public function convertSystemDateToGlobal($string): ?string { return $this->convertSystemDate($string); } + /** + * @deprecated Use `convertSystemDateTime`. + */ public function convertSystemDateTimeToGlobal(string $string): ?string { return $this->convertSystemDateTime($string); } - public function convertSystemDate(string $string, ?string $format = null, ?string $language = null): ?string - { + /** + * Convert a system date. + * + * @param string $string A system date. + * @param string|null $format A target format. If not specified then the default format will be used. + * @param string|null $language A language. If not specified then the default language will be used. + */ + public function convertSystemDate( + string $string, + ?string $format = null, + ?string $language = null + ): ?string { + $dateTime = DateTimeStd::createFromFormat('Y-m-d', $string); if ($dateTime) { @@ -144,6 +139,14 @@ class DateTime return null; } + /** + * Convert a system date-time. + * + * @param string $string A system date-time. + * @param string $timezone A target timezone. If not specified then the default timezone will be used. + * @param string|null $format A target format. If not specified then the default format will be used. + * @param string|null $language A language. If not specified then the default language will be used. + */ public function convertSystemDateTime( string $string, ?string $timezone = null, @@ -182,16 +185,6 @@ class DateTime $this->timezone = new DateTimeZone($timezone); } - public function getInternalNowString(): string - { - return date($this->getInternalDateTimeFormat()); - } - - public function getInternalTodayString(): string - { - return date($this->getInternalDateFormat()); - } - public function getTodayString(?string $timezone = null, ?string $format = null): string { if ($timezone) { @@ -204,34 +197,26 @@ class DateTime $dateTime->setTimezone($tz); - $format = $format ?? $this->getDateFormat(); - $carbon = Carbon::instance($dateTime); $carbon->locale($this->language); - return $carbon->isoFormat($format); + return $carbon->isoFormat($format ?? $this->getDateFormat()); } public function getNowString(?string $timezone = null, ?string $format = null): string { - if ($timezone) { - $tz = new DateTimeZone($timezone); - } else { - $tz = $this->timezone; - } + $tz = $timezone ? new DateTimeZone($timezone) : $this->timezone; $dateTime = new DateTimeStd(); $dateTime->setTimezone($tz); - $format = $format ?? $this->getDateTimeFormat(); - $carbon = Carbon::instance($dateTime); $carbon->locale($this->language); - return $carbon->isoFormat($format); + return $carbon->isoFormat($format ?? $this->getDateTimeFormat()); } public static function isAfterThreshold($value, string $period): bool @@ -266,4 +251,30 @@ class DateTime { return date(self::SYSTEM_DATE_TIME_FORMAT); } + + public static function getSystemTodayString(): string + { + return date(self::SYSTEM_DATE_FORMAT); + } + + public static function convertFormatToSystem(string $format): string + { + $map = [ + 'MM' => 'm', + 'DD' => 'd', + 'YYYY' => 'Y', + 'HH' => 'H', + 'mm' => 'i', + 'hh' => 'h', + 'A' => 'A', + 'a' => 'a', + 'ss' => 's', + ]; + + return str_replace( + array_keys($map), + array_values($map), + $format + ); + } } diff --git a/application/Espo/Resources/metadata/app/dateTime.json b/application/Espo/Resources/metadata/app/dateTime.json new file mode 100644 index 0000000000..92e64e8a16 --- /dev/null +++ b/application/Espo/Resources/metadata/app/dateTime.json @@ -0,0 +1,16 @@ +{ + "dateFormatList": [ + "DD.MM.YYYY", + "MM/DD/YYYY", + "DD/MM/YYYY", + "YYYY-MM-DD", + "DD. MM. YYYY" + ], + "timeFormatList": [ + "HH:mm", + "hh:mma", + "hh:mmA", + "hh:mm A", + "hh:mm a" + ] +} diff --git a/application/Espo/Resources/metadata/clientDefs/Import.json b/application/Espo/Resources/metadata/clientDefs/Import.json index 7e9018c152..561cb29bbd 100644 --- a/application/Espo/Resources/metadata/clientDefs/Import.json +++ b/application/Espo/Resources/metadata/clientDefs/Import.json @@ -39,5 +39,28 @@ ] }, "searchPanelDisabled": true, - "iconClass": "fas fa-file-import" + "iconClass": "fas fa-file-import", + "dateFormatList": [ + "YYYY-MM-DD", + "DD-MM-YYYY", + "MM-DD-YYYY", + "MM/DD/YYYY", + "DD/MM/YYYY", + "DD.MM.YYYY", + "MM.DD.YYYY", + "YYYY.MM.DD", + "DD. MM. YYYY" + ], + "timeFormatList": [ + "HH:mm:ss", + "HH:mm", + "hh:mm a", + "hh:mma", + "hh:mm A", + "hh:mmA", + "hh:mm:ss a", + "hh:mm:ssa", + "hh:mm:ss A", + "hh:mm:ssA" + ] } diff --git a/application/Espo/Resources/metadata/entityDefs/Portal.json b/application/Espo/Resources/metadata/entityDefs/Portal.json index a5f5adc467..cf5d11a8e5 100644 --- a/application/Espo/Resources/metadata/entityDefs/Portal.json +++ b/application/Espo/Resources/metadata/entityDefs/Portal.json @@ -62,19 +62,17 @@ }, "dateFormat": { "type": "enum", - "options": ["MM/DD/YYYY", "YYYY-MM-DD", "DD.MM.YYYY", "DD/MM/YYYY"], "default": "", "view": "views/preferences/fields/date-format" }, "timeFormat": { "type": "enum", - "options": ["HH:mm", "hh:mma", "hh:mmA", "hh:mm A", "hh:mm a"], "default": "", "view": "views/preferences/fields/time-format" }, "weekStart": { "type": "enumInt", - "options": [0, 1], + "options": [0, 1, 2, 3, 4, 5, 6], "default": -1, "view": "views/preferences/fields/week-start" }, diff --git a/application/Espo/Resources/metadata/entityDefs/Preferences.json b/application/Espo/Resources/metadata/entityDefs/Preferences.json index b489af56f1..35fb07c1da 100644 --- a/application/Espo/Resources/metadata/entityDefs/Preferences.json +++ b/application/Espo/Resources/metadata/entityDefs/Preferences.json @@ -7,13 +7,11 @@ }, "dateFormat": { "type": "enum", - "options": ["MM/DD/YYYY", "YYYY-MM-DD", "DD.MM.YYYY", "DD/MM/YYYY"], "default": "", "view": "views/preferences/fields/date-format" }, "timeFormat": { "type": "enum", - "options": ["HH:mm", "hh:mma", "hh:mmA", "hh:mm A", "hh:mm a"], "default": "", "view": "views/preferences/fields/time-format" }, diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index 824c7d38fc..a9967ca25a 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -28,13 +28,13 @@ }, "dateFormat": { "type": "enum", - "options": ["DD.MM.YYYY", "MM/DD/YYYY", "DD/MM/YYYY", "YYYY-MM-DD"], - "default": "DD.MM.YYYY" + "default": "DD.MM.YYYY", + "view": "views/settings/fields/date-format" }, "timeFormat": { "type": "enum", - "options": ["HH:mm", "hh:mma", "hh:mmA", "hh:mm A", "hh:mm a"], - "default": "HH:mm" + "default": "HH:mm", + "view": "views/settings/fields/time-format" }, "weekStart": { "type": "enumInt", diff --git a/application/Espo/Tools/Export/Formats/Xlsx.php b/application/Espo/Tools/Export/Formats/Xlsx.php index ecbeb236f6..06e9350115 100644 --- a/application/Espo/Tools/Export/Formats/Xlsx.php +++ b/application/Espo/Tools/Export/Formats/Xlsx.php @@ -465,7 +465,7 @@ class Xlsx $dt = new DateTime($value); $dt->setTimezone(new DateTimeZone($timeZone)); - $value = $dt->format($this->dateTime->getInternalDateTimeFormat()); + $value = $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT); } catch (Exception $e) { $value = ''; diff --git a/application/Espo/Tools/Import/Import.php b/application/Espo/Tools/Import/Import.php index 0fb903cc2c..2184bc8751 100644 --- a/application/Espo/Tools/Import/Import.php +++ b/application/Espo/Tools/Import/Import.php @@ -38,6 +38,7 @@ use Espo\Core\{ Utils\Config, FileStorage\Manager as FileStorageManager, Record\ServiceContainer as RecordServiceContainer, + Utils\DateTime as DateTimeUtil, }; use Espo\{ @@ -52,26 +53,6 @@ use Exception; class Import { - protected $dateFormatsMap = [ - 'YYYY-MM-DD' => 'Y-m-d', - 'DD-MM-YYYY' => 'd-m-Y', - 'MM-DD-YYYY' => 'm-d-Y', - 'MM/DD/YYYY' => 'm/d/Y', - 'DD/MM/YYYY' => 'd/m/Y', - 'DD.MM.YYYY' => 'd.m.Y', - 'MM.DD.YYYY' => 'm.d.Y', - 'YYYY.MM.DD' => 'Y.m.d', - ]; - - protected $timeFormatsMap = [ - 'HH:mm' => 'H:i', - 'HH:mm:ss' => 'H:i:s', - 'hh:mm a' => 'h:i a', - 'hh:mma' => 'h:ia', - 'hh:mm A' => 'h:iA', - 'hh:mmA' => 'h:iA', - ]; - protected $attributeList = []; protected $params = []; @@ -844,17 +825,13 @@ class Import $dateFormat = 'Y-m-d'; if (!empty($params['dateFormat'])) { - if (!empty($this->dateFormatsMap[$params['dateFormat']])) { - $dateFormat = $this->dateFormatsMap[$params['dateFormat']]; - } + $dateFormat = DateTimeUtil::convertFormatToSystem($params['dateFormat']); } $timeFormat = 'H:i'; if (!empty($params['timeFormat'])) { - if (!empty($this->timeFormatsMap[$params['timeFormat']])) { - $timeFormat = $this->timeFormatsMap[$params['timeFormat']]; - } + $timeFormat = DateTimeUtil::convertFormatToSystem($params['timeFormat']); } $type = $entity->getAttributeType($attribute); @@ -871,10 +848,12 @@ class Import case Entity::DATETIME: $timezone = new DateTimeZone(isset($params['timezone']) ? $params['timezone'] : 'UTC'); + $dt = DateTime::createFromFormat($dateFormat . ' ' . $timeFormat, $value, $timezone); if ($dt) { - $dt->setTimezone(new \DateTimeZone('UTC')); + $dt->setTimezone(new DateTimeZone('UTC')); + return $dt->format('Y-m-d H:i:s'); } diff --git a/client/src/views/import/step1.js b/client/src/views/import/step1.js index 9954dfa2e1..7e7efd5a21 100644 --- a/client/src/views/import/step1.js +++ b/client/src/views/import/step1.js @@ -151,36 +151,19 @@ define('views/import/step1', ['view', 'model'], function (Dep, Model) { personNameFormatList.push('l f m'); } - var dateFormatDataList = [ - {key: "YYYY-MM-DD", label: '2020-12-27'}, - {key: "DD-MM-YYYY", label: '27-12-2020'}, - {key: "MM-DD-YYYY", label: '12-27-2020'}, - {key: "MM/DD/YYYY", label: '12/27/2020'}, - {key: "DD/MM/YYYY", label: '27/12/2020'}, - {key: "DD.MM.YYYY", label: '27.12.2020'}, - {key: "MM.DD.YYYY", label: '12.27.2020'}, - {key: "YYYY.MM.DD", label: '2020.12.27'}, - ]; - var timeFormatDataList = [ - {key: "HH:mm:ss", label: '23:00:00'}, - {key: "HH:mm", label: '23:00'}, - {key: "hh:mm a", label: '11:00 pm'}, - {key: "hh:mma", label: '11:00pm'}, - {key: "hh:mm A", label: '11:00 PM'}, - {key: "hh:mmA", label: '11:00PM'}, - {key: "hh:mm:ss a", label: '11:00:00 pm'}, - {key: "hh:mm:ssa", label: '11:00:00pm'}, - {key: "hh:mm:ss A", label: '11:00:00 PM'}, - {key: "hh:mm:ssA", label: '11:00:00PM'}, - ]; + var dateFormatDataList = this.getDateFormatDataList(); + + var timeFormatDataList = this.getTimeFormatDataList(); var dateFormatList = []; + dateFormatDataList.forEach(function (item) { dateFormatList.push(item.key); }, this); var timeFormatList = []; var timeFormatOptions = {}; + timeFormatDataList.forEach(function (item) { timeFormatList.push(item.key); timeFormatOptions[item.key] = item.label; @@ -494,7 +477,8 @@ define('views/import/step1', ['view', 'model'], function (Dep, Model) { "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" + // Quoted fields. - "(?:"+strQualifier+"([^"+strQualifier+"]*(?:"+strQualifier+""+strQualifier+"[^"+strQualifier+"]*)*)"+strQualifier+"|" + + "(?:"+strQualifier+"([^"+strQualifier+"]*(?:"+strQualifier+""+strQualifier+ + "[^"+strQualifier+"]*)*)"+strQualifier+"|" + // Standard fields. "([^"+strQualifier+"\\" + strDelimiter + "\\r\\n]*))" @@ -576,5 +560,55 @@ define('views/import/step1', ['view', 'model'], function (Dep, Model) { this.$el.find('.field[data-name="'+name+'"]').parent().removeClass('hidden-cell'); }, + convertFormatToLabel: function (format) { + var formatItemLabelMap = { + 'YYYY': '2021', + 'DD': '27', + 'MM': '12', + 'HH': '23', + 'mm': '00', + 'hh': '11', + 'ss': '00', + 'a': 'pm', + 'A': 'PM', + }; + + var label = format; + + for (let item in formatItemLabelMap) { + var value = formatItemLabelMap[item]; + + label = label.replaceAll(item, value); + } + + return label; + }, + + getDateFormatDataList: function () { + var dateFormatList = this.getMetadata().get(['clientDefs', 'Import', 'dateFormatList']) || []; + + return dateFormatList.map( + function (item) { + return { + key: item, + label: this.convertFormatToLabel(item), + }; + }.bind(this) + ); + }, + + getTimeFormatDataList: function () { + var timeFormatList = this.getMetadata().get(['clientDefs', 'Import', 'timeFormatList']) || []; + + return timeFormatList.map( + function (item) { + return { + key: item, + label: this.convertFormatToLabel(item), + }; + }.bind(this) + ); + }, + }); }); diff --git a/client/src/views/preferences/fields/date-format.js b/client/src/views/preferences/fields/date-format.js index 0323148a92..91dff48cde 100644 --- a/client/src/views/preferences/fields/date-format.js +++ b/client/src/views/preferences/fields/date-format.js @@ -26,16 +26,21 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -Espo.define('views/preferences/fields/date-format', 'views/fields/enum', function (Dep) { +define('views/preferences/fields/date-format', 'views/fields/enum', function (Dep) { return Dep.extend({ setupOptions: function () { - this.params.options = Espo.Utils.clone(this.params.options); + this.params.options = Espo.Utils.clone( + this.getMetadata().get(['app', 'dateTime', 'dateFormatList']) || [] + ); + this.params.options.unshift(''); this.translatedOptions = this.translatedOptions || {}; - this.translatedOptions[''] = this.translate('Default') + ' (' + this.getConfig().get('dateFormat') +')'; + + this.translatedOptions[''] = this.translate('Default') + + ' (' + this.getConfig().get('dateFormat') +')'; }, }); diff --git a/client/src/views/preferences/fields/time-format.js b/client/src/views/preferences/fields/time-format.js index 60de5ada3d..f5c8b88fd1 100644 --- a/client/src/views/preferences/fields/time-format.js +++ b/client/src/views/preferences/fields/time-format.js @@ -26,16 +26,21 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -Espo.define('views/preferences/fields/time-format', 'views/fields/enum', function (Dep) { +define('views/preferences/fields/time-format', 'views/fields/enum', function (Dep) { return Dep.extend({ setupOptions: function () { - this.params.options = Espo.Utils.clone(this.params.options); + this.params.options = Espo.Utils.clone( + this.getMetadata().get(['app', 'dateTime', 'timeFormatList']) || [] + ); + this.params.options.unshift(''); this.translatedOptions = this.translatedOptions || {}; - this.translatedOptions[''] = this.translate('Default') + ' (' + this.getConfig().get('timeFormat') +')'; + + this.translatedOptions[''] = this.translate('Default') + + ' (' + this.getConfig().get('timeFormat') +')'; }, }); diff --git a/client/src/views/settings/fields/date-format.js b/client/src/views/settings/fields/date-format.js new file mode 100644 index 0000000000..524d8ad8db --- /dev/null +++ b/client/src/views/settings/fields/date-format.js @@ -0,0 +1,38 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('views/settings/fields/date-format', 'views/fields/enum', function (Dep) { + + return Dep.extend({ + + setupOptions: function () { + this.params.options = this.getMetadata().get(['app', 'dateTime', 'dateFormatList']) || []; + }, + + }); +}); diff --git a/client/src/views/settings/fields/time-format.js b/client/src/views/settings/fields/time-format.js new file mode 100644 index 0000000000..36cb9c2b2d --- /dev/null +++ b/client/src/views/settings/fields/time-format.js @@ -0,0 +1,38 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('views/settings/fields/time-format', 'views/fields/enum', function (Dep) { + + return Dep.extend({ + + setupOptions: function () { + this.params.options = this.getMetadata().get(['app', 'dateTime', 'timeFormatList']) || []; + }, + + }); +}); diff --git a/install/core/actions/step4.php b/install/core/actions/step4.php index a0ae677aab..77f419edb0 100644 --- a/install/core/actions/step4.php +++ b/install/core/actions/step4.php @@ -28,33 +28,38 @@ ************************************************************************/ $config = $installer->getConfig(); +$metadata = $installer->getMetadata(); -$fields = array( - 'dateFormat' =>array ( +$fields = [ + 'dateFormat' => [ 'default' => $config->get('dateFormat', ''), - ), - 'timeFormat' => array( + 'options' => $metadata->get(['app', 'dateTime', 'dateFormatList']) ?? [], + ], + 'timeFormat' => [ 'default'=> $config->get('timeFormat', ''), - ), - 'timeZone' => array( + 'options' => $metadata->get(['app', 'dateTime', 'timeFormatList']) ?? [], + ], + 'timeZone' => [ 'default'=> $config->get('timeZone', 'UTC'), - ), - 'weekStart' => array( + ], + 'weekStart' => [ 'default'=> $config->get('weekStart', 0), - ), - 'defaultCurrency' => array( + ], + 'defaultCurrency' => [ 'default' => $config->get('defaultCurrency', 'USD'), - ), - 'thousandSeparator' => array( + ], + 'thousandSeparator' => [ 'default' => $config->get('thousandSeparator', ','), - ), - 'decimalMark' =>array( + ], + 'decimalMark' => [ 'default' => $config->get('decimalMark', '.'), - ), - 'language' => array( - 'default'=> (!empty($_SESSION['install']['user-lang'])) ? $_SESSION['install']['user-lang'] : $config->get('language', 'en_US'), - ), -); + ], + 'language' => [ + 'default' => (!empty($_SESSION['install']['user-lang'])) ? + $_SESSION['install']['user-lang'] : + $config->get('language', 'en_US'), + ], +]; foreach ($fields as $fieldName => $field) { if (isset($_SESSION['install'][$fieldName])) { diff --git a/install/core/tpl/step4.tpl b/install/core/tpl/step4.tpl index 7b43fc05f5..63c75a17e8 100644 --- a/install/core/tpl/step4.tpl +++ b/install/core/tpl/step4.tpl @@ -10,7 +10,7 @@
- {foreach from=$defaultSettings['timeFormat'].options item=lbl key=val} + {foreach from=$fields['timeFormat'].options item=lbl key=val} {if $val == $fields['timeFormat'].value} {else} diff --git a/tests/unit/Espo/Core/Utils/DateTimeTest.php b/tests/unit/Espo/Core/Utils/DateTimeTest.php new file mode 100644 index 0000000000..525b5f0524 --- /dev/null +++ b/tests/unit/Espo/Core/Utils/DateTimeTest.php @@ -0,0 +1,61 @@ + 'Y-m-d', + 'DD-MM-YYYY' => 'd-m-Y', + 'MM-DD-YYYY' => 'm-d-Y', + 'MM/DD/YYYY' => 'm/d/Y', + 'DD/MM/YYYY' => 'd/m/Y', + 'DD.MM.YYYY' => 'd.m.Y', + 'DD. MM. YYYY' => 'd. m. Y', + 'MM.DD.YYYY' => 'm.d.Y', + 'YYYY.MM.DD' => 'Y.m.d', + 'HH:mm' => 'H:i', + 'HH:mm:ss' => 'H:i:s', + 'hh:mm a' => 'h:i a', + 'hh:mma' => 'h:ia', + 'hh:mm A' => 'h:i A', + 'hh:mmA' => 'h:iA', + 'DD. MM. YYYY HH:mm' => 'd. m. Y H:i', + ]; + + foreach ($map as $from => $to) { + $this->assertEquals($to, DateTime::convertFormatToSystem($from)); + } + } +}