diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index f9bdd52c26..f9b73fb817 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -917,6 +917,12 @@ dependencies: csv-parse: specifier: ~5.1.0 version: 5.1.0 + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + date-fns-tz: + specifier: ^2.0.0 + version: 2.0.0(date-fns@2.30.0) diff: specifier: ^5.1.0 version: 5.1.0 @@ -1031,9 +1037,6 @@ dependencies: minio: specifier: ^7.0.26 version: 7.1.3 - moment-timezone: - specifier: ^0.5.43 - version: 0.5.43 mongodb: specifier: ^6.3.0 version: 6.3.0 @@ -8224,6 +8227,21 @@ packages: resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==} dev: false + /date-fns-tz@2.0.0(date-fns@2.30.0): + resolution: {integrity: sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==} + peerDependencies: + date-fns: '>=2.0.0' + dependencies: + date-fns: 2.30.0 + dev: false + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.23.1 + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} dependencies: @@ -16886,7 +16904,7 @@ packages: dev: false file:projects/calendar-resources.tgz(@types/node@20.11.16)(esbuild@0.16.17)(postcss-load-config@4.0.1)(postcss@8.4.31)(ts-node@10.9.1): - resolution: {integrity: sha512-+J5+dGls2cjeZwgsifhTGvP0t5fvnXrOCBBtTS1K0lQeIxrZUjH+5rxq9GkeQsZwdwpR9vPlEuqcz3NJsUrzyw==, tarball: file:projects/calendar-resources.tgz} + resolution: {integrity: sha512-lJ2JaXA8QCbwpod7QjgyjVluatCeuzmdD63BB91L1ch1wIwLozIxnkcbwypYujwDAcsWscgCeX0F59mir50GIg==, tarball: file:projects/calendar-resources.tgz} id: file:projects/calendar-resources.tgz name: '@rush-temp/calendar-resources' version: 0.0.0 @@ -16894,6 +16912,8 @@ packages: '@types/jest': 29.5.5 '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.54.0)(typescript@5.3.3) '@typescript-eslint/parser': 6.11.0(eslint@8.54.0)(typescript@5.3.3) + date-fns: 2.30.0 + date-fns-tz: 2.0.0(date-fns@2.30.0) eslint: 8.54.0 eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.11.0)(eslint-plugin-import@2.28.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.54.0)(typescript@5.3.3) eslint-plugin-import: 2.28.1(eslint@8.54.0) @@ -23115,7 +23135,7 @@ packages: dev: false file:projects/ui.tgz(@types/node@20.11.16)(esbuild@0.16.17)(postcss-load-config@4.0.1)(postcss@8.4.31)(ts-node@10.9.1): - resolution: {integrity: sha512-e/ZUaufTKKEU5govEHF470SmSXz4qXfrfZFZeCfZxjWNPwl07iZPG8jD9y3PonhC6jzZrt5TCXSAlZ36rAFm3Q==, tarball: file:projects/ui.tgz} + resolution: {integrity: sha512-0FormJ2jYs7V10Jg7k1m4WwqRck3wVcmvdrnI/xFhzRb/QqdJ6RfKkMoPy8HTORAcWElNJ19kcC7EPwgmWZbTg==, tarball: file:projects/ui.tgz} id: file:projects/ui.tgz name: '@rush-temp/ui' version: 0.0.0 @@ -23124,6 +23144,8 @@ packages: '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.54.0)(typescript@5.3.3) '@typescript-eslint/parser': 6.11.0(eslint@8.54.0)(typescript@5.3.3) autolinker: 4.0.0 + date-fns: 2.30.0 + date-fns-tz: 2.0.0(date-fns@2.30.0) emoji-regex: 10.2.1 eslint: 8.54.0 eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.11.0)(eslint-plugin-import@2.28.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.1.1)(eslint@8.54.0)(typescript@5.3.3) diff --git a/packages/ui/package.json b/packages/ui/package.json index a4f936d349..636e135380 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -45,7 +45,8 @@ "fast-equals": "^2.0.3", "autolinker": "4.0.0", "emoji-regex": "^10.1.0", - "moment-timezone": "^0.5.43" + "date-fns": "^2.30.0", + "date-fns-tz": "^2.0.0" }, "repository": "https://github.com/hcenginneing/anticrm", "publishConfig": { diff --git a/packages/ui/src/components/calendar/DateInputBox.svelte b/packages/ui/src/components/calendar/DateInputBox.svelte index 8534d71fc3..a3680cdc87 100644 --- a/packages/ui/src/components/calendar/DateInputBox.svelte +++ b/packages/ui/src/components/calendar/DateInputBox.svelte @@ -18,8 +18,7 @@ import Icon from '../Icon.svelte' import Label from '../Label.svelte' import IconClose from '../icons/Close.svelte' - import { daysInMonth, getUserTimezone } from './internal/DateUtils' - import moment from 'moment-timezone' + import { daysInMonth, fromCurrentToTz, getUserTimezone } from './internal/DateUtils' export let currentDate: Date | null export let withTime: boolean = false @@ -44,32 +43,22 @@ const setValue = (val: number, date: Date | null, id: TEdits): Date => { if (date == null) date = new Date() + const value = timeZone ? fromCurrentToTz(date, timeZone) : date switch (id) { case 'day': - date = new Date(timeZone ? moment(date).tz(timeZone).date(val).valueOf() : moment(date).date(val).valueOf()) + date = new Date(value.setDate(val)) break case 'month': - date = new Date( - timeZone - ? moment(date) - .tz(timeZone) - .month(val - 1) - .valueOf() - : moment(date) - .month(val - 1) - .valueOf() - ) + date = new Date(value.setMonth(val - 1)) break case 'year': - date = new Date(timeZone ? moment(date).tz(timeZone).year(val).valueOf() : moment(date).year(val).valueOf()) + date = new Date(value.setFullYear(val)) break case 'hour': - date = new Date(timeZone ? moment(date).tz(timeZone).hours(val).valueOf() : moment(date).hours(val).valueOf()) + date = new Date(value.setHours(val)) break case 'min': - date = new Date( - timeZone ? moment(date).tz(timeZone).minutes(val).valueOf() : moment(date).minutes(val).valueOf() - ) + date = new Date(value.setMinutes(val)) break } return date @@ -92,17 +81,18 @@ } const getValue = (date: Date, id: TEdits): number => { + const val = timeZone ? fromCurrentToTz(date, timeZone) : date switch (id) { case 'day': - return timeZone ? moment(date).tz(timeZone).date() : moment(date).date() + return val.getDate() case 'month': - return timeZone ? moment(date).tz(timeZone).month() + 1 : moment(date).month() + 1 + return val.getMonth() + 1 case 'year': - return timeZone ? moment(date).tz(timeZone).year() : moment(date).year() + return val.getFullYear() case 'hour': - return timeZone ? moment(date).tz(timeZone).hours() : moment(date).hours() + return val.getHours() case 'min': - return timeZone ? moment(date).tz(timeZone).minutes() : moment(date).minutes() + return val.getMinutes() } } diff --git a/packages/ui/src/components/calendar/Month.svelte b/packages/ui/src/components/calendar/Month.svelte index 4e0475ed1d..bfa47e6c65 100644 --- a/packages/ui/src/components/calendar/Month.svelte +++ b/packages/ui/src/components/calendar/Month.svelte @@ -15,9 +15,9 @@ <script lang="ts"> import { afterUpdate, createEventDispatcher } from 'svelte' import { capitalizeFirstLetter } from '../../utils' - import Icon from '../Icon.svelte' - import IconChevronRight from '../icons/ChevronRight.svelte' + import ButtonIcon from '../ButtonIcon.svelte' import IconChevronLeft from '../icons/ChevronLeft.svelte' + import IconChevronRight from '../icons/ChevronRight.svelte' import { ICell, TCellStyle, @@ -25,12 +25,11 @@ day, daysInMonth, firstDay, + fromCurrentToTz, getMonthName, getUserTimezone, getWeekDayName } from './internal/DateUtils' - import ButtonIcon from '../ButtonIcon.svelte' - import moment from 'moment-timezone' export let currentDate: Date | null export let mondayStart: boolean = true @@ -52,12 +51,8 @@ let days: ICell[] = [] const getDateStyle = (date: Date): TCellStyle => { if (currentDate != null) { - const zonedTime = moment(currentDate).tz(timeZone) - if ( - zonedTime.date() === date.getDate() && - zonedTime.year() === date.getFullYear() && - zonedTime.month() === date.getMonth() - ) { + const zonedTime = fromCurrentToTz(currentDate, timeZone) + if (areDatesEqual(zonedTime, date)) { return 'selected' } } diff --git a/packages/ui/src/components/calendar/MonthSquare.svelte b/packages/ui/src/components/calendar/MonthSquare.svelte index ae9aaba50f..2bf792c729 100644 --- a/packages/ui/src/components/calendar/MonthSquare.svelte +++ b/packages/ui/src/components/calendar/MonthSquare.svelte @@ -14,21 +14,21 @@ --> <script lang="ts"> import { afterUpdate, createEventDispatcher } from 'svelte' + import { capitalizeFirstLetter } from '../../utils' + import Button from '../Button.svelte' import IconArrowLeft from '../icons/ArrowLeft.svelte' import IconArrowRight from '../icons/ArrowRight.svelte' - import Button from '../Button.svelte' import { - firstDay, - day, - getWeekDayName, areDatesEqual, + day, + firstDay, + fromCurrentToTz, getMonthName, - weekday, + getUserTimezone, + getWeekDayName, isWeekend, - getUserTimezone + weekday } from './internal/DateUtils' - import { capitalizeFirstLetter } from '../../utils' - import moment from 'moment-timezone' export let currentDate: Date | null export let viewDate: Date @@ -61,22 +61,14 @@ function isSelected (currentDate: Date | null, selectedTo: Date | null | undefined, target: Date): boolean { if (currentDate != null) { - const zonedTime = moment(currentDate).tz(timeZone) - if ( - zonedTime.date() === target.getDate() && - zonedTime.year() === target.getFullYear() && - zonedTime.month() === target.getMonth() - ) { + const zonedTime = fromCurrentToTz(currentDate, timeZone) + if (areDatesEqual(zonedTime, target)) { return true } } if (selectedTo != null) { - const zonedTime = moment(selectedTo).tz(timeZone) - if ( - zonedTime.date() === target.getDate() && - zonedTime.year() === target.getFullYear() && - zonedTime.month() === target.getMonth() - ) { + const zonedTime = fromCurrentToTz(selectedTo, timeZone) + if (areDatesEqual(zonedTime, target)) { return true } } diff --git a/packages/ui/src/components/calendar/TimeInputBox.svelte b/packages/ui/src/components/calendar/TimeInputBox.svelte index bd1ce745b4..b6bf64a977 100644 --- a/packages/ui/src/components/calendar/TimeInputBox.svelte +++ b/packages/ui/src/components/calendar/TimeInputBox.svelte @@ -16,7 +16,7 @@ import { afterUpdate, createEventDispatcher } from 'svelte' import ui from '../../plugin' import Label from '../Label.svelte' - import moment from 'moment-timezone' + import { fromCurrentToTz, fromTzToCurrent } from './internal/DateUtils' export let currentDate: Date export let size: 'small' | 'medium' = 'medium' @@ -42,14 +42,13 @@ const setValue = (val: number, date: Date | null, id: TEdits, timeZone: string | undefined): Date => { if (date == null) date = new Date() + const value = timeZone ? fromTzToCurrent(date, timeZone) : new Date(date) switch (id) { case 'hour': - date = new Date(timeZone ? moment(date).tz(timeZone).hours(val).valueOf() : moment(date).hours(val).valueOf()) + date = new Date(value.setHours(val)) break case 'min': - date = new Date( - timeZone ? moment(date).tz(timeZone).minutes(val).valueOf() : moment(date).minutes(val).valueOf() - ) + date = new Date(value.setMinutes(val)) break } return date @@ -66,11 +65,12 @@ } const getValue = (date: Date, id: TEdits, timeZone: string | undefined): number => { + const value = timeZone ? fromCurrentToTz(date, timeZone) : new Date(date) switch (id) { case 'hour': - return timeZone ? moment(date).tz(timeZone).hours() : moment(date).hours() + return value.getHours() case 'min': - return timeZone ? moment(date).tz(timeZone).minutes() : moment(date).minutes() + return value.getMinutes() } } diff --git a/packages/ui/src/components/calendar/internal/DateUtils.ts b/packages/ui/src/components/calendar/internal/DateUtils.ts index b979e37c18..9b2b9c971a 100644 --- a/packages/ui/src/components/calendar/internal/DateUtils.ts +++ b/packages/ui/src/components/calendar/internal/DateUtils.ts @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz' import { type TimeZone } from '../../../types' export const DAYS_IN_WEEK = 7 @@ -66,6 +67,14 @@ export function areDatesEqual (firstDate: Date | undefined, secondDate: Date | u ) } +export function fromCurrentToTz (date: Date | number, tz: string): Date { + return utcToZonedTime(zonedTimeToUtc(date, getUserTimezone()), tz) +} + +export function fromTzToCurrent (date: Date | number, tz: string): Date { + return utcToZonedTime(zonedTimeToUtc(date, tz), getUserTimezone()) +} + export function isWeekend (date: Date): boolean { return date.getDay() === 0 || date.getDay() === 6 } diff --git a/plugins/calendar-resources/package.json b/plugins/calendar-resources/package.json index bd124986f2..ba0510bc8d 100644 --- a/plugins/calendar-resources/package.json +++ b/plugins/calendar-resources/package.json @@ -53,6 +53,7 @@ "@hcengineering/view": "^0.6.9", "@hcengineering/workbench": "^0.6.9", "fast-equals": "^2.0.3", - "moment-timezone": "^0.5.43" + "date-fns": "^2.30.0", + "date-fns-tz": "^2.0.0" } } diff --git a/plugins/calendar-resources/src/components/EventTimeEditor.svelte b/plugins/calendar-resources/src/components/EventTimeEditor.svelte index 45b6bc51a3..554cc91f96 100644 --- a/plugins/calendar-resources/src/components/EventTimeEditor.svelte +++ b/plugins/calendar-resources/src/components/EventTimeEditor.svelte @@ -13,8 +13,8 @@ // limitations under the License. --> <script lang="ts"> - import { Icon, IconArrowRight, getUserTimezone } from '@hcengineering/ui' - import moment from 'moment-timezone' + import { Icon, IconArrowRight, areDatesEqual, getUserTimezone } from '@hcengineering/ui' + import { utcToZonedTime } from 'date-fns-tz' import { createEventDispatcher } from 'svelte' import calendar from '../plugin' import DateEditor from './DateEditor.svelte' @@ -26,7 +26,7 @@ export let timeZone: string = getUserTimezone() export let focusIndex = -1 - $: sameDate = moment(startDate).tz(timeZone).isSame(moment(dueDate).tz(timeZone), 'date') + $: sameDate = areDatesEqual(utcToZonedTime(startDate, timeZone), utcToZonedTime(dueDate, timeZone)) let diff = dueDate - startDate const allDayDuration = 24 * 60 * 60 * 1000 - 1