Date formatting per workspace member settings (#6408)
Implement date formatting per workspace member settings We'll need another round to maybe initialize all workspaces on the default settings. For now the default behavior is to take system settings if nothing is found in DB. --------- Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
@ -0,0 +1,6 @@
|
||||
export enum DateFormat {
|
||||
SYSTEM = 'SYSTEM',
|
||||
MONTH_FIRST = 'MMM d, yyyy', // US
|
||||
DAY_FIRST = 'd MMM, yyyy', // UK
|
||||
YEAR_FIRST = 'yyyy MMM d',
|
||||
}
|
||||
@ -0,0 +1,600 @@
|
||||
/**
|
||||
* Standard IANA time zones.
|
||||
* @see https://www.iana.org/time-zones
|
||||
*/
|
||||
export const IANA_TIME_ZONES = [
|
||||
'Africa/Abidjan',
|
||||
'Africa/Accra',
|
||||
'Africa/Addis_Ababa',
|
||||
'Africa/Algiers',
|
||||
'Africa/Asmara',
|
||||
'Africa/Asmera',
|
||||
'Africa/Bamako',
|
||||
'Africa/Bangui',
|
||||
'Africa/Banjul',
|
||||
'Africa/Bissau',
|
||||
'Africa/Blantyre',
|
||||
'Africa/Brazzaville',
|
||||
'Africa/Bujumbura',
|
||||
'Africa/Cairo',
|
||||
'Africa/Casablanca',
|
||||
'Africa/Ceuta',
|
||||
'Africa/Conakry',
|
||||
'Africa/Dakar',
|
||||
'Africa/Dar_es_Salaam',
|
||||
'Africa/Djibouti',
|
||||
'Africa/Douala',
|
||||
'Africa/El_Aaiun',
|
||||
'Africa/Freetown',
|
||||
'Africa/Gaborone',
|
||||
'Africa/Harare',
|
||||
'Africa/Johannesburg',
|
||||
'Africa/Juba',
|
||||
'Africa/Kampala',
|
||||
'Africa/Khartoum',
|
||||
'Africa/Kigali',
|
||||
'Africa/Kinshasa',
|
||||
'Africa/Lagos',
|
||||
'Africa/Libreville',
|
||||
'Africa/Lome',
|
||||
'Africa/Luanda',
|
||||
'Africa/Lubumbashi',
|
||||
'Africa/Lusaka',
|
||||
'Africa/Malabo',
|
||||
'Africa/Maputo',
|
||||
'Africa/Maseru',
|
||||
'Africa/Mbabane',
|
||||
'Africa/Mogadishu',
|
||||
'Africa/Monrovia',
|
||||
'Africa/Nairobi',
|
||||
'Africa/Ndjamena',
|
||||
'Africa/Niamey',
|
||||
'Africa/Nouakchott',
|
||||
'Africa/Ouagadougou',
|
||||
'Africa/Porto-Novo',
|
||||
'Africa/Sao_Tome',
|
||||
'Africa/Timbuktu',
|
||||
'Africa/Tripoli',
|
||||
'Africa/Tunis',
|
||||
'Africa/Windhoek',
|
||||
'America/Adak',
|
||||
'America/Anchorage',
|
||||
'America/Anguilla',
|
||||
'America/Antigua',
|
||||
'America/Araguaina',
|
||||
'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Catamarca',
|
||||
'America/Argentina/ComodRivadavia',
|
||||
'America/Argentina/Cordoba',
|
||||
'America/Argentina/Jujuy',
|
||||
'America/Argentina/La_Rioja',
|
||||
'America/Argentina/Mendoza',
|
||||
'America/Argentina/Rio_Gallegos',
|
||||
'America/Argentina/Salta',
|
||||
'America/Argentina/San_Juan',
|
||||
'America/Argentina/San_Luis',
|
||||
'America/Argentina/Tucuman',
|
||||
'America/Argentina/Ushuaia',
|
||||
'America/Aruba',
|
||||
'America/Asuncion',
|
||||
'America/Atikokan',
|
||||
'America/Atka',
|
||||
'America/Bahia',
|
||||
'America/Bahia_Banderas',
|
||||
'America/Barbados',
|
||||
'America/Belem',
|
||||
'America/Belize',
|
||||
'America/Blanc-Sablon',
|
||||
'America/Boa_Vista',
|
||||
'America/Bogota',
|
||||
'America/Boise',
|
||||
'America/Buenos_Aires',
|
||||
'America/Cambridge_Bay',
|
||||
'America/Campo_Grande',
|
||||
'America/Cancun',
|
||||
'America/Caracas',
|
||||
'America/Catamarca',
|
||||
'America/Cayenne',
|
||||
'America/Cayman',
|
||||
'America/Chicago',
|
||||
'America/Chihuahua',
|
||||
'America/Coral_Harbour',
|
||||
'America/Cordoba',
|
||||
'America/Costa_Rica',
|
||||
'America/Creston',
|
||||
'America/Cuiaba',
|
||||
'America/Curacao',
|
||||
'America/Danmarkshavn',
|
||||
'America/Dawson',
|
||||
'America/Dawson_Creek',
|
||||
'America/Denver',
|
||||
'America/Detroit',
|
||||
'America/Dominica',
|
||||
'America/Edmonton',
|
||||
'America/Eirunepe',
|
||||
'America/El_Salvador',
|
||||
'America/Ensenada',
|
||||
'America/Fort_Nelson',
|
||||
'America/Fort_Wayne',
|
||||
'America/Fortaleza',
|
||||
'America/Glace_Bay',
|
||||
'America/Godthab',
|
||||
'America/Goose_Bay',
|
||||
'America/Grand_Turk',
|
||||
'America/Grenada',
|
||||
'America/Guadeloupe',
|
||||
'America/Guatemala',
|
||||
'America/Guayaquil',
|
||||
'America/Guyana',
|
||||
'America/Halifax',
|
||||
'America/Havana',
|
||||
'America/Hermosillo',
|
||||
'America/Indiana/Indianapolis',
|
||||
'America/Indiana/Knox',
|
||||
'America/Indiana/Marengo',
|
||||
'America/Indiana/Petersburg',
|
||||
'America/Indiana/Tell_City',
|
||||
'America/Indiana/Vevay',
|
||||
'America/Indiana/Vincennes',
|
||||
'America/Indiana/Winamac',
|
||||
'America/Indianapolis',
|
||||
'America/Inuvik',
|
||||
'America/Iqaluit',
|
||||
'America/Jamaica',
|
||||
'America/Jujuy',
|
||||
'America/Juneau',
|
||||
'America/Kentucky/Louisville',
|
||||
'America/Kentucky/Monticello',
|
||||
'America/Knox_IN',
|
||||
'America/Kralendijk',
|
||||
'America/La_Paz',
|
||||
'America/Lima',
|
||||
'America/Los_Angeles',
|
||||
'America/Louisville',
|
||||
'America/Lower_Princes',
|
||||
'America/Maceio',
|
||||
'America/Managua',
|
||||
'America/Manaus',
|
||||
'America/Marigot',
|
||||
'America/Martinique',
|
||||
'America/Matamoros',
|
||||
'America/Mazatlan',
|
||||
'America/Mendoza',
|
||||
'America/Menominee',
|
||||
'America/Merida',
|
||||
'America/Metlakatla',
|
||||
'America/Mexico_City',
|
||||
'America/Miquelon',
|
||||
'America/Moncton',
|
||||
'America/Monterrey',
|
||||
'America/Montevideo',
|
||||
'America/Montreal',
|
||||
'America/Montserrat',
|
||||
'America/Nassau',
|
||||
'America/New_York',
|
||||
'America/Nipigon',
|
||||
'America/Nome',
|
||||
'America/Noronha',
|
||||
'America/North_Dakota/Beulah',
|
||||
'America/North_Dakota/Center',
|
||||
'America/North_Dakota/New_Salem',
|
||||
'America/Nuuk',
|
||||
'America/Ojinaga',
|
||||
'America/Panama',
|
||||
'America/Pangnirtung',
|
||||
'America/Paramaribo',
|
||||
'America/Phoenix',
|
||||
'America/Port_of_Spain',
|
||||
'America/Port-au-Prince',
|
||||
'America/Porto_Acre',
|
||||
'America/Porto_Velho',
|
||||
'America/Puerto_Rico',
|
||||
'America/Punta_Arenas',
|
||||
'America/Rainy_River',
|
||||
'America/Rankin_Inlet',
|
||||
'America/Recife',
|
||||
'America/Regina',
|
||||
'America/Resolute',
|
||||
'America/Rio_Branco',
|
||||
'America/Rosario',
|
||||
'America/Santa_Isabel',
|
||||
'America/Santarem',
|
||||
'America/Santiago',
|
||||
'America/Santo_Domingo',
|
||||
'America/Sao_Paulo',
|
||||
'America/Scoresbysund',
|
||||
'America/Shiprock',
|
||||
'America/Sitka',
|
||||
'America/St_Barthelemy',
|
||||
'America/St_Johns',
|
||||
'America/St_Kitts',
|
||||
'America/St_Lucia',
|
||||
'America/St_Thomas',
|
||||
'America/St_Vincent',
|
||||
'America/Swift_Current',
|
||||
'America/Tegucigalpa',
|
||||
'America/Thule',
|
||||
'America/Thunder_Bay',
|
||||
'America/Tijuana',
|
||||
'America/Toronto',
|
||||
'America/Tortola',
|
||||
'America/Vancouver',
|
||||
'America/Virgin',
|
||||
'America/Whitehorse',
|
||||
'America/Winnipeg',
|
||||
'America/Yakutat',
|
||||
'America/Yellowknife',
|
||||
'Antarctica/Casey',
|
||||
'Antarctica/Davis',
|
||||
'Antarctica/DumontDUrville',
|
||||
'Antarctica/Macquarie',
|
||||
'Antarctica/Mawson',
|
||||
'Antarctica/McMurdo',
|
||||
'Antarctica/Palmer',
|
||||
'Antarctica/Rothera',
|
||||
'Antarctica/South_Pole',
|
||||
'Antarctica/Syowa',
|
||||
'Antarctica/Troll',
|
||||
'Antarctica/Vostok',
|
||||
'Arctic/Longyearbyen',
|
||||
'Asia/Aden',
|
||||
'Asia/Almaty',
|
||||
'Asia/Amman',
|
||||
'Asia/Anadyr',
|
||||
'Asia/Aqtau',
|
||||
'Asia/Aqtobe',
|
||||
'Asia/Ashgabat',
|
||||
'Asia/Ashkhabad',
|
||||
'Asia/Atyrau',
|
||||
'Asia/Baghdad',
|
||||
'Asia/Bahrain',
|
||||
'Asia/Baku',
|
||||
'Asia/Bangkok',
|
||||
'Asia/Barnaul',
|
||||
'Asia/Beirut',
|
||||
'Asia/Bishkek',
|
||||
'Asia/Brunei',
|
||||
'Asia/Calcutta',
|
||||
'Asia/Chita',
|
||||
'Asia/Choibalsan',
|
||||
'Asia/Chongqing',
|
||||
'Asia/Chungking',
|
||||
'Asia/Colombo',
|
||||
'Asia/Dacca',
|
||||
'Asia/Damascus',
|
||||
'Asia/Dhaka',
|
||||
'Asia/Dili',
|
||||
'Asia/Dubai',
|
||||
'Asia/Dushanbe',
|
||||
'Asia/Famagusta',
|
||||
'Asia/Gaza',
|
||||
'Asia/Harbin',
|
||||
'Asia/Hebron',
|
||||
'Asia/Ho_Chi_Minh',
|
||||
'Asia/Hong_Kong',
|
||||
'Asia/Hovd',
|
||||
'Asia/Irkutsk',
|
||||
'Asia/Istanbul',
|
||||
'Asia/Jakarta',
|
||||
'Asia/Jayapura',
|
||||
'Asia/Jerusalem',
|
||||
'Asia/Kabul',
|
||||
'Asia/Kamchatka',
|
||||
'Asia/Karachi',
|
||||
'Asia/Kashgar',
|
||||
'Asia/Kathmandu',
|
||||
'Asia/Katmandu',
|
||||
'Asia/Khandyga',
|
||||
'Asia/Kolkata',
|
||||
'Asia/Krasnoyarsk',
|
||||
'Asia/Kuala_Lumpur',
|
||||
'Asia/Kuching',
|
||||
'Asia/Kuwait',
|
||||
'Asia/Macao',
|
||||
'Asia/Macau',
|
||||
'Asia/Magadan',
|
||||
'Asia/Makassar',
|
||||
'Asia/Manila',
|
||||
'Asia/Muscat',
|
||||
'Asia/Nicosia',
|
||||
'Asia/Novokuznetsk',
|
||||
'Asia/Novosibirsk',
|
||||
'Asia/Omsk',
|
||||
'Asia/Oral',
|
||||
'Asia/Phnom_Penh',
|
||||
'Asia/Pontianak',
|
||||
'Asia/Pyongyang',
|
||||
'Asia/Qatar',
|
||||
'Asia/Qostanay',
|
||||
'Asia/Qyzylorda',
|
||||
'Asia/Rangoon',
|
||||
'Asia/Riyadh',
|
||||
'Asia/Saigon',
|
||||
'Asia/Sakhalin',
|
||||
'Asia/Samarkand',
|
||||
'Asia/Seoul',
|
||||
'Asia/Shanghai',
|
||||
'Asia/Singapore',
|
||||
'Asia/Srednekolymsk',
|
||||
'Asia/Taipei',
|
||||
'Asia/Tashkent',
|
||||
'Asia/Tbilisi',
|
||||
'Asia/Tehran',
|
||||
'Asia/Tel_Aviv',
|
||||
'Asia/Thimbu',
|
||||
'Asia/Thimphu',
|
||||
'Asia/Tokyo',
|
||||
'Asia/Tomsk',
|
||||
'Asia/Ujung_Pandang',
|
||||
'Asia/Ulaanbaatar',
|
||||
'Asia/Ulan_Bator',
|
||||
'Asia/Urumqi',
|
||||
'Asia/Ust-Nera',
|
||||
'Asia/Vientiane',
|
||||
'Asia/Vladivostok',
|
||||
'Asia/Yakutsk',
|
||||
'Asia/Yangon',
|
||||
'Asia/Yekaterinburg',
|
||||
'Asia/Yerevan',
|
||||
'Atlantic/Azores',
|
||||
'Atlantic/Bermuda',
|
||||
'Atlantic/Canary',
|
||||
'Atlantic/Cape_Verde',
|
||||
'Atlantic/Faeroe',
|
||||
'Atlantic/Faroe',
|
||||
'Atlantic/Jan_Mayen',
|
||||
'Atlantic/Madeira',
|
||||
'Atlantic/Reykjavik',
|
||||
'Atlantic/South_Georgia',
|
||||
'Atlantic/St_Helena',
|
||||
'Atlantic/Stanley',
|
||||
'Australia/ACT',
|
||||
'Australia/Adelaide',
|
||||
'Australia/Brisbane',
|
||||
'Australia/Broken_Hill',
|
||||
'Australia/Canberra',
|
||||
'Australia/Currie',
|
||||
'Australia/Darwin',
|
||||
'Australia/Eucla',
|
||||
'Australia/Hobart',
|
||||
'Australia/LHI',
|
||||
'Australia/Lindeman',
|
||||
'Australia/Lord_Howe',
|
||||
'Australia/Melbourne',
|
||||
'Australia/North',
|
||||
'Australia/NSW',
|
||||
'Australia/Perth',
|
||||
'Australia/Queensland',
|
||||
'Australia/South',
|
||||
'Australia/Sydney',
|
||||
'Australia/Tasmania',
|
||||
'Australia/Victoria',
|
||||
'Australia/West',
|
||||
'Australia/Yancowinna',
|
||||
'Brazil/Acre',
|
||||
'Brazil/DeNoronha',
|
||||
'Brazil/East',
|
||||
'Brazil/West',
|
||||
'Canada/Atlantic',
|
||||
'Canada/Central',
|
||||
'Canada/Eastern',
|
||||
'Canada/Mountain',
|
||||
'Canada/Newfoundland',
|
||||
'Canada/Pacific',
|
||||
'Canada/Saskatchewan',
|
||||
'Canada/Yukon',
|
||||
'CET',
|
||||
'Chile/Continental',
|
||||
'Chile/EasterIsland',
|
||||
'CST6CDT',
|
||||
'Cuba',
|
||||
'EET',
|
||||
'Egypt',
|
||||
'Eire',
|
||||
'EST',
|
||||
'EST5EDT',
|
||||
'Etc/GMT',
|
||||
'Etc/GMT-0',
|
||||
'Etc/GMT-1',
|
||||
'Etc/GMT-10',
|
||||
'Etc/GMT-11',
|
||||
'Etc/GMT-12',
|
||||
'Etc/GMT-13',
|
||||
'Etc/GMT-14',
|
||||
'Etc/GMT-2',
|
||||
'Etc/GMT-3',
|
||||
'Etc/GMT-4',
|
||||
'Etc/GMT-5',
|
||||
'Etc/GMT-6',
|
||||
'Etc/GMT-7',
|
||||
'Etc/GMT-8',
|
||||
'Etc/GMT-9',
|
||||
'Etc/GMT+0',
|
||||
'Etc/GMT+1',
|
||||
'Etc/GMT+10',
|
||||
'Etc/GMT+11',
|
||||
'Etc/GMT+12',
|
||||
'Etc/GMT+2',
|
||||
'Etc/GMT+3',
|
||||
'Etc/GMT+4',
|
||||
'Etc/GMT+5',
|
||||
'Etc/GMT+6',
|
||||
'Etc/GMT+7',
|
||||
'Etc/GMT+8',
|
||||
'Etc/GMT+9',
|
||||
'Etc/GMT0',
|
||||
'Etc/Greenwich',
|
||||
'Etc/UCT',
|
||||
'Etc/Universal',
|
||||
'Etc/UTC',
|
||||
'Etc/Zulu',
|
||||
'Europe/Amsterdam',
|
||||
'Europe/Andorra',
|
||||
'Europe/Astrakhan',
|
||||
'Europe/Athens',
|
||||
'Europe/Belfast',
|
||||
'Europe/Belgrade',
|
||||
'Europe/Berlin',
|
||||
'Europe/Bratislava',
|
||||
'Europe/Brussels',
|
||||
'Europe/Bucharest',
|
||||
'Europe/Budapest',
|
||||
'Europe/Busingen',
|
||||
'Europe/Chisinau',
|
||||
'Europe/Copenhagen',
|
||||
'Europe/Dublin',
|
||||
'Europe/Gibraltar',
|
||||
'Europe/Guernsey',
|
||||
'Europe/Helsinki',
|
||||
'Europe/Isle_of_Man',
|
||||
'Europe/Istanbul',
|
||||
'Europe/Jersey',
|
||||
'Europe/Kaliningrad',
|
||||
'Europe/Kiev',
|
||||
'Europe/Kirov',
|
||||
'Europe/Lisbon',
|
||||
'Europe/Ljubljana',
|
||||
'Europe/London',
|
||||
'Europe/Luxembourg',
|
||||
'Europe/Madrid',
|
||||
'Europe/Malta',
|
||||
'Europe/Mariehamn',
|
||||
'Europe/Minsk',
|
||||
'Europe/Monaco',
|
||||
'Europe/Moscow',
|
||||
'Europe/Nicosia',
|
||||
'Europe/Oslo',
|
||||
'Europe/Paris',
|
||||
'Europe/Podgorica',
|
||||
'Europe/Prague',
|
||||
'Europe/Riga',
|
||||
'Europe/Rome',
|
||||
'Europe/Samara',
|
||||
'Europe/San_Marino',
|
||||
'Europe/Sarajevo',
|
||||
'Europe/Saratov',
|
||||
'Europe/Simferopol',
|
||||
'Europe/Skopje',
|
||||
'Europe/Sofia',
|
||||
'Europe/Stockholm',
|
||||
'Europe/Tallinn',
|
||||
'Europe/Tirane',
|
||||
'Europe/Tiraspol',
|
||||
'Europe/Ulyanovsk',
|
||||
'Europe/Uzhgorod',
|
||||
'Europe/Vaduz',
|
||||
'Europe/Vatican',
|
||||
'Europe/Vienna',
|
||||
'Europe/Vilnius',
|
||||
'Europe/Volgograd',
|
||||
'Europe/Warsaw',
|
||||
'Europe/Zagreb',
|
||||
'Europe/Zaporozhye',
|
||||
'Europe/Zurich',
|
||||
'GB',
|
||||
'GB-Eire',
|
||||
'GMT',
|
||||
'GMT-0',
|
||||
'GMT+0',
|
||||
'GMT0',
|
||||
'Greenwich',
|
||||
'Hongkong',
|
||||
'HST',
|
||||
'Iceland',
|
||||
'Indian/Antananarivo',
|
||||
'Indian/Chagos',
|
||||
'Indian/Christmas',
|
||||
'Indian/Cocos',
|
||||
'Indian/Comoro',
|
||||
'Indian/Kerguelen',
|
||||
'Indian/Mahe',
|
||||
'Indian/Maldives',
|
||||
'Indian/Mauritius',
|
||||
'Indian/Mayotte',
|
||||
'Indian/Reunion',
|
||||
'Iran',
|
||||
'Israel',
|
||||
'Jamaica',
|
||||
'Japan',
|
||||
'Kwajalein',
|
||||
'Libya',
|
||||
'MET',
|
||||
'Mexico/BajaNorte',
|
||||
'Mexico/BajaSur',
|
||||
'Mexico/General',
|
||||
'MST',
|
||||
'MST7MDT',
|
||||
'Navajo',
|
||||
'NZ',
|
||||
'NZ-CHAT',
|
||||
'Pacific/Apia',
|
||||
'Pacific/Auckland',
|
||||
'Pacific/Bougainville',
|
||||
'Pacific/Chatham',
|
||||
'Pacific/Chuuk',
|
||||
'Pacific/Easter',
|
||||
'Pacific/Efate',
|
||||
'Pacific/Enderbury',
|
||||
'Pacific/Fakaofo',
|
||||
'Pacific/Fiji',
|
||||
'Pacific/Funafuti',
|
||||
'Pacific/Galapagos',
|
||||
'Pacific/Gambier',
|
||||
'Pacific/Guadalcanal',
|
||||
'Pacific/Guam',
|
||||
'Pacific/Honolulu',
|
||||
'Pacific/Johnston',
|
||||
'Pacific/Kanton',
|
||||
'Pacific/Kiritimati',
|
||||
'Pacific/Kosrae',
|
||||
'Pacific/Kwajalein',
|
||||
'Pacific/Majuro',
|
||||
'Pacific/Marquesas',
|
||||
'Pacific/Midway',
|
||||
'Pacific/Nauru',
|
||||
'Pacific/Niue',
|
||||
'Pacific/Norfolk',
|
||||
'Pacific/Noumea',
|
||||
'Pacific/Pago_Pago',
|
||||
'Pacific/Palau',
|
||||
'Pacific/Pitcairn',
|
||||
'Pacific/Pohnpei',
|
||||
'Pacific/Ponape',
|
||||
'Pacific/Port_Moresby',
|
||||
'Pacific/Rarotonga',
|
||||
'Pacific/Saipan',
|
||||
'Pacific/Samoa',
|
||||
'Pacific/Tahiti',
|
||||
'Pacific/Tarawa',
|
||||
'Pacific/Tongatapu',
|
||||
'Pacific/Truk',
|
||||
'Pacific/Wake',
|
||||
'Pacific/Wallis',
|
||||
'Pacific/Yap',
|
||||
'Poland',
|
||||
'Portugal',
|
||||
'PRC',
|
||||
'PST8PDT',
|
||||
'ROC',
|
||||
'ROK',
|
||||
'Singapore',
|
||||
'Turkey',
|
||||
'UCT',
|
||||
'Universal',
|
||||
'US/Alaska',
|
||||
'US/Aleutian',
|
||||
'US/Arizona',
|
||||
'US/Central',
|
||||
'US/East-Indiana',
|
||||
'US/Eastern',
|
||||
'US/Hawaii',
|
||||
'US/Indiana-Starke',
|
||||
'US/Michigan',
|
||||
'US/Mountain',
|
||||
'US/Pacific',
|
||||
'US/Samoa',
|
||||
'UTC',
|
||||
'W-SU',
|
||||
'WET',
|
||||
'Zulu',
|
||||
];
|
||||
@ -0,0 +1,5 @@
|
||||
export enum TimeFormat {
|
||||
SYSTEM = 'SYSTEM',
|
||||
HOUR_24 = 'HH:mm',
|
||||
HOUR_12 = 'h:mm aa',
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { detectTimeZone } from '@/localization/utils/detectTimeZone';
|
||||
import { createState } from 'twenty-ui';
|
||||
|
||||
export const dateTimeFormatState = createState<{
|
||||
timeZone: string;
|
||||
dateFormat: DateFormat;
|
||||
timeFormat: TimeFormat;
|
||||
}>({
|
||||
key: 'dateTimeFormatState',
|
||||
defaultValue: {
|
||||
timeZone: detectTimeZone(),
|
||||
dateFormat: DateFormat.MONTH_FIRST,
|
||||
timeFormat: TimeFormat['HOUR_24'],
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,69 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { detectDateFormat } from '@/localization/utils/detectDateFormat';
|
||||
|
||||
describe('detectDateFormat', () => {
|
||||
it('should return DateFormat.MONTH_FIRST if the detected format starts with month', () => {
|
||||
// Mock the Intl.DateTimeFormat to return a specific format
|
||||
const mockDateTimeFormat = jest.fn().mockReturnValue({
|
||||
formatToParts: () => [
|
||||
{ type: 'month', value: '01' },
|
||||
{ type: 'day', value: '01' },
|
||||
{ type: 'year', value: '2022' },
|
||||
],
|
||||
supportedLocalesOf: () => [],
|
||||
}) as any;
|
||||
global.Intl.DateTimeFormat = mockDateTimeFormat;
|
||||
|
||||
const result = detectDateFormat();
|
||||
|
||||
expect(result).toBe(DateFormat.MONTH_FIRST);
|
||||
});
|
||||
|
||||
it('should return DateFormat.DAY_FIRST if the detected format starts with day', () => {
|
||||
// Mock the Intl.DateTimeFormat to return a specific format
|
||||
const mockDateTimeFormat = jest.fn().mockReturnValue({
|
||||
formatToParts: () => [
|
||||
{ type: 'day', value: '01' },
|
||||
{ type: 'month', value: '01' },
|
||||
{ type: 'year', value: '2022' },
|
||||
],
|
||||
}) as any;
|
||||
global.Intl.DateTimeFormat = mockDateTimeFormat;
|
||||
|
||||
const result = detectDateFormat();
|
||||
|
||||
expect(result).toBe(DateFormat.DAY_FIRST);
|
||||
});
|
||||
|
||||
it('should return DateFormat.YEAR_FIRST if the detected format starts with year', () => {
|
||||
// Mock the Intl.DateTimeFormat to return a specific format
|
||||
const mockDateTimeFormat = jest.fn().mockReturnValue({
|
||||
formatToParts: () => [
|
||||
{ type: 'year', value: '2022' },
|
||||
{ type: 'month', value: '01' },
|
||||
{ type: 'day', value: '01' },
|
||||
],
|
||||
}) as any;
|
||||
global.Intl.DateTimeFormat = mockDateTimeFormat;
|
||||
|
||||
const result = detectDateFormat();
|
||||
|
||||
expect(result).toBe(DateFormat.YEAR_FIRST);
|
||||
});
|
||||
|
||||
it('should return DateFormat.MONTH_FIRST by default if the detected format does not match any specific order', () => {
|
||||
// Mock the Intl.DateTimeFormat to return a specific format
|
||||
const mockDateTimeFormat = jest.fn().mockReturnValue({
|
||||
formatToParts: () => [
|
||||
{ type: 'hour', value: '12' },
|
||||
{ type: 'minute', value: '00' },
|
||||
{ type: 'second', value: '00' },
|
||||
],
|
||||
}) as any;
|
||||
global.Intl.DateTimeFormat = mockDateTimeFormat;
|
||||
|
||||
const result = detectDateFormat();
|
||||
|
||||
expect(result).toBe(DateFormat.MONTH_FIRST);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,30 @@
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { detectTimeFormat } from '@/localization/utils/detectTimeFormat';
|
||||
|
||||
describe('detectTimeFormat', () => {
|
||||
it('should return TimeFormat.HOUR_12 if the hour format is 12-hour', () => {
|
||||
// Mock the resolvedOptions method to return hour12 as true
|
||||
const mockResolvedOptions = jest.fn(() => ({ hour12: true }));
|
||||
Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({
|
||||
resolvedOptions: mockResolvedOptions,
|
||||
})) as any;
|
||||
|
||||
const result = detectTimeFormat();
|
||||
|
||||
expect(result).toBe(TimeFormat.HOUR_12);
|
||||
expect(mockResolvedOptions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return TimeFormat.HOUR_24 if the hour format is 24-hour', () => {
|
||||
// Mock the resolvedOptions method to return hour12 as false
|
||||
const mockResolvedOptions = jest.fn(() => ({ hour12: false }));
|
||||
Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({
|
||||
resolvedOptions: mockResolvedOptions,
|
||||
})) as any;
|
||||
|
||||
const result = detectTimeFormat();
|
||||
|
||||
expect(result).toBe(TimeFormat.HOUR_24);
|
||||
expect(mockResolvedOptions).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,21 @@
|
||||
import { formatTimeZoneLabel } from '@/localization/utils/formatTimeZoneLabel';
|
||||
|
||||
describe('formatTimeZoneLabel', () => {
|
||||
it('should format the time zone label correctly when location is included in the label', () => {
|
||||
const ianaTimeZone = 'Europe/Paris';
|
||||
const expectedLabel = '(GMT+02:00) Central European Summer Time - Paris';
|
||||
|
||||
const formattedLabel = formatTimeZoneLabel(ianaTimeZone);
|
||||
|
||||
expect(formattedLabel).toEqual(expectedLabel);
|
||||
});
|
||||
|
||||
it('should format the time zone label correctly when location is not included in the label', () => {
|
||||
const ianaTimeZone = 'America/New_York';
|
||||
const expectedLabel = '(GMT-04:00) Eastern Daylight Time - New York';
|
||||
|
||||
const formattedLabel = formatTimeZoneLabel(ianaTimeZone);
|
||||
|
||||
expect(formattedLabel).toEqual(expectedLabel);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
|
||||
export const detectDateFormat = (): DateFormat => {
|
||||
const date = new Date();
|
||||
const formatter = new Intl.DateTimeFormat(navigator.language);
|
||||
const parts = formatter.formatToParts(date);
|
||||
|
||||
const partOrder = parts
|
||||
.filter((part) => ['year', 'month', 'day'].includes(part.type))
|
||||
.map((part) => part.type);
|
||||
|
||||
if (partOrder[0] === 'month') return DateFormat.MONTH_FIRST;
|
||||
if (partOrder[0] === 'day') return DateFormat.DAY_FIRST;
|
||||
if (partOrder[0] === 'year') return DateFormat.YEAR_FIRST;
|
||||
|
||||
return DateFormat.MONTH_FIRST;
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const detectTimeFormat = () => {
|
||||
const isHour12 = Intl.DateTimeFormat(navigator.language, {
|
||||
hour: 'numeric',
|
||||
}).resolvedOptions().hour12;
|
||||
if (isDefined(isHour12) && isHour12) return TimeFormat.HOUR_12;
|
||||
return TimeFormat.HOUR_24;
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Detects the user's time zone.
|
||||
* @returns a IANA time zone
|
||||
*/
|
||||
export const detectTimeZone = () =>
|
||||
Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
@ -0,0 +1,10 @@
|
||||
import { formatTimeZoneLabel } from '@/localization/utils/formatTimeZoneLabel';
|
||||
import { AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL } from '@/settings/accounts/constants/AvailableTimezoneOptionsByLabel';
|
||||
|
||||
/**
|
||||
* Finds the matching available IANA time zone select option from a given IANA time zone.
|
||||
* @param value the IANA time zone to match
|
||||
* @returns the matching available IANA time zone select option or undefined
|
||||
*/
|
||||
export const findAvailableTimeZoneOption = (value: string) =>
|
||||
AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL[formatTimeZoneLabel(value)];
|
||||
@ -0,0 +1,15 @@
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
import { parseDate } from '~/utils/date-utils';
|
||||
|
||||
export const formatDatetime = (
|
||||
date: Date | string,
|
||||
timeZone: string,
|
||||
dateFormat: string,
|
||||
timeFormat: string,
|
||||
) => {
|
||||
return formatInTimeZone(
|
||||
parseDate(date).toJSDate(),
|
||||
timeZone,
|
||||
`${dateFormat} ${timeFormat}`,
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
|
||||
export const formatDateISOStringToDate = (
|
||||
date: string,
|
||||
timeZone: string,
|
||||
dateFormat: DateFormat,
|
||||
) => {
|
||||
return formatInTimeZone(new Date(date), timeZone, `${dateFormat}`);
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
|
||||
export const formatDateISOStringToDateTime = (
|
||||
date: string,
|
||||
timeZone: string,
|
||||
dateFormat: DateFormat,
|
||||
timeFormat: TimeFormat,
|
||||
) => {
|
||||
return formatInTimeZone(
|
||||
new Date(date),
|
||||
timeZone,
|
||||
`${dateFormat} ${timeFormat}`,
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,29 @@
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
import defaultLocale from 'date-fns/locale/en-US';
|
||||
|
||||
/**
|
||||
* Formats a IANA time zone to a select option label.
|
||||
* @param ianaTimeZone IANA time zone
|
||||
* @returns Formatted label
|
||||
* @example 'Europe/Paris' => '(GMT+01:00) Central European Time - Paris'
|
||||
*/
|
||||
export const formatTimeZoneLabel = (ianaTimeZone: string) => {
|
||||
const timeZoneWithGmtOffset = formatInTimeZone(
|
||||
Date.now(),
|
||||
ianaTimeZone,
|
||||
`(OOOO) zzzz`,
|
||||
{ locale: defaultLocale },
|
||||
);
|
||||
const ianaTimeZoneParts = ianaTimeZone.split('/');
|
||||
const location =
|
||||
ianaTimeZoneParts.length > 1
|
||||
? ianaTimeZoneParts.slice(-1)[0].replaceAll('_', ' ')
|
||||
: undefined;
|
||||
|
||||
const timeZoneLabel =
|
||||
!location || timeZoneWithGmtOffset.includes(location)
|
||||
? timeZoneWithGmtOffset
|
||||
: [timeZoneWithGmtOffset, location].join(' - ');
|
||||
|
||||
return timeZoneLabel;
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { detectDateFormat } from '@/localization/utils/detectDateFormat';
|
||||
import { WorkspaceMemberDateFormatEnum } from '~/generated/graphql';
|
||||
|
||||
export const getDateFormatFromWorkspaceDateFormat = (
|
||||
workspaceDateFormat: WorkspaceMemberDateFormatEnum,
|
||||
) => {
|
||||
switch (workspaceDateFormat) {
|
||||
case WorkspaceMemberDateFormatEnum.System:
|
||||
return detectDateFormat();
|
||||
case WorkspaceMemberDateFormatEnum.MonthFirst:
|
||||
return DateFormat.MONTH_FIRST;
|
||||
case WorkspaceMemberDateFormatEnum.DayFirst:
|
||||
return DateFormat.DAY_FIRST;
|
||||
case WorkspaceMemberDateFormatEnum.YearFirst:
|
||||
return DateFormat.YEAR_FIRST;
|
||||
default:
|
||||
return DateFormat.MONTH_FIRST;
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { detectTimeFormat } from '@/localization/utils/detectTimeFormat';
|
||||
import { WorkspaceMemberTimeFormatEnum } from '~/generated/graphql';
|
||||
|
||||
export const getTimeFormatFromWorkspaceTimeFormat = (
|
||||
workspaceTimeFormat: WorkspaceMemberTimeFormatEnum,
|
||||
) => {
|
||||
switch (workspaceTimeFormat) {
|
||||
case WorkspaceMemberTimeFormatEnum.System:
|
||||
return detectTimeFormat();
|
||||
case WorkspaceMemberTimeFormatEnum.Hour_24:
|
||||
return TimeFormat.HOUR_24;
|
||||
case WorkspaceMemberTimeFormatEnum.Hour_12:
|
||||
return TimeFormat.HOUR_12;
|
||||
default:
|
||||
return TimeFormat.HOUR_24;
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||
import { WorkspaceMemberDateFormatEnum } from '~/generated/graphql';
|
||||
|
||||
export const getWorkspaceDateFormatFromDateFormat = (
|
||||
dateFormat: DateFormat,
|
||||
) => {
|
||||
switch (dateFormat) {
|
||||
case DateFormat.SYSTEM:
|
||||
return WorkspaceMemberDateFormatEnum.System;
|
||||
case DateFormat.MONTH_FIRST:
|
||||
return WorkspaceMemberDateFormatEnum.MonthFirst;
|
||||
case DateFormat.DAY_FIRST:
|
||||
return WorkspaceMemberDateFormatEnum.DayFirst;
|
||||
case DateFormat.YEAR_FIRST:
|
||||
return WorkspaceMemberDateFormatEnum.YearFirst;
|
||||
default:
|
||||
return WorkspaceMemberDateFormatEnum.MonthFirst;
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||
import { WorkspaceMemberTimeFormatEnum } from '~/generated/graphql';
|
||||
|
||||
export const getWorkspaceTimeFormatFromTimeFormat = (
|
||||
timeFormat: TimeFormat,
|
||||
) => {
|
||||
switch (timeFormat) {
|
||||
case TimeFormat.SYSTEM:
|
||||
return WorkspaceMemberTimeFormatEnum.System;
|
||||
case TimeFormat.HOUR_24:
|
||||
return WorkspaceMemberTimeFormatEnum.Hour_24;
|
||||
case TimeFormat.HOUR_12:
|
||||
return WorkspaceMemberTimeFormatEnum.Hour_12;
|
||||
default:
|
||||
return WorkspaceMemberTimeFormatEnum.Hour_24;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user