From 4fbe02dfe1b99c374ddeea3ecfea1d291bbbc7d0 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:58:36 +0400 Subject: [PATCH 1/9] refactor(scheduler): rename m_utils and m_utils_time_zone (drop m_ prefix) --- .../scheduler/__tests__/performance.test.ts | 2 +- .../scheduler/appointment_popup/form.ts | 2 +- .../appointments/m_appointment_collection.ts | 2 +- .../js/__internal/scheduler/m_scheduler.ts | 4 +- .../js/__internal/scheduler/m_subscribes.ts | 2 +- .../js/__internal/scheduler/m_utils.ts | 42 --- .../__internal/scheduler/m_utils_time_zone.ts | 290 ------------------ .../scheduler/r1/timezone_calculator/utils.ts | 2 +- .../js/__internal/scheduler/r1/utils/base.ts | 2 +- .../scheduler/recurrence/generate_dates.ts | 2 +- .../scheduler_options_base_widget.ts | 2 +- ...st.ts => utils_time_zone.santiago.test.ts} | 2 +- ...e_zone.test.ts => utils_time_zone.test.ts} | 2 +- .../get_date_information.ts | 2 +- .../options/get_minutes_cell_intervals.ts | 2 +- .../view_model/get_appointment_info.ts | 2 +- .../scheduler/workspaces/m_work_space.ts | 2 +- .../scheduler/workspaces/timeline.ts | 2 +- .../m_date_header_data_generator.ts | 2 +- .../view_model/m_grouped_data_map_provider.ts | 2 +- .../view_model/m_view_data_generator.ts | 2 +- .../view_model/m_view_data_generator_month.ts | 2 +- .../m_view_data_generator_timeline_month.ts | 2 +- .../view_model/m_view_data_provider.ts | 2 +- .../workspaces/work_space_indicator.ts | 2 +- .../scheduler/workspaces/work_space_month.ts | 2 +- .../common.methods.tests.js | 2 +- .../dataSource.tests.js | 2 +- .../integration.appointmentsVertical.tests.js | 2 +- .../timezones.tests.js | 2 +- 30 files changed, 29 insertions(+), 361 deletions(-) delete mode 100644 packages/devextreme/js/__internal/scheduler/m_utils.ts delete mode 100644 packages/devextreme/js/__internal/scheduler/m_utils_time_zone.ts rename packages/devextreme/js/__internal/scheduler/{m_utils_time_zone.santiago.test.ts => utils_time_zone.santiago.test.ts} (92%) rename packages/devextreme/js/__internal/scheduler/{m_utils_time_zone.test.ts => utils_time_zone.test.ts} (98%) diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/performance.test.ts b/packages/devextreme/js/__internal/scheduler/__tests__/performance.test.ts index dc13c5c5cf5d..92b1b4ecffda 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/performance.test.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/performance.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, jest, } from '@jest/globals'; -import timezoneUtils from '../m_utils_time_zone'; +import timezoneUtils from '../utils_time_zone'; import { createScheduler } from './__mock__/create_scheduler'; const startDate = new Date(2025, 0, 6); diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/form.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/form.ts index 600e72ed09cc..2b5526acff2d 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/form.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/form.ts @@ -27,7 +27,6 @@ import { dateSerialization } from '@ts/core/utils/m_date_serialization'; import DropDownEditor from '@ts/ui/drop_down_editor/drop_down_editor'; import type Popup from '@ts/ui/popup/m_popup'; -import timeZoneUtils from '../m_utils_time_zone'; import type { TimeZoneCalculator } from '../r1/timezone_calculator/calculator'; import type { CreateComponentFn, SafeAppointment } from '../types'; import type { AppointmentDataAccessor } from '../utils/data_accessor/appointment_data_accessor'; @@ -35,6 +34,7 @@ import type { ResourceLoader } from '../utils/loader/resource_loader'; import { DEFAULT_ICONS_SHOW_MODE } from '../utils/options/constants'; import { getAppointmentGroupIndex, getRawAppointmentGroupValues, getSafeGroupValues } from '../utils/resource_manager/appointment_groups_utils'; import type { ResourceManager } from '../utils/resource_manager/resource_manager'; +import timeZoneUtils from '../utils_time_zone'; import { customizeFormItems } from './customize_form_items'; import { getRepeatSelectItems, REPEAT_NEVER_VALUE } from './localized_items'; import type { AppointmentPopupContext } from './popup'; diff --git a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts index a85011fc3c0a..a27cab8d43dd 100644 --- a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts +++ b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts @@ -27,7 +27,7 @@ import { APPOINTMENT_ITEM_CLASS, } from '../classes'; import { APPOINTMENT_SETTINGS_KEY } from '../constants'; -import timeZoneUtils from '../m_utils_time_zone'; +import timeZoneUtils from '../utils_time_zone'; import type { CompactAppointmentOptions } from '../types'; import { AppointmentAdapter } from '../utils/appointment_adapter/appointment_adapter'; import type { AppointmentDataAccessor } from '../utils/data_accessor/appointment_data_accessor'; diff --git a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts index 2cfd65ffa81c..9f6c5c7d607c 100644 --- a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts +++ b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts @@ -51,8 +51,6 @@ import { hide as hideLoading, show as showLoading } from './loading'; import { CompactAppointmentsHelper } from './m_compact_appointments_helper'; import type { SubscribeKey, SubscribeMethods } from './m_subscribes'; import subscribes from './m_subscribes'; -import { utils } from './m_utils'; -import timeZoneUtils, { type TimezoneLabel } from './m_utils_time_zone'; import { combineRemoteFilter } from './r1/filterting/remote'; import { createTimeZoneCalculator } from './r1/timezone_calculator/index'; import { @@ -73,6 +71,7 @@ import type { ScrollToGroupValuesOrOptions, ScrollToOptions, TargetedAppointment, ViewType, } from './types'; +import { utils } from './utils'; import { AppointmentAdapter } from './utils/appointment_adapter/appointment_adapter'; import { AppointmentDataAccessor } from './utils/data_accessor/appointment_data_accessor'; import { getTargetedAppointment } from './utils/get_targeted_appointment'; @@ -83,6 +82,7 @@ import { VIEWS } from './utils/options/constants_view'; import type { NormalizedView, SafeSchedulerOptions } from './utils/options/types'; import { getAppointmentGroupValues, setAppointmentGroupValues } from './utils/resource_manager/appointment_groups_utils'; import { ResourceManager } from './utils/resource_manager/resource_manager'; +import timeZoneUtils, { type TimezoneLabel } from './utils_time_zone'; import AppointmentLayoutManager from './view_model/appointments_layout_manager'; import { AppointmentDataSource } from './view_model/m_appointment_data_source'; import type { AppointmentViewModelPlain } from './view_model/types'; diff --git a/packages/devextreme/js/__internal/scheduler/m_subscribes.ts b/packages/devextreme/js/__internal/scheduler/m_subscribes.ts index d530559a8b82..6170ead29c8d 100644 --- a/packages/devextreme/js/__internal/scheduler/m_subscribes.ts +++ b/packages/devextreme/js/__internal/scheduler/m_subscribes.ts @@ -8,7 +8,6 @@ import { getDeltaTime } from './appointments/resizing/get_delta_time'; import { getDateFormatType, getDateText } from './appointments_new/utils/get_date_text'; import { VERTICAL_VIEW_TYPES } from './constants'; import type Scheduler from './m_scheduler'; -import { utils } from './m_utils'; import { isAppointmentTakesAllDay } from './r1/utils/base'; import type { AppointmentTooltipItem, @@ -16,6 +15,7 @@ import type { SafeAppointment, TargetedAppointment, } from './types'; +import { utils } from './utils'; import { AppointmentAdapter } from './utils/appointment_adapter/appointment_adapter'; import type { AppointmentItemViewModel } from './view_model/types'; diff --git a/packages/devextreme/js/__internal/scheduler/m_utils.ts b/packages/devextreme/js/__internal/scheduler/m_utils.ts deleted file mode 100644 index 5ec2aa60830c..000000000000 --- a/packages/devextreme/js/__internal/scheduler/m_utils.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { getPublicElement } from '@js/core/element'; -import $ from '@js/core/renderer'; -import { getOuterHeight, setHeight, setWidth } from '@js/core/utils/size'; - -import { APPOINTMENT_SETTINGS_KEY } from './constants'; -import type { AppointmentViewModelPlain } from './view_model/types'; - -export const utils = { - dataAccessors: { - getAppointmentSettings: (element) => $(element) - .data(APPOINTMENT_SETTINGS_KEY) as unknown as AppointmentViewModelPlain | undefined, - }, - DOM: { - getHeaderHeight: (header) => (header - ? header._$element && parseInt(getOuterHeight(header._$element), 10) - : 0), - }, - renovation: { - renderComponent: (widget, parentElement, componentClass, componentName, viewModel) => { - let component = widget[componentName]; - if (!component) { - const container = getPublicElement(parentElement); - component = widget._createComponent(container, componentClass, viewModel); - widget[componentName] = component; - } else { - const $element = component.$element(); - const elementStyle = $element.get(0).style; - const { height } = elementStyle; - const { width } = elementStyle; - - component.option(viewModel); - - if (height) { - setHeight($element, height); - } - if (width) { - setWidth($element, width); - } - } - }, - }, -}; diff --git a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.ts b/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.ts deleted file mode 100644 index c704c975c414..000000000000 --- a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.ts +++ /dev/null @@ -1,290 +0,0 @@ -// TODO(Refactoring): move this module to ./utils directory -import errors from '@js/core/errors'; -import { dateUtilsTs } from '@ts/core/utils/date'; -import { macroTaskArray } from '@ts/scheduler/utils/index'; - -import dateUtils from '../../core/utils/date'; -import { globalCache } from './global_cache'; -import timeZoneList from './timezones/timezone_list'; - -export interface TimezoneLabel { - /** uniq timezone id, e.g: 'America/Los_Angeles' */ - id: string; - /** timezone display string, e.g: '(GMT -08:00) America - Los Angeles' */ - title?: string; -} - -export interface TimezoneData extends TimezoneLabel { - /** timezone offset in hours */ - offset?: number; -} - -const timeZoneListSet = new Set(timeZoneList.value); -const toMs = dateUtils.dateToMilliseconds; -const MINUTES_IN_HOUR = 60; -const MS_IN_MINUTE = 60000; -const GMT = 'GMT'; -const offsetFormatRegexp = /^GMT(?:[+-]\d{2}:\d{2})?$/; - -const createUTCDateWithLocalOffset = (date) => { - if (!date) { - return date; - } - - return new Date(Date.UTC( - date.getFullYear(), - date.getMonth(), - date.getDate(), - date.getHours(), - date.getMinutes(), - date.getSeconds(), - )); -}; - -const createDateFromUTCWithLocalOffset = (date: Date): Date => new Date( - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate(), - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds(), -); - -const getTimezoneOffsetChangeInMinutes = (startDate, endDate, updatedStartDate, updatedEndDate) => getDaylightOffset(updatedStartDate, updatedEndDate) - getDaylightOffset(startDate, endDate); - -const getTimezoneOffsetChangeInMs = (startDate, endDate, updatedStartDate, updatedEndDate) => getTimezoneOffsetChangeInMinutes(startDate, endDate, updatedStartDate, updatedEndDate) * toMs('minute'); - -const getDaylightOffset = (startDate, endDate) => new Date(startDate).getTimezoneOffset() - new Date(endDate).getTimezoneOffset(); - -const getDaylightOffsetInMs = (startDate, endDate) => getDaylightOffset(startDate, endDate) * toMs('minute'); - -const calculateTimezoneByValueCore = (timeZone: string, date = new Date()): number | undefined => { - const offset = getStringOffset(timeZone, date); - - if (offset === undefined) { - return undefined; - } - - if (offset === GMT) { - return 0; - } - - const isMinus = offset.substring(3, 4) === '-'; - const hours = offset.substring(4, 6); - const minutes = offset.substring(7, 9); - - const result = parseInt(hours, 10) + parseInt(minutes, 10) / MINUTES_IN_HOUR; - return isMinus ? -result : result; -}; - -const calculateTimezoneByValue = (timeZone: string | undefined, date: Date | number = new Date()): number | undefined => { - if (!timeZone) { - return undefined; - } - - const isValidTimezone = timeZoneListSet.has(timeZone); - if (!isValidTimezone) { - errors.log('W0009', timeZone); - return undefined; - } - - const dateObj = new Date(date); - if (!dateUtilsTs.isValidDate(dateObj)) { - return undefined; - } - - if (isEqualLocalTimeZone(timeZone)) { - return -dateObj.getTimezoneOffset() / MINUTES_IN_HOUR; - } - - return calculateTimezoneByValueCore(timeZone, dateObj); -}; - -// 'GMT±XX:YY' or 'GMT' format -const getStringOffset = (timeZone: string, date = new Date()): string | undefined => { - let result = ''; - try { - const dateTimeFormat = globalCache.timezones.memo(`intl${timeZone}`, () => new Intl.DateTimeFormat('en-US', { - timeZone, - timeZoneName: 'longOffset', - })); - - result = dateTimeFormat - .formatToParts(date) - .find(({ type }) => type === 'timeZoneName')?.value ?? ''; - } catch (e) { - errors.log('W0009', timeZone); - return undefined; - } - - const isSupportedFormat = offsetFormatRegexp.test(result); - if (!isSupportedFormat) { - errors.log('W0009', timeZone); - return undefined; - } - - return result; -}; - -const getOffsetNamePart = (offset: string): string => { - if (offset === GMT) { - return `${offset} +00:00`; - } - - return offset.replace(GMT, `${GMT} `); -}; - -const getTimezoneTitle = (timeZone: string, date = new Date()): string | undefined => { - if (!dateUtilsTs.isValidDate(date)) { - return ''; - } - - const tzNamePart = timeZone.replace(/\//g, ' - ').replace(/_/g, ' '); - const offset = getStringOffset(timeZone, date); - if (offset === undefined) { - return undefined; - } - - const offsetNamePart = getOffsetNamePart(offset); - return `(${offsetNamePart}) ${tzNamePart}`; -}; - -// eslint-disable-next-line @typescript-eslint/naming-convention -const _getDaylightOffsetByTimezone = (startDate: Date, endDate: Date, timeZone: string): number => { - const startDayOffset = calculateTimezoneByValue(timeZone, startDate); - const endDayOffset = calculateTimezoneByValue(timeZone, endDate); - if (startDayOffset === undefined || endDayOffset === undefined) { - return 0; - } - - return startDayOffset - endDayOffset; -}; - -const getCorrectedDateByDaylightOffsets = (convertedOriginalStartDate, convertedDate, date, timeZone, startDateTimezone) => { - const daylightOffsetByCommonTimezone = _getDaylightOffsetByTimezone(convertedOriginalStartDate, convertedDate, timeZone); - const daylightOffsetByAppointmentTimezone = _getDaylightOffsetByTimezone(convertedOriginalStartDate, convertedDate, startDateTimezone); - const diff = daylightOffsetByCommonTimezone - daylightOffsetByAppointmentTimezone; - - return new Date(date.getTime() - diff * toMs('hour')); -}; - -const correctRecurrenceExceptionByTimezone = (exception, exceptionByStartDate) => { - const timezoneOffset = (exception.getTimezoneOffset() - exceptionByStartDate.getTimezoneOffset()) / MINUTES_IN_HOUR; - - return new Date(exception.getTime() + timezoneOffset * toMs('hour')); -}; - -const isTimezoneChangeInDate = (date) => { - const startDayDate = new Date(new Date(date).setHours(0, 0, 0, 0)); - const endDayDate = new Date(new Date(date).setHours(23, 59, 59, 0)); - return (startDayDate.getTimezoneOffset() - endDayDate.getTimezoneOffset()) !== 0; -}; - -const getDateWithoutTimezoneChange = (date) => { - const clonedDate = new Date(date); - if (isTimezoneChangeInDate(clonedDate)) { - const result = new Date(clonedDate); - return new Date(result.setDate(result.getDate() + 1)); - } - return clonedDate; -}; - -const isSameAppointmentDates = (startDate, endDate) => { - // NOTE: subtract 1 millisecond to avoid 00.00 time. Method should return 'true' for "2020:10:10 22:00:00" and "2020:10:11 00:00:00", for example. - endDate = new Date(endDate.getTime() - 1); - - return dateUtils.sameDate(startDate, endDate); -}; - -const getClientTimezoneOffset = (date = new Date()) => date.getTimezoneOffset() * MS_IN_MINUTE; - -const getDiffBetweenClientTimezoneOffsets = (firstDate = new Date(), secondDate = new Date()) => getClientTimezoneOffset(firstDate) - getClientTimezoneOffset(secondDate); - -const getMachineTimezoneName = () => globalCache.timezones.memo('localTimezone', () => dateUtils.getMachineTimezoneName()); - -const isEqualLocalTimeZone = (timeZoneName: string) => { - const localTimeZoneName = getMachineTimezoneName(); - if (localTimeZoneName && localTimeZoneName === timeZoneName) { - return true; - } - return false; -}; - -const addOffsetsWithoutDST = (date: Date, ...offsets: number[]): Date => { - const newDate = dateUtilsTs.addOffsets(date, ...offsets); - const daylightShift = getDaylightOffsetInMs(date, newDate); - - if (!daylightShift) { - return newDate; - } - - const correctLocalDate = dateUtilsTs.addOffsets(newDate, -daylightShift); - const daylightSecondShift = getDaylightOffsetInMs(newDate, correctLocalDate); - - return !daylightSecondShift - ? correctLocalDate - : newDate; -}; - -const getTimeZones = ( - date = new Date(), - timeZones = timeZoneList.value, -): TimezoneData[] => timeZones.map((timezoneId) => ({ - id: timezoneId, - title: getTimezoneTitle(timezoneId, date), - offset: calculateTimezoneByValue(timezoneId, date), -})); - -const GET_TIMEZONES_BATCH_SIZE = 10; -const cacheTimeZones = async (): Promise => globalCache.timezones.memo( - 'timeZonesCachePromise', - () => macroTaskArray - .map( - timeZoneList.value, - (timezoneId) => ({ - id: timezoneId, - title: getTimezoneTitle(timezoneId, new Date()), - }), - GET_TIMEZONES_BATCH_SIZE, - ) - .then((data) => globalCache.timezones.memo('timeZonesCache', () => data)), -); - -const getTimeZonesCache = (): TimezoneLabel[] => globalCache.timezones.get('timeZonesCache') ?? []; - -const isLocalTimeMidnightDST = (date: Date): boolean => { - const startDayDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - - return startDayDate.getHours() === 1; -}; - -const utils = { - getDaylightOffset, - getDaylightOffsetInMs, - getTimezoneOffsetChangeInMinutes, - getTimezoneOffsetChangeInMs, - calculateTimezoneByValue, - getCorrectedDateByDaylightOffsets, - isSameAppointmentDates, - correctRecurrenceExceptionByTimezone, - getClientTimezoneOffset, - getDiffBetweenClientTimezoneOffsets, - - createUTCDateWithLocalOffset, - createDateFromUTCWithLocalOffset, - - isTimezoneChangeInDate, - getDateWithoutTimezoneChange, - getMachineTimezoneName, - isEqualLocalTimeZone, - - addOffsetsWithoutDST, - - getTimeZones, - getTimeZonesCache, - cacheTimeZones, - - isLocalTimeMidnightDST, -}; - -export default utils; diff --git a/packages/devextreme/js/__internal/scheduler/r1/timezone_calculator/utils.ts b/packages/devextreme/js/__internal/scheduler/r1/timezone_calculator/utils.ts index 9b5c4c591a1c..84f12b39bf0e 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/timezone_calculator/utils.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/timezone_calculator/utils.ts @@ -1,4 +1,4 @@ -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import { TimeZoneCalculator } from './calculator'; export const createTimeZoneCalculator = ( diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts index 607d19165a82..bcb7457a933d 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts @@ -7,7 +7,7 @@ import { VERTICAL_GROUP_COUNT_CLASSES } from '../../classes'; import { HORIZONTAL_GROUP_ORIENTATION, VERTICAL_GROUP_ORIENTATION, } from '../../constants'; -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import type { AllDayPanelModeType, AppointmentGeometry, diff --git a/packages/devextreme/js/__internal/scheduler/recurrence/generate_dates.ts b/packages/devextreme/js/__internal/scheduler/recurrence/generate_dates.ts index 6027f03aa3ba..c5bc3f7fc390 100644 --- a/packages/devextreme/js/__internal/scheduler/recurrence/generate_dates.ts +++ b/packages/devextreme/js/__internal/scheduler/recurrence/generate_dates.ts @@ -1,7 +1,7 @@ import { dateUtilsTs } from '@ts/core/utils/date'; import { RRule, RRuleSet } from 'rrule'; -import timeZoneUtils from '../m_utils_time_zone'; +import timeZoneUtils from '../utils_time_zone'; import { getDateByAsciiString, parseRecurrenceRule } from './base'; import type { ProcessorOptions, RRuleParams } from './types'; import { validateRRuleObject } from './validate_rule'; diff --git a/packages/devextreme/js/__internal/scheduler/scheduler_options_base_widget.ts b/packages/devextreme/js/__internal/scheduler/scheduler_options_base_widget.ts index 50300301227e..b36e1c45741b 100644 --- a/packages/devextreme/js/__internal/scheduler/scheduler_options_base_widget.ts +++ b/packages/devextreme/js/__internal/scheduler/scheduler_options_base_widget.ts @@ -1,7 +1,6 @@ import Widget from '@js/ui/widget/ui.widget'; import { extend } from '@ts/core/utils/m_extend'; -import timeZoneUtils from './m_utils_time_zone'; import { DEFAULT_SCHEDULER_INTEGRATION_OPTIONS, DEFAULT_SCHEDULER_INTERNAL_OPTIONS, @@ -15,6 +14,7 @@ import type { } from './utils/options/types'; import { getCurrentView, getViewOption, getViews } from './utils/options/utils'; import { SchedulerOptionsValidator, SchedulerOptionsValidatorErrorsHandler } from './utils/options_validator/index'; +import timeZoneUtils from './utils_time_zone'; export class SchedulerOptionsBaseWidget extends Widget { protected views: NormalizedView[] = []; diff --git a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.santiago.test.ts b/packages/devextreme/js/__internal/scheduler/utils_time_zone.santiago.test.ts similarity index 92% rename from packages/devextreme/js/__internal/scheduler/m_utils_time_zone.santiago.test.ts rename to packages/devextreme/js/__internal/scheduler/utils_time_zone.santiago.test.ts index 8563d2bab873..354709f51445 100644 --- a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.santiago.test.ts +++ b/packages/devextreme/js/__internal/scheduler/utils_time_zone.santiago.test.ts @@ -6,7 +6,7 @@ import { describe, expect, it, } from '@jest/globals'; -import timeZoneUtils from './m_utils_time_zone'; +import timeZoneUtils from './utils_time_zone'; describe('isLocalTimeMidnightDST', () => { it('should return false for summer DST', () => { diff --git a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.test.ts b/packages/devextreme/js/__internal/scheduler/utils_time_zone.test.ts similarity index 98% rename from packages/devextreme/js/__internal/scheduler/m_utils_time_zone.test.ts rename to packages/devextreme/js/__internal/scheduler/utils_time_zone.test.ts index bacd710c2525..acc54ae684d6 100644 --- a/packages/devextreme/js/__internal/scheduler/m_utils_time_zone.test.ts +++ b/packages/devextreme/js/__internal/scheduler/utils_time_zone.test.ts @@ -4,8 +4,8 @@ import { import { macroTaskArray } from '@ts/scheduler/utils/index'; import { globalCache } from './global_cache'; -import timeZoneUtils from './m_utils_time_zone'; import timeZoneList from './timezones/timezone_list'; +import timeZoneUtils from './utils_time_zone'; const defaultTimeZones = timeZoneList.value; diff --git a/packages/devextreme/js/__internal/scheduler/view_model/filtration/utils/split_by_recurrence/get_date_information.ts b/packages/devextreme/js/__internal/scheduler/view_model/filtration/utils/split_by_recurrence/get_date_information.ts index 35281af8cdb7..4ee6edc62e5e 100644 --- a/packages/devextreme/js/__internal/scheduler/view_model/filtration/utils/split_by_recurrence/get_date_information.ts +++ b/packages/devextreme/js/__internal/scheduler/view_model/filtration/utils/split_by_recurrence/get_date_information.ts @@ -1,7 +1,7 @@ import dateUtils from '@js/core/utils/date'; import { globalCache } from '../../../../global_cache'; -import timeZoneUtils from '../../../../m_utils_time_zone'; +import timeZoneUtils from '../../../../utils_time_zone'; export interface DateInformation { offsetMs: number; diff --git a/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/options/get_minutes_cell_intervals.ts b/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/options/get_minutes_cell_intervals.ts index 6085f47c2afe..dc4b1b31bcc6 100644 --- a/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/options/get_minutes_cell_intervals.ts +++ b/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/options/get_minutes_cell_intervals.ts @@ -1,6 +1,6 @@ import { dateUtils } from '@ts/core/utils/m_date'; -import timeZoneUtils from '../../../m_utils_time_zone'; +import timeZoneUtils from '../../../utils_time_zone'; import { splitIntervalByDay } from '../../common/split_interval_by_days'; import type { CellInterval, DateInterval } from '../../types'; diff --git a/packages/devextreme/js/__internal/scheduler/view_model/get_appointment_info.ts b/packages/devextreme/js/__internal/scheduler/view_model/get_appointment_info.ts index 58e8c9ccc3d4..6d59ecba0bf3 100644 --- a/packages/devextreme/js/__internal/scheduler/view_model/get_appointment_info.ts +++ b/packages/devextreme/js/__internal/scheduler/view_model/get_appointment_info.ts @@ -1,4 +1,4 @@ -import timeZoneUtils from '../m_utils_time_zone'; +import timeZoneUtils from '../utils_time_zone'; import type { AppointmentAgendaViewModel, AppointmentItemViewModel, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts b/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts index aa83e0941532..59438594a231 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts @@ -73,7 +73,7 @@ import AppointmentDragBehavior from '../m_appointment_drag_behavior'; import { CompactAppointmentsHelper } from '../m_compact_appointments_helper'; import type { SubscribeKey, SubscribeMethods } from '../m_subscribes'; import tableCreatorModule, { type GroupRows } from '../m_table_creator'; -import { utils } from '../m_utils'; +import { utils } from '../utils'; import VerticalShader from '../shaders/current_time_shader_vertical'; import type { ViewCellData } from '../types'; import type { ResourceLoader } from '../utils/loader/resource_loader'; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts index aec079d7d622..4aa823777848 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts @@ -17,7 +17,7 @@ import { GROUP_ROW_CLASS, } from '../classes'; import tableCreatorModule, { type GroupRows } from '../m_table_creator'; -import timezoneUtils from '../m_utils_time_zone'; +import timezoneUtils from '../utils_time_zone'; import HorizontalShader from '../shaders/current_time_shader_horizontal'; import type { ResourceLoader } from '../utils/loader/resource_loader'; import { getFirstVisibleDate } from '../utils/skipped_days'; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_date_header_data_generator.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_date_header_data_generator.ts index 8cd05ceb7e50..fa54720943b1 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_date_header_data_generator.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_date_header_data_generator.ts @@ -1,7 +1,6 @@ import dateUtils from '@js/core/utils/date'; import type { DateHeaderData } from '@ts/scheduler/types'; -import timeZoneUtils from '../../m_utils_time_zone'; import { formatWeekdayAndDay, getDisplayedCellCount, @@ -11,6 +10,7 @@ import { isTimelineView, } from '../../r1/utils/index'; import { VIEWS } from '../../utils/options/constants_view'; +import timeZoneUtils from '../../utils_time_zone'; import type { ViewDataProviderExtendedOptions } from './m_types'; export class DateHeaderDataGenerator { diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_grouped_data_map_provider.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_grouped_data_map_provider.ts index af60dd63d2b4..a5e1f1ebe012 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_grouped_data_map_provider.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_grouped_data_map_provider.ts @@ -2,7 +2,7 @@ import dateUtils from '@js/core/utils/date'; import { dateUtilsTs } from '@ts/core/utils/date'; import { isDateAndTimeView } from '@ts/scheduler/r1/utils/index'; -import timezoneUtils from '../../m_utils_time_zone'; +import timezoneUtils from '../../utils_time_zone'; const toMs = dateUtils.dateToMilliseconds; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator.ts index c853f48e82ed..2b96bb2333e8 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator.ts @@ -3,7 +3,6 @@ import { dateUtilsTs } from '@ts/core/utils/date'; import type { GroupLeaf } from '@ts/scheduler/utils/resource_manager/types'; import { HORIZONTAL_GROUP_ORIENTATION } from '../../constants'; -import timezoneUtils from '../../m_utils_time_zone'; import { calculateCellIndex, calculateDayDuration, @@ -22,6 +21,7 @@ import { getVisibleDaysOfWeek, isDateSkipped, } from '../../utils/skipped_days'; +import timezoneUtils from '../../utils_time_zone'; import type { ViewCellDataSimple, ViewCellGeneratedData, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_month.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_month.ts index 9f979cfa05b1..6370e2dfdc69 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_month.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_month.ts @@ -4,7 +4,7 @@ import { getToday, isFirstCellInMonthWithIntervalCount, monthUtils, setOptionHour, } from '@ts/scheduler/r1/utils/index'; -import timezoneUtils from '../../m_utils_time_zone'; +import timezoneUtils from '../../utils_time_zone'; import type { MonthViewCellDataSimple, ViewDataProviderExtendedOptions } from './m_types'; import { ViewDataGenerator } from './m_view_data_generator'; import { calculateAlignedWeeksBetweenDates } from './utils/view_generator_utils'; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_timeline_month.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_timeline_month.ts index 56a45bd5fd49..f85d5720b3b4 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_timeline_month.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_generator_timeline_month.ts @@ -1,8 +1,8 @@ import dateUtils from '@js/core/utils/date'; import { setOptionHour, timelineMonthUtils } from '@ts/scheduler/r1/utils/index'; -import timezoneUtils from '../../m_utils_time_zone'; import type { CountGenerationConfig } from '../../types'; +import timezoneUtils from '../../utils_time_zone'; import { ViewDataGenerator } from './m_view_data_generator'; const toMs = dateUtils.dateToMilliseconds; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_provider.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_provider.ts index 1189212f074b..d384bbe4016e 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_provider.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_provider.ts @@ -1,7 +1,6 @@ import dateUtils from '@js/core/utils/date'; import { dateUtilsTs } from '@ts/core/utils/date'; -import timeZoneUtils from '../../m_utils_time_zone'; import { calculateIsGroupedAllDayPanel, getGroupPanelData, @@ -18,6 +17,7 @@ import type { ViewDataMap, ViewOptions, ViewType, } from '../../types'; +import timeZoneUtils from '../../utils_time_zone'; import { DateHeaderDataGenerator } from './m_date_header_data_generator'; import { GroupedDataMapProvider } from './m_grouped_data_map_provider'; import { TimePanelDataGenerator } from './m_time_panel_data_generator'; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts index ea640311efaf..f16304fb5f15 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts @@ -10,7 +10,7 @@ import type { OptionChanged } from '@ts/core/widget/types'; import { getToday } from '@ts/scheduler/r1/utils/index'; import { HEADER_CURRENT_TIME_CELL_CLASS } from '../classes'; -import timezoneUtils from '../m_utils_time_zone'; +import timezoneUtils from '../utils_time_zone'; import SchedulerWorkSpace, { type WorkspaceOptionsInternal, } from './m_work_space'; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts index b0b81f198bb8..b66a259fecd4 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts @@ -6,7 +6,7 @@ import { hasWindow } from '@js/core/utils/window'; import { DateTableMonthComponent } from '@ts/scheduler/r1/components/index'; import { formatWeekday, monthUtils } from '@ts/scheduler/r1/utils/index'; -import { utils } from '../m_utils'; +import { utils } from '../utils'; import { VIEWS } from '../utils/options/constants_view'; import type { ViewDateGenerationOptions } from './m_work_space'; import SchedulerWorkSpace from './work_space_indicator'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.methods.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.methods.tests.js index fd3d36810fd9..1da239c9ff7a 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.methods.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.methods.tests.js @@ -3,7 +3,7 @@ import fx from 'common/core/animation/fx'; import { CustomStore } from 'common/data/custom_store'; import { DataSource } from 'common/data/data_source/data_source'; -import timeZoneUtils from '__internal/scheduler/m_utils_time_zone'; +import timeZoneUtils from '__internal/scheduler/utils_time_zone'; import { createWrapper, initTestMarkup } from '../../helpers/scheduler/helpers.js'; import { waitAsync } from '../../helpers/scheduler/waitForAsync.js'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/dataSource.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/dataSource.tests.js index a3855bc24824..22e59ce8282b 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/dataSource.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/dataSource.tests.js @@ -9,7 +9,7 @@ import { DataSource } from 'common/data/data_source/data_source'; import ArrayStore from 'common/data/array_store'; import fx from 'common/core/animation/fx'; import translator from 'common/core/animation/translator'; -import timeZoneUtils from '__internal/scheduler/m_utils_time_zone'; +import timeZoneUtils from '__internal/scheduler/utils_time_zone'; import { CustomStore } from 'common/data/custom_store'; import { noop } from 'core/utils/common'; import dragEvents from 'common/core/events/drag'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentsVertical.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentsVertical.tests.js index ab8112ea4ca0..ebd4b857083d 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentsVertical.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentsVertical.tests.js @@ -7,7 +7,7 @@ import translator from 'common/core/animation/translator'; import fx from 'common/core/animation/fx'; import { DataSource } from 'common/data/data_source/data_source'; import dataUtils from 'core/element_data'; -import timeZoneUtils from '__internal/scheduler/m_utils_time_zone'; +import timeZoneUtils from '__internal/scheduler/utils_time_zone'; import 'fluent_blue_light.css!'; import '__internal/scheduler/m_scheduler'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js index de564fc47ced..a73405cbba06 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js @@ -16,7 +16,7 @@ import { hide } from '__internal/ui/tooltip/m_tooltip'; import { DataSource } from 'common/data/data_source/data_source'; import ArrayStore from 'common/data/array_store'; import dragEvents from 'common/core/events/drag'; -import timeZoneUtils from '__internal/scheduler/m_utils_time_zone'; +import timeZoneUtils from '__internal/scheduler/utils_time_zone'; import 'fluent_blue_light.css!'; From 940b483c9b7642c933205a51f0c5be8f8202e393 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:44:32 +0400 Subject: [PATCH 2/9] refactor(scheduler): rename m_utils and m_utils_time_zone --- .../scheduler/r1/utils/agenda.pacific.test.ts | 8 +- .../r1/utils/agenda.santiago.test.ts | 8 +- .../__internal/scheduler/r1/utils/agenda.ts | 5 +- .../js/__internal/scheduler/utils.ts | 73 ++++ .../__internal/scheduler/utils_time_zone.ts | 349 ++++++++++++++++++ .../view_model/common/get_compare_options.ts | 6 +- .../steps/virtual_screen_filter.ts | 6 +- 7 files changed, 439 insertions(+), 16 deletions(-) create mode 100644 packages/devextreme/js/__internal/scheduler/utils.ts create mode 100644 packages/devextreme/js/__internal/scheduler/utils_time_zone.ts diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts index b208afc7fbb9..221ec0c810cf 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts @@ -4,14 +4,14 @@ import { describe, expect, it } from '@jest/globals'; -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import { calculateRows } from './agenda'; const createDate = (year: number, month: number, day: number, hours: number) => { - const dateUTC = timeZoneUtils.createUTCDateWithLocalOffset( + const date = timeZoneUtils.createUTCDateWithLocalOffset( new Date(year, month, day, hours), - ).getTime(); - return dateUTC; + ); + return date ? date.getTime() : 0; }; describe('calculateRows', () => { diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts index 23f42e32ea0e..5c9a66868afb 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts @@ -4,14 +4,14 @@ import { describe, expect, it } from '@jest/globals'; -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import { calculateRows } from './agenda'; const createDate = (year: number, month: number, day: number, hours: number) => { - const dateUTC = timeZoneUtils.createUTCDateWithLocalOffset( + const date = timeZoneUtils.createUTCDateWithLocalOffset( new Date(year, month, day, hours), - ).getTime(); - return dateUTC; + ); + return date ? date.getTime() : 0; }; describe('calculateRows', () => { diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.ts index c6d475fd17dd..04143ef0adc8 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.ts @@ -1,4 +1,4 @@ -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import type { ListEntity } from '../../view_model/types'; import { setOptionHour } from './base'; @@ -49,7 +49,8 @@ export const calculateRows = ( for (let i = 0; i < agendaDuration; i += 1) { const date = getDateByIndex(startViewDate, i); - const dayStart = getDayStart(timeZoneUtils.createUTCDateWithLocalOffset(date)); + const utcDate = timeZoneUtils.createUTCDateWithLocalOffset(date); + const dayStart = getDayStart(utcDate as Date); intervalsStartMap.set(dayStart, i); } diff --git a/packages/devextreme/js/__internal/scheduler/utils.ts b/packages/devextreme/js/__internal/scheduler/utils.ts new file mode 100644 index 000000000000..3fd18943717e --- /dev/null +++ b/packages/devextreme/js/__internal/scheduler/utils.ts @@ -0,0 +1,73 @@ +import { getPublicElement } from '@js/core/element'; +import type { dxElementWrapper } from '@js/core/renderer'; +import $ from '@js/core/renderer'; +import { getOuterHeight, setHeight, setWidth } from '@js/core/utils/size'; + +import { APPOINTMENT_SETTINGS_KEY } from './constants'; +import type { AppointmentViewModelPlain } from './view_model/types'; + +interface HeaderWithElement { + [key: string]: unknown; +} + +interface RenovationWidget { + [key: string]: unknown; +} + +export const utils = { + dataAccessors: { + getAppointmentSettings: ( + element: Element, + ): AppointmentViewModelPlain | undefined => $(element) + .data(APPOINTMENT_SETTINGS_KEY) as unknown as AppointmentViewModelPlain | undefined, + }, + DOM: { + getHeaderHeight: ( + header: HeaderWithElement | null | undefined, + ): number => { + const $element = header?._$element as + dxElementWrapper | undefined; + return $element + ? parseInt(getOuterHeight($element), 10) + : 0; + }, + }, + renovation: { + renderComponent: ( + widget: RenovationWidget, + parentElement: dxElementWrapper, + componentClass: unknown, + componentName: string, + viewModel: Record, + ): void => { + let component = widget[componentName] as + Record | undefined; + if (!component) { + const container = getPublicElement(parentElement); + const createComponent = widget._createComponent as + Function; + component = createComponent( + container, + componentClass, + viewModel, + ) as Record; + widget[componentName] = component; + } else { + const $element = component.$element() as + dxElementWrapper; + const elementStyle = ($element.get(0) as HTMLElement).style; + const { height } = elementStyle; + const { width } = elementStyle; + + (component.option)(viewModel); + + if (height) { + setHeight($element, height); + } + if (width) { + setWidth($element, width); + } + } + }, + }, +}; diff --git a/packages/devextreme/js/__internal/scheduler/utils_time_zone.ts b/packages/devextreme/js/__internal/scheduler/utils_time_zone.ts new file mode 100644 index 000000000000..ca4dff2d6c41 --- /dev/null +++ b/packages/devextreme/js/__internal/scheduler/utils_time_zone.ts @@ -0,0 +1,349 @@ +// TODO(Refactoring): move this module to ./utils directory +import errors from '@js/core/errors'; +import { dateUtilsTs } from '@ts/core/utils/date'; +import { macroTaskArray } from '@ts/scheduler/utils/index'; + +import dateUtils from '../../core/utils/date'; +import { globalCache } from './global_cache'; +import timeZoneList from './timezones/timezone_list'; + +export interface TimezoneLabel { + /** uniq timezone id, e.g: 'America/Los_Angeles' */ + id: string; + /** timezone display string, e.g: '(GMT -08:00) America - Los Angeles' */ + title?: string; +} + +export interface TimezoneData extends TimezoneLabel { + /** timezone offset in hours */ + offset?: number; +} + +const timeZoneListSet = new Set(timeZoneList.value); +const toMs = dateUtils.dateToMilliseconds; +const MINUTES_IN_HOUR = 60; +const MS_IN_MINUTE = 60000; +const GMT = 'GMT'; +const offsetFormatRegexp = /^GMT(?:[+-]\d{2}:\d{2})?$/; + +const createUTCDateWithLocalOffset = (date: Date | null | undefined): Date | null | undefined => { + if (!date) { + return date; + } + + return new Date(Date.UTC( + date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + )); +}; + +const createDateFromUTCWithLocalOffset = (date: Date): Date => new Date( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds(), +); + +const getDaylightOffset = ( + startDate: Date | number, + endDate: Date | number, +): number => new Date(startDate).getTimezoneOffset() - new Date(endDate).getTimezoneOffset(); + +const getDaylightOffsetInMs = ( + startDate: Date | number, + endDate: Date | number, +): number => getDaylightOffset(startDate, endDate) * toMs('minute'); + +const getTimezoneOffsetChangeInMinutes = ( + startDate: Date, + endDate: Date, + updatedStartDate: Date, + updatedEndDate: Date, +): number => getDaylightOffset(updatedStartDate, updatedEndDate) - getDaylightOffset( + startDate, + endDate, +); + +const getTimezoneOffsetChangeInMs = ( + startDate: Date, + endDate: Date, + updatedStartDate: Date, + updatedEndDate: Date, +): number => { + const minutes = getTimezoneOffsetChangeInMinutes( + startDate, + endDate, + updatedStartDate, + updatedEndDate, + ); + return minutes * toMs('minute'); +}; + +// 'GMT±XX:YY' or 'GMT' format +const getStringOffset = (timeZone: string, date = new Date()): string | undefined => { + let result = ''; + try { + const dateTimeFormat = globalCache.timezones.memo( + `intl${timeZone}`, + () => new Intl.DateTimeFormat('en-US', { + timeZone, + timeZoneName: 'longOffset', + }), + ); + + result = dateTimeFormat + .formatToParts(date) + .find(({ type }) => type === 'timeZoneName')?.value ?? ''; + } catch (e) { + errors.log('W0009', timeZone); + return undefined; + } + + const isSupportedFormat = offsetFormatRegexp.test(result); + if (!isSupportedFormat) { + errors.log('W0009', timeZone); + return undefined; + } + + return result; +}; + +const calculateTimezoneByValueCore = (timeZone: string, date = new Date()): number | undefined => { + const offset = getStringOffset(timeZone, date); + + if (offset === undefined) { + return undefined; + } + + if (offset === GMT) { + return 0; + } + + const isMinus = offset.substring(3, 4) === '-'; + const hours = offset.substring(4, 6); + const minutes = offset.substring(7, 9); + + const result = parseInt(hours, 10) + parseInt(minutes, 10) / MINUTES_IN_HOUR; + return isMinus ? -result : result; +}; + +const getMachineTimezoneName = (): string | null => globalCache.timezones.memo( + 'localTimezone', + () => dateUtils.getMachineTimezoneName(), +); + +const isEqualLocalTimeZone = (timeZoneName: string): boolean => { + const localTimeZoneName = getMachineTimezoneName(); + if (localTimeZoneName && localTimeZoneName === timeZoneName) { + return true; + } + return false; +}; + +const calculateTimezoneByValue = ( + timeZone: string | undefined, + date: Date | number = new Date(), +): number | undefined => { + if (!timeZone) { + return undefined; + } + + const isValidTimezone = timeZoneListSet.has(timeZone); + if (!isValidTimezone) { + errors.log('W0009', timeZone); + return undefined; + } + + const dateObj = new Date(date); + if (!dateUtilsTs.isValidDate(dateObj)) { + return undefined; + } + + if (isEqualLocalTimeZone(timeZone)) { + return -dateObj.getTimezoneOffset() / MINUTES_IN_HOUR; + } + + return calculateTimezoneByValueCore(timeZone, dateObj); +}; + +const getOffsetNamePart = (offset: string): string => { + if (offset === GMT) { + return `${offset} +00:00`; + } + + return offset.replace(GMT, `${GMT} `); +}; + +const getTimezoneTitle = (timeZone: string, date = new Date()): string | undefined => { + if (!dateUtilsTs.isValidDate(date)) { + return ''; + } + + const tzNamePart = timeZone.replace(/\//g, ' - ').replace(/_/g, ' '); + const offset = getStringOffset(timeZone, date); + if (offset === undefined) { + return undefined; + } + + const offsetNamePart = getOffsetNamePart(offset); + return `(${offsetNamePart}) ${tzNamePart}`; +}; + +// eslint-disable-next-line @typescript-eslint/naming-convention +const _getDaylightOffsetByTimezone = (startDate: Date, endDate: Date, timeZone: string): number => { + const startDayOffset = calculateTimezoneByValue(timeZone, startDate); + const endDayOffset = calculateTimezoneByValue(timeZone, endDate); + if (startDayOffset === undefined || endDayOffset === undefined) { + return 0; + } + + return startDayOffset - endDayOffset; +}; + +const getCorrectedDateByDaylightOffsets = ( + convertedOriginalStartDate: Date, + convertedDate: Date, + date: Date, + timeZone: string, + startDateTimezone: string, +): Date => { + const daylightOffsetByCommonTimezone = _getDaylightOffsetByTimezone( + convertedOriginalStartDate, + convertedDate, + timeZone, + ); + const daylightOffsetByAppointmentTimezone = _getDaylightOffsetByTimezone( + convertedOriginalStartDate, + convertedDate, + startDateTimezone, + ); + const diff = daylightOffsetByCommonTimezone - daylightOffsetByAppointmentTimezone; + + return new Date(date.getTime() - diff * toMs('hour')); +}; + +const correctRecurrenceExceptionByTimezone = ( + exception: Date, + exceptionByStartDate: Date, +): Date => { + const timezoneOffset = (exception.getTimezoneOffset() - exceptionByStartDate.getTimezoneOffset()) + / MINUTES_IN_HOUR; + + return new Date(exception.getTime() + timezoneOffset * toMs('hour')); +}; + +const isTimezoneChangeInDate = (date: Date | number): boolean => { + const startDayDate = new Date(new Date(date).setHours(0, 0, 0, 0)); + const endDayDate = new Date(new Date(date).setHours(23, 59, 59, 0)); + return (startDayDate.getTimezoneOffset() - endDayDate.getTimezoneOffset()) !== 0; +}; + +const getDateWithoutTimezoneChange = (date: Date | number): Date => { + const clonedDate = new Date(date); + if (isTimezoneChangeInDate(clonedDate)) { + const result = new Date(clonedDate); + return new Date(result.setDate(result.getDate() + 1)); + } + return clonedDate; +}; + +const isSameAppointmentDates = (startDate: Date, endDate: Date): boolean => { + // NOTE: subtract 1 millisecond to avoid 00.00 time. Method should return 'true' for + // "2020:10:10 22:00:00" and "2020:10:11 00:00:00", for example. + const adjustedEndDate = new Date(endDate.getTime() - 1); + + return dateUtils.sameDate(startDate, adjustedEndDate); +}; + +const getClientTimezoneOffset = (date = new Date()): number => date.getTimezoneOffset() +* MS_IN_MINUTE; + +const getDiffBetweenClientTimezoneOffsets = ( + firstDate = new Date(), + secondDate = new Date(), +): number => getClientTimezoneOffset(firstDate) - getClientTimezoneOffset(secondDate); + +const addOffsetsWithoutDST = (date: Date, ...offsets: number[]): Date => { + const newDate = dateUtilsTs.addOffsets(date, ...offsets); + const daylightShift = getDaylightOffsetInMs(date, newDate); + + if (!daylightShift) { + return newDate; + } + + const correctLocalDate = dateUtilsTs.addOffsets(newDate, -daylightShift); + const daylightSecondShift = getDaylightOffsetInMs(newDate, correctLocalDate); + + return !daylightSecondShift + ? correctLocalDate + : newDate; +}; + +const getTimeZones = ( + date = new Date(), + timeZones = timeZoneList.value, +): TimezoneData[] => timeZones.map((timezoneId) => ({ + id: timezoneId, + title: getTimezoneTitle(timezoneId, date), + offset: calculateTimezoneByValue(timezoneId, date), +})); + +const GET_TIMEZONES_BATCH_SIZE = 10; +const cacheTimeZones = async (): Promise => globalCache.timezones.memo( + 'timeZonesCachePromise', + () => macroTaskArray + .map( + timeZoneList.value, + (timezoneId) => ({ + id: timezoneId, + title: getTimezoneTitle(timezoneId, new Date()), + }), + GET_TIMEZONES_BATCH_SIZE, + ) + .then((data) => globalCache.timezones.memo('timeZonesCache', () => data)), +); + +const getTimeZonesCache = (): TimezoneLabel[] => globalCache.timezones.get('timeZonesCache') ?? []; + +const isLocalTimeMidnightDST = (date: Date): boolean => { + const startDayDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + + return startDayDate.getHours() === 1; +}; + +const utils = { + getDaylightOffset, + getDaylightOffsetInMs, + getTimezoneOffsetChangeInMinutes, + getTimezoneOffsetChangeInMs, + calculateTimezoneByValue, + getCorrectedDateByDaylightOffsets, + isSameAppointmentDates, + correctRecurrenceExceptionByTimezone, + getClientTimezoneOffset, + getDiffBetweenClientTimezoneOffsets, + + createUTCDateWithLocalOffset, + createDateFromUTCWithLocalOffset, + + isTimezoneChangeInDate, + getDateWithoutTimezoneChange, + getMachineTimezoneName, + isEqualLocalTimeZone, + + addOffsetsWithoutDST, + + getTimeZones, + getTimeZonesCache, + cacheTimeZones, + + isLocalTimeMidnightDST, +}; + +export default utils; diff --git a/packages/devextreme/js/__internal/scheduler/view_model/common/get_compare_options.ts b/packages/devextreme/js/__internal/scheduler/view_model/common/get_compare_options.ts index 203db8f64802..6fbd9b9b0391 100644 --- a/packages/devextreme/js/__internal/scheduler/view_model/common/get_compare_options.ts +++ b/packages/devextreme/js/__internal/scheduler/view_model/common/get_compare_options.ts @@ -1,5 +1,5 @@ import type Scheduler from '../../m_scheduler'; -import timeZoneUtils from '../../m_utils_time_zone'; +import timeZoneUtils from '../../utils_time_zone'; import type { CompareOptions } from '../types'; export const getCompareOptions = ( @@ -10,8 +10,8 @@ export const getCompareOptions = ( const compareOptions = { startDayHour: schedulerStore.getViewOption('startDayHour'), endDayHour: schedulerStore.getViewOption('endDayHour'), - min: timeZoneUtils.createUTCDateWithLocalOffset(dateRange[0]).getTime(), - max: timeZoneUtils.createUTCDateWithLocalOffset(dateRange[1]).getTime(), + min: (timeZoneUtils.createUTCDateWithLocalOffset(dateRange[0]) as Date).getTime(), + max: (timeZoneUtils.createUTCDateWithLocalOffset(dateRange[1]) as Date).getTime(), skippedDays: schedulerStore.getViewOption('hiddenWeekDays') as number[], }; diff --git a/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/steps/virtual_screen_filter.ts b/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/steps/virtual_screen_filter.ts index 1afd763e3c00..9f440bd72b38 100644 --- a/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/steps/virtual_screen_filter.ts +++ b/packages/devextreme/js/__internal/scheduler/view_model/generate_view_model/steps/virtual_screen_filter.ts @@ -1,4 +1,4 @@ -import timeZoneUtils from '../../../m_utils_time_zone'; +import timeZoneUtils from '../../../utils_time_zone'; import type ViewDataProvider from '../../../workspaces/view_model/m_view_data_provider'; import { isAppointmentMatchedIntervals } from '../../common/is_appointment_matched_intervals'; import type { ListEntity } from '../../types'; @@ -16,8 +16,8 @@ export const filterByVirtualScreen = ( const groupIntervalsMap = new Map(); groupsInfo.forEach((group) => { groupIntervalsMap.set(group.groupIndex, { - min: timeZoneUtils.createUTCDateWithLocalOffset(group.startDate).getTime(), - max: timeZoneUtils.createUTCDateWithLocalOffset(group.endDate).getTime(), + min: (timeZoneUtils.createUTCDateWithLocalOffset(group.startDate) as Date).getTime(), + max: (timeZoneUtils.createUTCDateWithLocalOffset(group.endDate) as Date).getTime(), }); }); From 7050013eaeb13e202b5d64eff6d856b8c5f7c3d7 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:04:17 +0400 Subject: [PATCH 3/9] fix(scheduler): use unknown params in utils to accept class instances --- .../js/__internal/scheduler/utils.ts | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/utils.ts b/packages/devextreme/js/__internal/scheduler/utils.ts index 3fd18943717e..83953f5343e5 100644 --- a/packages/devextreme/js/__internal/scheduler/utils.ts +++ b/packages/devextreme/js/__internal/scheduler/utils.ts @@ -6,27 +6,17 @@ import { getOuterHeight, setHeight, setWidth } from '@js/core/utils/size'; import { APPOINTMENT_SETTINGS_KEY } from './constants'; import type { AppointmentViewModelPlain } from './view_model/types'; -interface HeaderWithElement { - [key: string]: unknown; -} - -interface RenovationWidget { - [key: string]: unknown; -} - export const utils = { dataAccessors: { getAppointmentSettings: ( - element: Element, - ): AppointmentViewModelPlain | undefined => $(element) + element: unknown, + ): AppointmentViewModelPlain | undefined => $(element as Element) .data(APPOINTMENT_SETTINGS_KEY) as unknown as AppointmentViewModelPlain | undefined, }, DOM: { - getHeaderHeight: ( - header: HeaderWithElement | null | undefined, - ): number => { - const $element = header?._$element as - dxElementWrapper | undefined; + getHeaderHeight: (header: unknown): number => { + const $element = (header as Record) + ?._$element as dxElementWrapper | undefined; return $element ? parseInt(getOuterHeight($element), 10) : 0; @@ -34,28 +24,30 @@ export const utils = { }, renovation: { renderComponent: ( - widget: RenovationWidget, + widget: unknown, parentElement: dxElementWrapper, componentClass: unknown, componentName: string, viewModel: Record, ): void => { - let component = widget[componentName] as + const w = widget as Record; + let component = w[componentName] as Record | undefined; if (!component) { const container = getPublicElement(parentElement); - const createComponent = widget._createComponent as - Function; + const createComponent = w._createComponent as Function; component = createComponent( container, componentClass, viewModel, ) as Record; - widget[componentName] = component; + w[componentName] = component; } else { const $element = component.$element() as dxElementWrapper; - const elementStyle = ($element.get(0) as HTMLElement).style; + const elementStyle = ( + $element.get(0) as HTMLElement + ).style; const { height } = elementStyle; const { width } = elementStyle; From a032aba21b01a140312624e505c172275d5c58ea Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:11:56 +0400 Subject: [PATCH 4/9] fix(scheduler): resolve build errors and review feedback --- .../js/__internal/scheduler/r1/utils/agenda.pacific.test.ts | 4 ++-- .../js/__internal/scheduler/r1/utils/agenda.santiago.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts index 221ec0c810cf..d3b2f56c1d6b 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.pacific.test.ts @@ -10,8 +10,8 @@ import { calculateRows } from './agenda'; const createDate = (year: number, month: number, day: number, hours: number) => { const date = timeZoneUtils.createUTCDateWithLocalOffset( new Date(year, month, day, hours), - ); - return date ? date.getTime() : 0; + ) as Date; + return date.getTime(); }; describe('calculateRows', () => { diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts index 5c9a66868afb..33eacd3b0242 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/agenda.santiago.test.ts @@ -10,8 +10,8 @@ import { calculateRows } from './agenda'; const createDate = (year: number, month: number, day: number, hours: number) => { const date = timeZoneUtils.createUTCDateWithLocalOffset( new Date(year, month, day, hours), - ); - return date ? date.getTime() : 0; + ) as Date; + return date.getTime(); }; describe('calculateRows', () => { From 77c88503e4656bf58c979253ec3f5ecf920e693d Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:25:44 +0400 Subject: [PATCH 5/9] fix(scheduler): update missed import in public API re-export --- .../devextreme/js/common/core/environment/time_zone_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devextreme/js/common/core/environment/time_zone_utils.js b/packages/devextreme/js/common/core/environment/time_zone_utils.js index 4bbab0e11a5e..d27b4e7dc42a 100644 --- a/packages/devextreme/js/common/core/environment/time_zone_utils.js +++ b/packages/devextreme/js/common/core/environment/time_zone_utils.js @@ -1,3 +1,3 @@ -import timeZoneUtils from '../../../__internal/scheduler/m_utils_time_zone'; +import timeZoneUtils from '../../../__internal/scheduler/utils_time_zone'; export const getTimeZones = timeZoneUtils.getTimeZones; From ffc51b289236348423efba74ac26b053404ab01d Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:07:21 +0400 Subject: [PATCH 6/9] fix(scheduler): preserve original logic in utils renderComponent --- .../js/__internal/scheduler/utils.ts | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/utils.ts b/packages/devextreme/js/__internal/scheduler/utils.ts index 83953f5343e5..f2536284d39c 100644 --- a/packages/devextreme/js/__internal/scheduler/utils.ts +++ b/packages/devextreme/js/__internal/scheduler/utils.ts @@ -15,10 +15,9 @@ export const utils = { }, DOM: { getHeaderHeight: (header: unknown): number => { - const $element = (header as Record) - ?._$element as dxElementWrapper | undefined; - return $element - ? parseInt(getOuterHeight($element), 10) + const h = header as Record | null | undefined; + return h?._$element + ? parseInt(getOuterHeight(h._$element as dxElementWrapper), 10) : 0; }, }, @@ -30,28 +29,20 @@ export const utils = { componentName: string, viewModel: Record, ): void => { - const w = widget as Record; - let component = w[componentName] as - Record | undefined; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const w = widget as any; + let component = w[componentName]; if (!component) { const container = getPublicElement(parentElement); - const createComponent = w._createComponent as Function; - component = createComponent( - container, - componentClass, - viewModel, - ) as Record; + component = w._createComponent(container, componentClass, viewModel); w[componentName] = component; } else { - const $element = component.$element() as - dxElementWrapper; - const elementStyle = ( - $element.get(0) as HTMLElement - ).style; + const $element = component.$element() as dxElementWrapper; + const elementStyle = ($element.get(0) as HTMLElement).style; const { height } = elementStyle; const { width } = elementStyle; - (component.option)(viewModel); + component.option(viewModel); if (height) { setHeight($element, height); From c4a3fce220c7f5dafcfa575382cd3a00df66a730 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Thu, 4 Jun 2026 19:46:47 +0400 Subject: [PATCH 7/9] fix(scheduler): type getAppointmentSettings param as dxElementWrapper --- packages/devextreme/js/__internal/scheduler/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/utils.ts b/packages/devextreme/js/__internal/scheduler/utils.ts index f2536284d39c..8c9e22196cd2 100644 --- a/packages/devextreme/js/__internal/scheduler/utils.ts +++ b/packages/devextreme/js/__internal/scheduler/utils.ts @@ -9,8 +9,8 @@ import type { AppointmentViewModelPlain } from './view_model/types'; export const utils = { dataAccessors: { getAppointmentSettings: ( - element: unknown, - ): AppointmentViewModelPlain | undefined => $(element as Element) + element: dxElementWrapper, + ): AppointmentViewModelPlain | undefined => $(element) .data(APPOINTMENT_SETTINGS_KEY) as unknown as AppointmentViewModelPlain | undefined, }, DOM: { From fa080ddb847be89872600f7e7a13c6380714257f Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:33:38 +0400 Subject: [PATCH 8/9] fix(scheduler): sort imports in workspace files --- .../js/__internal/scheduler/workspaces/m_work_space.ts | 2 +- .../devextreme/js/__internal/scheduler/workspaces/timeline.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts b/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts index 59438594a231..90884d0a8a8e 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts @@ -73,9 +73,9 @@ import AppointmentDragBehavior from '../m_appointment_drag_behavior'; import { CompactAppointmentsHelper } from '../m_compact_appointments_helper'; import type { SubscribeKey, SubscribeMethods } from '../m_subscribes'; import tableCreatorModule, { type GroupRows } from '../m_table_creator'; -import { utils } from '../utils'; import VerticalShader from '../shaders/current_time_shader_vertical'; import type { ViewCellData } from '../types'; +import { utils } from '../utils'; import type { ResourceLoader } from '../utils/loader/resource_loader'; import { getAppointmentGroupIndex, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts index 4aa823777848..a847ee8da4a0 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts @@ -17,10 +17,10 @@ import { GROUP_ROW_CLASS, } from '../classes'; import tableCreatorModule, { type GroupRows } from '../m_table_creator'; -import timezoneUtils from '../utils_time_zone'; import HorizontalShader from '../shaders/current_time_shader_horizontal'; import type { ResourceLoader } from '../utils/loader/resource_loader'; import { getFirstVisibleDate } from '../utils/skipped_days'; +import timezoneUtils from '../utils_time_zone'; import type { WorkspaceOptionsInternal } from './m_work_space'; import type { ViewDataProviderOptions } from './view_model/m_types'; import SchedulerWorkSpace from './work_space_indicator'; From 79775cbd2755e5a22749314cc4f993996d124321 Mon Sep 17 00:00:00 2001 From: Maksim Zakharov <251575087+bit-byte0@users.noreply.github.com> Date: Fri, 5 Jun 2026 19:37:32 +0400 Subject: [PATCH 9/9] fix(scheduler): sort imports in appointment_collection and base --- .../scheduler/appointments/m_appointment_collection.ts | 2 +- packages/devextreme/js/__internal/scheduler/r1/utils/base.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts index a27cab8d43dd..26add8462075 100644 --- a/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts +++ b/packages/devextreme/js/__internal/scheduler/appointments/m_appointment_collection.ts @@ -27,7 +27,6 @@ import { APPOINTMENT_ITEM_CLASS, } from '../classes'; import { APPOINTMENT_SETTINGS_KEY } from '../constants'; -import timeZoneUtils from '../utils_time_zone'; import type { CompactAppointmentOptions } from '../types'; import { AppointmentAdapter } from '../utils/appointment_adapter/appointment_adapter'; import type { AppointmentDataAccessor } from '../utils/data_accessor/appointment_data_accessor'; @@ -38,6 +37,7 @@ import { import { getAppointmentGroupValues } from '../utils/resource_manager/appointment_groups_utils'; import { getGroupTexts } from '../utils/resource_manager/group_utils'; import type { ResourceManager } from '../utils/resource_manager/resource_manager'; +import timeZoneUtils from '../utils_time_zone'; import type { AppointmentAgendaViewModel, AppointmentCollectorViewModel, diff --git a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts index bcb7457a933d..6282960638dc 100644 --- a/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts +++ b/packages/devextreme/js/__internal/scheduler/r1/utils/base.ts @@ -7,7 +7,6 @@ import { VERTICAL_GROUP_COUNT_CLASSES } from '../../classes'; import { HORIZONTAL_GROUP_ORIENTATION, VERTICAL_GROUP_ORIENTATION, } from '../../constants'; -import timeZoneUtils from '../../utils_time_zone'; import type { AllDayPanelModeType, AppointmentGeometry, @@ -24,6 +23,7 @@ import type { import type { ResourceLoader } from '../../utils/loader/resource_loader'; import type { ResourceId } from '../../utils/loader/types'; import { VIEWS } from '../../utils/options/constants_view'; +import timeZoneUtils from '../../utils_time_zone'; const toMs = dateUtils.dateToMilliseconds; const DAY_HOURS = 24;