From 787701d307c887404000f7987b793496677f2d31 Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Wed, 4 Sep 2024 23:20:21 +0500 Subject: [PATCH 1/6] dropDown added --- .../src/comps/comps/dateComp/dateComp.tsx | 9 +++++++ .../src/comps/comps/dateComp/timeComp.tsx | 10 ++++++- .../src/comps/comps/dateComp/timeZone.ts | 27 +++++++++++++++++++ .../packages/lowcoder/src/i18n/locales/en.ts | 1 + 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx index 8e22ee7bf..8e6bc7957 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx @@ -48,6 +48,8 @@ import { RefControl } from "comps/controls/refControl"; // import { CommonPickerMethods } from "antd/es/date-picker/generatePicker/interface"; import { DateRangeUIView } from "comps/comps/dateComp/dateRangeUIView"; import { EditorContext } from "comps/editorState"; +import { dropdownControl } from "comps/controls/dropdownControl"; +import { timeZoneOptions } from "./timeZone"; const EventOptions = [changeEvent, focusEvent, blurEvent] as const; @@ -80,6 +82,7 @@ const commonChildren = { ...validationChildren, viewRef: RefControl, inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'), + timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"), }; type CommonChildrenType = RecordConstructorToComp; @@ -224,6 +227,9 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => { placeholder: "2022-04-07 21:39:59", tooltip: trans("date.formatTip") })} + {children.timeZone.propertyView({ + label: trans("prop.timeZone") + })} @@ -380,6 +386,9 @@ export const dateRangeControl = (function () { placeholder: "2022-04-07 21:39:59", tooltip: trans("date.formatTip"), })} + {children.timeZone.propertyView({ + label: trans("prop.timeZone") + })} diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx index c362e01b7..07dbf9bbf 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx @@ -52,6 +52,8 @@ import { RefControl } from "comps/controls/refControl"; import { TimePickerProps } from "antd/es/time-picker"; import { EditorContext } from "comps/editorState"; +import { dropdownControl } from "comps/controls/dropdownControl"; +import { timeZoneOptions } from "./timeZone"; const EventOptions = [changeEvent, focusEvent, blurEvent] as const; @@ -81,6 +83,7 @@ const commonChildren = { ), inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'), suffixIcon: withDefault(IconControl, "/icon:regular/clock"), + timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"), viewRef: RefControl, ...validationChildren, }; @@ -196,7 +199,9 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => { label: trans("prop.defaultValue"), tooltip: trans("time.formatTip"), })} - + {children.timeZone.propertyView({ + label: trans("prop.timeZone") + })} @@ -336,6 +341,9 @@ export const timeRangeControl = (function () { label: trans("time.end"), tooltip: trans("time.formatTip"), })} + {children.timeZone.propertyView({ + label: trans("prop.timeZone") + })} diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts new file mode 100644 index 000000000..759247730 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts @@ -0,0 +1,27 @@ +export const timeZoneOptions = [ + { label: "(UTC-12:00) International Date Line West", value: "DatelineStandard" }, + { label: "(UTC-11:00) Coordinated Universal Time-11", value: "UTC11" }, + { label: "(UTC-10:00) Hawaii", value: "HawaiianStandard" }, + { label: "(UTC-09:00) Alaska", value: "AlaskanStandard" }, + { label: "(UTC-08:00) Baja California", value: "PacificStandardMexico" }, + { label: "(UTC-07:00) Pacific Daylight Time (US & Canada)", value: "PacificDaylight" }, + { label: "(UTC-06:00) Central Time (US & Canada)", value: "CentralStandard" }, + { label: "(UTC-05:00) Eastern Time (US & Canada)", value: "EasternStandard" }, + { label: "(UTC-04:00) Atlantic Time (Canada)", value: "AtlanticStandard" }, + { label: "(UTC-03:00) Buenos Aires", value: "ArgentinaStandard" }, + { label: "(UTC-02:00) Coordinated Universal Time-02", value: "UTC02" }, + { label: "(UTC-01:00) Cape Verde Is.", value: "CapeVerdeStandard" }, + { label: "(UTC+00:00) Coordinated Universal Time", value: "UTC" }, + { label: "(UTC+01:00) Amsterdam, Berlin, Rome, Vienna", value: "WEuropeStandard" }, + { label: "(UTC+02:00) Athens, Bucharest", value: "GTBStandard" }, + { label: "(UTC+03:00) Moscow, St. Petersburg", value: "MoscowStandard" }, + { label: "(UTC+04:00) Abu Dhabi, Muscat", value: "ArabianStandard" }, + { label: "(UTC+05:00) Islamabad, Karachi", value: "PakistanStandard" }, + { label: "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", value: "IndiaStandard" }, + { label: "(UTC+06:00) Dhaka", value: "BangladeshStandard" }, + { label: "(UTC+07:00) Bangkok, Hanoi, Jakarta", value: "SEAsiaStandard" }, + { label: "(UTC+08:00) Beijing, Chongqing, Hong Kong", value: "ChinaStandard" }, + { label: "(UTC+09:00) Tokyo, Seoul", value: "JapanStandard" }, + { label: "(UTC+10:00) Sydney, Melbourne", value: "AUSEasternStandard" }, + { label: "User Choice", value: "UserChoice" }, +]; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 8c1069710..55479020a 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -222,6 +222,7 @@ export const en = { "horizontalGridCells": "Horizontal Grid Cells", "showHorizontalScrollbar": "Show Horizontal Scrollbar", "showVerticalScrollbar": "Show Vertical Scrollbar", + "timeZone": "TimeZone", }, "autoHeightProp": { "auto": "Auto", From e31ceba495eee6052adf542eac415375b8bed8c9 Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Thu, 5 Sep 2024 01:06:20 +0500 Subject: [PATCH 2/6] timeZone values added in modals --- .../comps/comps/dateComp/dateRangeUIView.tsx | 23 ++++++++++++++++++- .../src/comps/comps/dateComp/dateUIView.tsx | 23 +++++++++++++++++++ .../comps/comps/dateComp/timeRangeUIView.tsx | 18 +++++++++++++++ .../src/comps/comps/dateComp/timeUIView.tsx | 20 +++++++++++++++- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx index d31a7980a..fe7539104 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx @@ -11,6 +11,8 @@ import { default as DatePicker } from "antd/es/date-picker"; import { hasIcon } from "comps/utils"; import { omit } from "lodash"; import { DateParser } from "@lowcoder-ee/util/dateTimeUtils"; +import { default as AntdSelect } from "antd/es/select"; +import { timeZoneOptions } from "./timeZone"; const { RangePicker } = DatePicker; @@ -21,6 +23,17 @@ const RangePickerStyled = styled(RangePicker)<{$style: DateTimeStyleType}>` ${(props) => props.$style && getStyle(props.$style)} `; +const StyledAntdSelect = styled(AntdSelect)` + width: 400px; + margin: 10px 0px; + .ant-select-selector { + font-size: 14px; + line-height: 1.5; + } +`; +const StyledDiv = styled.div` + text-align: center; +`; const DateRangeMobileUIView = React.lazy(() => import("./dateMobileUIView").then((m) => ({ default: m.DateRangeMobileUIView })) ); @@ -44,7 +57,6 @@ export const DateRangeUIView = (props: DateRangeUIViewProps) => { // Use the same placeholder for both start and end if it's a single string placeholders = [props.placeholder || 'Start Date', props.placeholder || 'End Date']; } - return useUIView( , { hourStep={props.hourStep as any} minuteStep={props.minuteStep as any} secondStep={props.secondStep as any} + renderExtraFooter={() => ( + + {console.log("handleTimeZoneChange")}} + /> + + )} /> ); }; diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx index 58310258e..766ce1664 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx @@ -11,6 +11,8 @@ import { default as DatePicker } from "antd/es/date-picker"; import type { DatePickerProps } from "antd/es/date-picker"; import type { Dayjs } from 'dayjs'; import { DateParser } from "@lowcoder-ee/util/dateTimeUtils"; +import { timeZoneOptions } from "./timeZone"; +import { default as AntdSelect } from "antd/es/select"; const DatePickerStyled = styled(DatePicker)<{ $style: DateTimeStyleType }>` width: 100%; @@ -18,6 +20,18 @@ const DatePickerStyled = styled(DatePicker)<{ $style: DateTimeStyleType } ${(props) => props.$style && getStyle(props.$style)} `; +const StyledDiv = styled.div` + width: 100%; + margin: 10px 0px; +`; + +const StyledAntdSelect = styled(AntdSelect)` + width: 100%; + .ant-select-selector { + font-size: 14px; + line-height: 1.5; + } +`; export interface DataUIViewProps extends DateCompViewProps { value?: DatePickerProps['value']; @@ -48,6 +62,15 @@ export const DateUIView = (props: DataUIViewProps) => { picker={"date"} inputReadOnly={checkIsMobile(editorState?.getAppSettings().maxWidth)} placeholder={placeholder} + renderExtraFooter={()=>( + + {console.log("DatePickerStyled")}} + /> + + )} /> ); }; diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx index a4a36ae68..c351d7a21 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx @@ -10,6 +10,8 @@ import { EditorContext } from "../../editorState"; import dayjs from "dayjs"; import { hasIcon } from "comps/utils"; import { omit } from "lodash"; +import { timeZoneOptions } from "./timeZone"; +import { default as AntdSelect } from "antd/es/select"; const { RangePicker } = TimePicker; @@ -18,6 +20,15 @@ const RangePickerStyled = styled((props: any) => )<{ $ ${(props) => props.$style && getStyle(props.$style)} `; +const StyledAntdSelect = styled(AntdSelect)` + width: 100%; + margin: 10px 0px; + .ant-select-selector { + font-size: 14px; + line-height: 1.5; + } +`; + const TimeRangeMobileUIView = React.lazy(() => import("./timeMobileUIView").then((m) => ({ default: m.TimeRangeMobileUIView })) ); @@ -54,6 +65,13 @@ export const TimeRangeUIView = (props: TimeRangeUIViewProps) => { inputReadOnly={checkIsMobile(editorState?.getAppSettings().maxWidth)} suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} placeholder={placeholders} + renderExtraFooter={() => ( + {console.log("handleTimeZoneChange")}} + /> + )} /> ); }; diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx index 5c51d12ab..abf6f679f 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx @@ -8,6 +8,8 @@ import React, { useContext } from "react"; import type { TimeCompViewProps } from "./timeComp"; import { EditorContext } from "../../editorState"; import dayjs from "dayjs" +import { default as AntdSelect } from "antd/es/select"; +import { timeZoneOptions } from "./timeZone"; const TimePickerStyled = styled(TimePicker)<{ $style: DateTimeStyleType }>` width: 100%; @@ -17,6 +19,15 @@ const TimePickerStyled = styled(TimePicker)<{ $style: DateTimeStyleType }>` const TimeMobileUIView = React.lazy(() => import("./timeMobileUIView").then((m) => ({ default: m.TimeMobileUIView })) ); + +const StyledAntdSelect = styled(AntdSelect)` + width: 100%; + margin: 10px 0; + .ant-select-selector { + font-size: 14px; + padding: 8px; + } +`; export interface TimeUIViewProps extends TimeCompViewProps { value: dayjs.Dayjs | null; @@ -36,6 +47,13 @@ export const TimeUIView = (props: TimeUIViewProps) => { hideDisabledOptions inputReadOnly={checkIsMobile(editorState?.getAppSettings().maxWidth)} placeholder={placeholder} - /> + renderExtraFooter={()=>( + {console.log("handleTimeZoneChange")}} + /> + )} + /> ); }; From 8725cf7bdc87ce870bca4de58c9266dded091cdd Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Thu, 5 Sep 2024 01:29:27 +0500 Subject: [PATCH 3/6] condition added --- .../src/comps/comps/dateComp/dateComp.tsx | 3 +++ .../src/comps/comps/dateComp/dateRangeUIView.tsx | 16 +++++++++------- .../src/comps/comps/dateComp/dateUIView.tsx | 14 ++++++++------ .../src/comps/comps/dateComp/timeComp.tsx | 6 ++++-- .../src/comps/comps/dateComp/timeRangeUIView.tsx | 6 ++++-- .../src/comps/comps/dateComp/timeUIView.tsx | 2 ++ 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx index 8e6bc7957..afc194502 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx @@ -156,6 +156,7 @@ export type DateCompViewProps = Pick< | "minuteStep" | "secondStep" | "viewRef" + | "timeZone" > & { onFocus: () => void; onBlur: () => void; @@ -187,6 +188,7 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => { onMouseDown: (e) => e.stopPropagation(), children: ( disabledTime(props.minTime, props.maxTime)} $style={props.inputFieldStyle} @@ -323,6 +325,7 @@ export const dateRangeControl = (function () { const children = ( { minuteStep={props.minuteStep as any} secondStep={props.secondStep as any} renderExtraFooter={() => ( - - {console.log("handleTimeZoneChange")}} - /> - + props.timeZone === "UserChoice" && ( + + {console.log("handleTimeZoneChange")}} + /> + + ) )} /> ); diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx index 766ce1664..e4f58abe7 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx @@ -63,13 +63,15 @@ export const DateUIView = (props: DataUIViewProps) => { inputReadOnly={checkIsMobile(editorState?.getAppSettings().maxWidth)} placeholder={placeholder} renderExtraFooter={()=>( - - {console.log("DatePickerStyled")}} - /> + props.timeZone === "UserChoice" && ( + + {console.log("DatePickerStyled")}} + /> + ) )} /> ); diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx index 07dbf9bbf..2430e6752 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx @@ -143,6 +143,7 @@ export type TimeCompViewProps = Pick< disabledTime: () => ReturnType; suffixIcon?: ReactNode | false; placeholder?: string | [string, string]; + timeZone:string }; export const timePickerControl = new UICompBuilder(childrenMap, (props) => { @@ -167,6 +168,7 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => { onMouseDown: (e) => e.stopPropagation(), children: ( { }} onFocus={() => props.onEvent("focus")} onBlur={() => props.onEvent("blur")} - suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} - /> + suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} /> ), ...validate(props), }); @@ -290,6 +291,7 @@ export const timeRangeControl = (function () { const children = ( { suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} placeholder={placeholders} renderExtraFooter={() => ( - {console.log("handleTimeZoneChange")}} /> - )} + ) + )} /> ); }; diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx index abf6f679f..1915d8b02 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx @@ -48,11 +48,13 @@ export const TimeUIView = (props: TimeUIViewProps) => { inputReadOnly={checkIsMobile(editorState?.getAppSettings().maxWidth)} placeholder={placeholder} renderExtraFooter={()=>( + props.timeZone === "UserChoice" && ( {console.log("handleTimeZoneChange")}} /> + ) )} /> ); From fb6330bd8d73a135a0ef1549d79a71e5b4ccce13 Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Thu, 5 Sep 2024 15:20:39 +0500 Subject: [PATCH 4/6] time zone activated --- .../src/comps/comps/dateComp/dateComp.tsx | 167 +++++++++++++----- .../src/comps/comps/dateComp/timeComp.tsx | 58 ++++-- .../src/comps/comps/dateComp/timeZone.ts | 47 +++-- .../packages/lowcoder/src/i18n/locales/en.ts | 6 +- 4 files changed, 193 insertions(+), 85 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx index afc194502..aa6cf8f7d 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx @@ -1,5 +1,7 @@ import _, { noop } from "lodash"; import dayjs from "dayjs"; +import utc from 'dayjs/plugin/utc'; +import timezone from 'dayjs/plugin/timezone'; import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"; import { BoolCodeControl, @@ -51,6 +53,10 @@ import { EditorContext } from "comps/editorState"; import { dropdownControl } from "comps/controls/dropdownControl"; import { timeZoneOptions } from "./timeZone"; + +dayjs.extend(utc); +dayjs.extend(timezone); + const EventOptions = [changeEvent, focusEvent, blurEvent] as const; const validationChildren = { @@ -82,7 +88,7 @@ const commonChildren = { ...validationChildren, viewRef: RefControl, inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'), - timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"), + timeZone: dropdownControl(timeZoneOptions, "Etc/UTC"), }; type CommonChildrenType = RecordConstructorToComp; @@ -452,21 +458,42 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [ depsConfig({ name: "value", desc: trans("export.datePickerValueDesc"), - depKeys: ["value", "showTime"], + depKeys: ["value", "showTime", "timeZone"], // Include timeZone as a dependency func: (input) => { - const mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; - return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null; + let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; + + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { + mom = mom?.hour(12); // Default to noon to avoid day shift + } + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedDate = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); + return formattedDate; + } + return null; }, }), depsConfig({ name: "formattedValue", desc: trans("export.datePickerFormattedValueDesc"), - depKeys: ["value", "format"], + depKeys: ["value", "format", "timeZone"], func: (input) => { - const mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; - return mom?.isValid() ? mom.format(input.format) : ""; + let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; + + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { + mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts + } + + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedTime = mom.tz(tz).format(input.format); + + return formattedTime; + } + return ''; }, }), + depsConfig({ name: "timestamp", desc: trans("export.datePickerTimestampDesc"), @@ -486,6 +513,14 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [ value: { value: input.value }, } as any).validateStatus !== "success", }), + depsConfig({ + name: "timeZone", + desc: trans("export.timeZoneDesc"), + depKeys: ["timeZone"], + func: (input) => { + return input.timeZone; + }, + }), ...CommonNameConfig, ]); @@ -493,85 +528,133 @@ export let DateRangeComp = withExposingConfigs(dateRangeControl, [ depsConfig({ name: "start", desc: trans("export.dateRangeStartDesc"), - depKeys: ["start", "showTime"], + depKeys: ["start", "showTime", "timeZone"], func: (input) => { - const mom = Boolean(input.start) ? dayjs(input.start, DateParser): null; - return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null; + const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null; + + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedStart = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); + return formattedStart; + } + return null; }, }), + depsConfig({ name: "end", desc: trans("export.dateRangeEndDesc"), - depKeys: ["end", "showTime"], + depKeys: ["end", "showTime", "timeZone"], func: (input) => { - const mom = Boolean(input.end) ? dayjs(input.end, DateParser): null; - return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null; + let mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { + mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts + } + + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedEnd = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); + return formattedEnd; + } + return null; }, }), + depsConfig({ name: "startTimestamp", desc: trans("export.dateRangeStartTimestampDesc"), - depKeys: ["start"], + depKeys: ["start", "timeZone"], func: (input) => { const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null; - return mom?.isValid() ? mom.unix() : ""; + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + return mom.tz(tz).unix(); + } + return ""; }, }), depsConfig({ name: "endTimestamp", desc: trans("export.dateRangeEndTimestampDesc"), - depKeys: ["end"], + depKeys: ["end", "timeZone"], func: (input) => { const mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null; - return mom?.isValid() ? mom.unix() : ""; + if (mom?.isValid()) { + const tz = input.timeZone || 'UTC'; + return mom.tz(tz).unix(); + } + return ""; }, }), depsConfig({ name: "formattedValue", desc: trans("export.dateRangeFormattedValueDesc"), - depKeys: ["start", "end", "format"], + depKeys: ["start", "end", "format", "timeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, DateParser): null; - const end = Boolean(input.end) ? dayjs(input.end, DateParser): null; - return [ - start?.isValid() && start.format(input.format), - end?.isValid() && end.format(input.format), - ] - .filter((item) => item) - .join(" - "); + const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null; + const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + + if (start?.isValid() || end?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedStart = start?.isValid() ? start.tz(tz).format(input.format) : ''; + const formattedEnd = end?.isValid() ? end.tz(tz).format(input.format) : ''; + const formattedValue = [formattedStart, formattedEnd].filter(Boolean).join(" - "); + return formattedValue; + } + return ''; }, }), + depsConfig({ name: "formattedStartValue", desc: trans("export.dateRangeFormattedStartValueDesc"), - depKeys: ["start", "format"], + depKeys: ["start", "format", "timeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, DateParser): null; - return start?.isValid() && start.format(input.format); + const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null; + + if (start?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedStart = start.tz(tz).format(input.format); + } + return ''; }, }), depsConfig({ name: "formattedEndValue", desc: trans("export.dateRangeFormattedEndValueDesc"), - depKeys: ["end", "format"], + depKeys: ["end", "format", "timeZone"], func: (input) => { - const end = Boolean(input.end) ? dayjs(input.end, DateParser): null; - return end?.isValid() && end.format(input.format); + const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + + if (end?.isValid()) { + const tz = input.timeZone || 'UTC'; + const formattedEnd = end.tz(tz).format(input.format); + return formattedEnd; + } + return ''; }, }), depsConfig({ name: "invalid", desc: trans("export.invalidDesc"), - depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule"], - func: (input) => - validate({ - ...input, - value: { value: input.start }, - }).validateStatus !== "success" || - validate({ - ...input, - value: { value: input.end }, - }).validateStatus !== "success", + depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule", "timeZone"], + func: (input) => { + const tz = input.timeZone || 'UTC'; + const startDate = Boolean(input.start) ? dayjs(input.start, DateParser).tz(tz) : null; + const endDate = Boolean(input.end) ? dayjs(input.end, DateParser).tz(tz) : null; + const startInvalid = startDate && (!startDate.isValid() || (input.minDate && startDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && startDate.isAfter(dayjs(input.maxDate).tz(tz)))); + const endInvalid = endDate && (!endDate.isValid() || (input.minDate && endDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && endDate.isAfter(dayjs(input.maxDate).tz(tz)))); + return startInvalid || endInvalid; + }, + }), + depsConfig({ + name: "timeZone", + desc: trans("export.timeZoneDesc"), + depKeys: ["timeZone"], + func: (input) => { + return input.timeZone || 'UTC'; + }, }), ...CommonNameConfig, ]); diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx index 2430e6752..04db1d82f 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx @@ -1,5 +1,7 @@ import _ from "lodash"; import dayjs from "dayjs"; +import utc from 'dayjs/plugin/utc'; +import timezone from 'dayjs/plugin/timezone'; import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"; import { BoolCodeControl, @@ -55,6 +57,8 @@ import { EditorContext } from "comps/editorState"; import { dropdownControl } from "comps/controls/dropdownControl"; import { timeZoneOptions } from "./timeZone"; +dayjs.extend(utc); +dayjs.extend(timezone); const EventOptions = [changeEvent, focusEvent, blurEvent] as const; const validationChildren = { @@ -83,7 +87,7 @@ const commonChildren = { ), inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'), suffixIcon: withDefault(IconControl, "/icon:regular/clock"), - timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"), + timeZone: dropdownControl(timeZoneOptions, "Etc/UTC"), viewRef: RefControl, ...validationChildren, }; @@ -406,10 +410,20 @@ export const TimePickerComp = withExposingConfigs(timePickerControl, [ depsConfig({ name: "formattedValue", desc: trans("export.timePickerFormattedValueDesc"), - depKeys: ["value", "format"], + depKeys: ["value", "format", "timeZone"], func: (input) => { const mom = Boolean(input.value) ? dayjs(input.value, TimeParser) : null; - return mom?.isValid() ? mom.format(input.format) : ''; + const tz = input.timeZone || 'UTC'; + const formattedTime = mom?.tz(tz).format("HH:mm:ss"); + return mom?.isValid() ? mom.tz(tz).format(input.format) : ''; + }, + }), + depsConfig({ + name: "timeZone", + desc: trans("export.timeZoneDesc"), + depKeys: ["timeZone"], + func: (input) => { + return input.timeZone || 'UTC'; }, }), depsConfig({ @@ -431,34 +445,42 @@ export let TimeRangeComp = withExposingConfigs(timeRangeControl, [ depsConfig({ name: "formattedValue", desc: trans("export.timeRangeFormattedValueDesc"), - depKeys: ["start", "end", "format"], + depKeys: ["start", "end", "format", "timeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, TimeParser) : null; - const end = Boolean(input.end) ? dayjs(input.end, TimeParser) : null; - return [ - start?.isValid() && start.format(input.format), - end?.isValid() && end.format(input.format), - ] - .filter((item) => item) - .join(" - "); + const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null; + const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null; + const tz = input.timeZone || 'UTC'; + const formattedStart = start?.isValid() && start.tz(tz).format(input.format); + const formattedEnd = end?.isValid() && end.tz(tz).format(input.format); + return [formattedStart, formattedEnd].filter((item) => item).join(" - "); }, }), depsConfig({ name: "formattedStartValue", desc: trans("export.timeRangeFormattedStartValueDesc"), - depKeys: ["start", "format"], + depKeys: ["start", "format", "timeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, TimeParser) : null; - return start?.isValid() && start.format(input.format); + const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null; + const tz = input.timeZone || 'UTC'; + return start?.isValid() && start.tz(tz).format(input.format); }, }), depsConfig({ name: "formattedEndValue", desc: trans("export.timeRangeFormattedEndValueDesc"), - depKeys: ["end", "format"], + depKeys: ["end", "format", "timeZone"], + func: (input) => { + const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null; + const tz = input.timeZone || 'UTC'; + return end?.isValid() && end.tz(tz).format(input.format); + }, + }), + depsConfig({ + name: "timeZone", + desc: trans("export.timeZoneDesc"), + depKeys: ["timeZone"], func: (input) => { - const end = Boolean(input.end) ? dayjs(input.end, TimeParser) : null; - return end?.isValid() && end.format(input.format); + return input.timeZone || 'UTC'; }, }), depsConfig({ diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts index 759247730..ff807c060 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts @@ -1,27 +1,26 @@ export const timeZoneOptions = [ - { label: "(UTC-12:00) International Date Line West", value: "DatelineStandard" }, - { label: "(UTC-11:00) Coordinated Universal Time-11", value: "UTC11" }, - { label: "(UTC-10:00) Hawaii", value: "HawaiianStandard" }, - { label: "(UTC-09:00) Alaska", value: "AlaskanStandard" }, - { label: "(UTC-08:00) Baja California", value: "PacificStandardMexico" }, - { label: "(UTC-07:00) Pacific Daylight Time (US & Canada)", value: "PacificDaylight" }, - { label: "(UTC-06:00) Central Time (US & Canada)", value: "CentralStandard" }, - { label: "(UTC-05:00) Eastern Time (US & Canada)", value: "EasternStandard" }, - { label: "(UTC-04:00) Atlantic Time (Canada)", value: "AtlanticStandard" }, - { label: "(UTC-03:00) Buenos Aires", value: "ArgentinaStandard" }, - { label: "(UTC-02:00) Coordinated Universal Time-02", value: "UTC02" }, - { label: "(UTC-01:00) Cape Verde Is.", value: "CapeVerdeStandard" }, - { label: "(UTC+00:00) Coordinated Universal Time", value: "UTC" }, - { label: "(UTC+01:00) Amsterdam, Berlin, Rome, Vienna", value: "WEuropeStandard" }, - { label: "(UTC+02:00) Athens, Bucharest", value: "GTBStandard" }, - { label: "(UTC+03:00) Moscow, St. Petersburg", value: "MoscowStandard" }, - { label: "(UTC+04:00) Abu Dhabi, Muscat", value: "ArabianStandard" }, - { label: "(UTC+05:00) Islamabad, Karachi", value: "PakistanStandard" }, - { label: "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", value: "IndiaStandard" }, - { label: "(UTC+06:00) Dhaka", value: "BangladeshStandard" }, - { label: "(UTC+07:00) Bangkok, Hanoi, Jakarta", value: "SEAsiaStandard" }, - { label: "(UTC+08:00) Beijing, Chongqing, Hong Kong", value: "ChinaStandard" }, - { label: "(UTC+09:00) Tokyo, Seoul", value: "JapanStandard" }, - { label: "(UTC+10:00) Sydney, Melbourne", value: "AUSEasternStandard" }, + { label: "(UTC-12:00) International Date Line West", value: "Etc/GMT+12" }, + { label: "(UTC-11:00) Coordinated Universal Time-11", value: "Etc/GMT+11" }, + { label: "(UTC-10:00) Hawaii", value: "Pacific/Honolulu" }, + { label: "(UTC-09:00) Alaska", value: "America/Anchorage" }, + { label: "(UTC-08:00) Baja California", value: "America/Tijuana" }, + { label: "(UTC-07:00) Pacific Daylight Time (US & Canada)", value: "America/Los_Angeles" }, { label: "(UTC-06:00) Central Time (US & Canada)", value: "America/Chicago" }, + { label: "(UTC-05:00) Eastern Time (US & Canada)", value: "America/New_York" }, + { label: "(UTC-04:00) Atlantic Time (Canada)", value: "America/Halifax" }, + { label: "(UTC-03:00) Buenos Aires", value: "America/Argentina/Buenos_Aires" }, + { label: "(UTC-02:00) Coordinated Universal Time-02", value: "Etc/GMT+2" }, + { label: "(UTC-01:00) Cape Verde Is.", value: "Atlantic/Cape_Verde" }, + { label: "Etc/UTC", value: "Etc/UTC" }, + { label: "(UTC+01:00) Amsterdam, Berlin, Rome, Vienna", value: "Europe/Berlin" }, + { label: "(UTC+02:00) Athens, Bucharest", value: "Europe/Bucharest" }, + { label: "(UTC+03:00) Moscow, St. Petersburg", value: "Europe/Moscow" }, + { label: "(UTC+04:00) Abu Dhabi, Muscat", value: "Asia/Dubai" }, + { label: "(UTC+05:00) Islamabad, Karachi", value: "Asia/Karachi" }, + { label: "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", value: "Asia/Kolkata" }, + { label: "(UTC+06:00) Dhaka", value: "Asia/Dhaka" }, + { label: "(UTC+07:00) Bangkok, Hanoi, Jakarta", value: "Asia/Bangkok" }, + { label: "(UTC+08:00) Beijing, Chongqing, Hong Kong", value: "Asia/Shanghai" }, + { label: "(UTC+09:00) Tokyo, Seoul", value: "Asia/Tokyo" }, + { label: "(UTC+10:00) Sydney, Melbourne", value: "Australia/Sydney" }, { label: "User Choice", value: "UserChoice" }, ]; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 55479020a..2087f4f87 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -597,7 +597,11 @@ export const en = { "timeRangeEndDesc": "End time of the range", "timeRangeFormattedValueDesc": "Formatted time range", "timeRangeFormattedStartValueDesc": "Formatted start time", - "timeRangeFormattedEndValueDesc": "Formatted end time" + "timeRangeFormattedEndValueDesc": "Formatted end time", + "timeZone": "Time Zone", + "timeZoneDesc": "Timezone of the selected date", + + }, "validationDesc": { "email": "Please enter a valid email address", From 3be3f05307328b45da81a492041954957ae5d569 Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Thu, 5 Sep 2024 22:35:04 +0500 Subject: [PATCH 5/6] time and date converted --- .../src/comps/comps/dateComp/dateComp.tsx | 238 ++++++++++++++---- .../comps/comps/dateComp/dateRangeUIView.tsx | 6 +- .../src/comps/comps/dateComp/dateUIView.tsx | 7 +- .../src/comps/comps/dateComp/timeComp.tsx | 174 ++++++++++--- .../comps/comps/dateComp/timeRangeUIView.tsx | 6 +- .../src/comps/comps/dateComp/timeUIView.tsx | 6 +- 6 files changed, 344 insertions(+), 93 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx index aa6cf8f7d..3b3e637c5 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx @@ -1,6 +1,7 @@ import _, { noop } from "lodash"; import dayjs from "dayjs"; import utc from 'dayjs/plugin/utc'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; import timezone from 'dayjs/plugin/timezone'; import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"; import { @@ -56,6 +57,8 @@ import { timeZoneOptions } from "./timeZone"; dayjs.extend(utc); dayjs.extend(timezone); +dayjs.extend(customParseFormat); + const EventOptions = [changeEvent, focusEvent, blurEvent] as const; @@ -146,6 +149,7 @@ function validate( const childrenMap = { value: stringExposingStateControl("value"), + userTimeZone: stringExposingStateControl("userTimeZone", 'Etc/UTC'), ...commonChildren, ...formDataChildren, }; @@ -185,6 +189,10 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => { setTempValue(value); }, [props.value.value]) + const handleDateZoneChange = (newTimeZone: any) => { + props.userTimeZone.onChange(newTimeZone) + } + return props.label({ required: props.required, style: props.style, @@ -194,7 +202,8 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => { onMouseDown: (e) => e.stopPropagation(), children: ( disabledTime(props.minTime, props.maxTime)} $style={props.inputFieldStyle} @@ -301,6 +310,7 @@ export const dateRangeControl = (function () { const childrenMap = { start: stringExposingStateControl("start"), end: stringExposingStateControl("end"), + userRangeTimeZone: stringExposingStateControl("userRangeTimeZone" , 'Etc/UTC'), ...formDataChildren, ...commonChildren, }; @@ -329,9 +339,15 @@ export const dateRangeControl = (function () { setTempEndValue(value); }, [props.end.value]) + + const handleDateRangeZoneChange = (newTimeZone: any) => { + props.userRangeTimeZone.onChange(newTimeZone) + } + const children = ( props.onEvent("focus")} onBlur={() => props.onEvent("blur")} - suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} - /> + suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} /> ); const startResult = validate({ ...props, value: props.start }); @@ -458,42 +473,57 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [ depsConfig({ name: "value", desc: trans("export.datePickerValueDesc"), - depKeys: ["value", "showTime", "timeZone"], // Include timeZone as a dependency + depKeys: ["value", "showTime", "timeZone", "userTimeZone"], func: (input) => { - let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.value, format).isValid()) { + mom = dayjs.utc(input.value, format); + break; + } + } + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { mom = mom?.hour(12); // Default to noon to avoid day shift - } + } + if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userTimeZone : input.timeZone || 'UTC'; const formattedDate = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); return formattedDate; } + return null; }, }), + depsConfig({ name: "formattedValue", desc: trans("export.datePickerFormattedValueDesc"), - depKeys: ["value", "format", "timeZone"], - func: (input) => { - let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null; + depKeys: ["value", "format", "timeZone", "userTimeZone"], - if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { + func: (input) => { + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.value, format).isValid()) { + mom = dayjs.utc(input.value, format); + break; + } + } + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts } - - if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + if (mom?.isValid()) { + const tz = input.timeZone === 'UserChoice' ? input.userTimeZone : input.timeZone || 'UTC'; const formattedTime = mom.tz(tz).format(input.format); - return formattedTime; } return ''; }, }), + depsConfig({ name: "timestamp", desc: trans("export.datePickerTimestampDesc"), @@ -516,9 +546,11 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [ depsConfig({ name: "timeZone", desc: trans("export.timeZoneDesc"), - depKeys: ["timeZone"], + depKeys: ["timeZone", "userTimeZone"], func: (input) => { - return input.timeZone; + console.log("input.timeZone", input.timeZone) + return input.timeZone === 'UserChoice' ? input.userTimeZone : input.timeZone || 'UTC'; + }, }), ...CommonNameConfig, @@ -528,75 +560,129 @@ export let DateRangeComp = withExposingConfigs(dateRangeControl, [ depsConfig({ name: "start", desc: trans("export.dateRangeStartDesc"), - depKeys: ["start", "showTime", "timeZone"], + depKeys: ["start", "showTime", "timeZone", "userRangeTimeZone"], func: (input) => { - const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null; - + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.start, format).isValid()) { + mom = dayjs.utc(input.start, format); + break; + } + } + if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { + mom = mom?.hour(12); + } + if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; const formattedStart = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); return formattedStart; } - return null; + return null; }, }), - + depsConfig({ name: "end", desc: trans("export.dateRangeEndDesc"), - depKeys: ["end", "showTime", "timeZone"], - func: (input) => { - let mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + depKeys: ["end", "showTime", "timeZone", "userRangeTimeZone"], + func: (input) => { + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.end, format).isValid()) { + mom = dayjs.utc(input.end, format); + break; + } + } if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) { - mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts + mom = mom?.hour(12); } - + if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; const formattedEnd = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT); return formattedEnd; } return null; }, }), - + depsConfig({ name: "startTimestamp", desc: trans("export.dateRangeStartTimestampDesc"), - depKeys: ["start", "timeZone"], + depKeys: ["start", "timeZone", "userRangeTimeZone"], func: (input) => { - const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null; + + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.start, format).isValid()) { + mom = dayjs.utc(input.start, format); + break; + } + } if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; return mom.tz(tz).unix(); } return ""; }, }), + depsConfig({ name: "endTimestamp", desc: trans("export.dateRangeEndTimestampDesc"), - depKeys: ["end", "timeZone"], + depKeys: ["end", "timeZone", "userRangeTimeZone"], func: (input) => { - const mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + + let mom = null; + for (const format of DateParser) { + if (dayjs.utc(input.end, format).isValid()) { + mom = dayjs.utc(input.end, format); + break; + } + } if (mom?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; return mom.tz(tz).unix(); } return ""; }, }), + depsConfig({ name: "formattedValue", desc: trans("export.dateRangeFormattedValueDesc"), - depKeys: ["start", "end", "format", "timeZone"], + depKeys: ["start", "end", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null; - const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + let start = null; + let end = null; + + for (const format of DateParser) { + if (dayjs.utc(input.start, format).isValid()) { + start = dayjs.utc(input.start, format); + break; + } + } + for (const format of DateParser) { + if (dayjs.utc(input.end, format).isValid()) { + end = dayjs.utc(input.end, format); + break; + } + } + + //When the time is 00:00:00 and you convert it to a timezone behind UTC (e.g., UTC-5), the date can shift to the previous day + if (!input.showTime && start?.hour() === 0 && start?.minute() === 0 && start?.second() === 0) { + start = start?.hour(12); + } + + if (!input.showTime && end?.hour() === 0 && end?.minute() === 0 && end?.second() === 0) { + end = end?.hour(12); + } if (start?.isValid() || end?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + const formattedStart = start?.isValid() ? start.tz(tz).format(input.format) : ''; const formattedEnd = end?.isValid() ? end.tz(tz).format(input.format) : ''; const formattedValue = [formattedStart, formattedEnd].filter(Boolean).join(" - "); @@ -606,59 +692,103 @@ export let DateRangeComp = withExposingConfigs(dateRangeControl, [ }, }), + depsConfig({ name: "formattedStartValue", desc: trans("export.dateRangeFormattedStartValueDesc"), - depKeys: ["start", "format", "timeZone"], + depKeys: ["start", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null; + let start = null; + // Loop through DateParser to find a valid format + for (const format of DateParser) { + if (dayjs.utc(input.start, format).isValid()) { + start = dayjs.utc(input.start, format); + break; + } + } + + if (!input.showTime && start?.hour() === 0 && start?.minute() === 0 && start?.second() === 0) { + start = start?.hour(12); + } if (start?.isValid()) { - const tz = input.timeZone || 'UTC'; - const formattedStart = start.tz(tz).format(input.format); + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + const formattedStart = start.tz(tz).format(input.format); + return formattedStart; } return ''; }, }), + depsConfig({ name: "formattedEndValue", desc: trans("export.dateRangeFormattedEndValueDesc"), - depKeys: ["end", "format", "timeZone"], + depKeys: ["end", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null; + let end = null; + // Loop through DateParser to find a valid format + for (const format of DateParser) { + if (dayjs.utc(input.end, format).isValid()) { + end = dayjs.utc(input.end, format); + break; + } + } + + if (!input.showTime && end?.hour() === 0 && end?.minute() === 0 && end?.second() === 0) { + end = end?.hour(12); + } if (end?.isValid()) { - const tz = input.timeZone || 'UTC'; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; const formattedEnd = end.tz(tz).format(input.format); return formattedEnd; } return ''; }, }), + + depsConfig({ name: "invalid", desc: trans("export.invalidDesc"), - depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule", "timeZone"], + depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule", "timeZone", "userRangeTimeZone"], func: (input) => { - const tz = input.timeZone || 'UTC'; - const startDate = Boolean(input.start) ? dayjs(input.start, DateParser).tz(tz) : null; - const endDate = Boolean(input.end) ? dayjs(input.end, DateParser).tz(tz) : null; + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + let startDate = null; + let endDate = null; + + for (const format of DateParser) { + if (dayjs.utc(input.start, format).isValid()) { + startDate = dayjs.utc(input.start, format).tz(tz); + break; + } + } + for (const format of DateParser) { + if (dayjs.utc(input.end, format).isValid()) { + endDate = dayjs.utc(input.end, format).tz(tz); + break; + } + } + const startInvalid = startDate && (!startDate.isValid() || (input.minDate && startDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && startDate.isAfter(dayjs(input.maxDate).tz(tz)))); const endInvalid = endDate && (!endDate.isValid() || (input.minDate && endDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && endDate.isAfter(dayjs(input.maxDate).tz(tz)))); + return startInvalid || endInvalid; }, }), + depsConfig({ name: "timeZone", desc: trans("export.timeZoneDesc"), - depKeys: ["timeZone"], + depKeys: ["timeZone", "userRangeTimeZone"], func: (input) => { - return input.timeZone || 'UTC'; + return input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; }, }), ...CommonNameConfig, ]); + DateRangeComp = withMethodExposing(DateRangeComp, [ ...dateRefMethods, { diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx index f378dbbc4..1c925fa95 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx @@ -44,6 +44,7 @@ export interface DateRangeUIViewProps extends DateCompViewProps { placeholder?: string | [string, string]; onChange: (start?: dayjs.Dayjs | null, end?: dayjs.Dayjs | null) => void; onPanelChange: (value: any, mode: [string, string]) => void; + onClickDateRangeTimeZone:(value:any)=>void } export const DateRangeUIView = (props: DateRangeUIViewProps) => { @@ -79,9 +80,10 @@ export const DateRangeUIView = (props: DateRangeUIViewProps) => { props.timeZone === "UserChoice" && ( option.value !== 'UserChoice')} placeholder="Select Time Zone" - onChange={()=>{console.log("handleTimeZoneChange")}} + defaultValue={'Etc/UTC'} + onChange={props?.onClickDateRangeTimeZone} /> ) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx index e4f58abe7..80ab630f6 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx @@ -37,6 +37,8 @@ export interface DataUIViewProps extends DateCompViewProps { value?: DatePickerProps['value']; onChange: DatePickerProps['onChange']; onPanelChange: () => void; + onClickDateTimeZone:(value:any)=>void; + } const DateMobileUIView = React.lazy(() => @@ -66,9 +68,10 @@ export const DateUIView = (props: DataUIViewProps) => { props.timeZone === "UserChoice" && ( option.value !== 'UserChoice')} placeholder="Select Time Zone" - onChange={()=>{console.log("DatePickerStyled")}} + defaultValue={'Etc/UTC'} + onChange={props.onClickDateTimeZone} /> ) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx index 04db1d82f..5b8809e9a 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx @@ -2,6 +2,7 @@ import _ from "lodash"; import dayjs from "dayjs"; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"; import { BoolCodeControl, @@ -59,6 +60,8 @@ import { timeZoneOptions } from "./timeZone"; dayjs.extend(utc); dayjs.extend(timezone); +dayjs.extend(customParseFormat); + const EventOptions = [changeEvent, focusEvent, blurEvent] as const; const validationChildren = { @@ -127,6 +130,7 @@ function validate( const childrenMap = { value: stringExposingStateControl("value"), + userTimeZone: stringExposingStateControl("userTimeZone" , 'Etc/UTC'), ...commonChildren, ...formDataChildren, }; @@ -163,6 +167,10 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => { setTempValue(value); }, [props.value.value]) + const handleTimeZoneChange = (newTimeZone: any) => { + props.userTimeZone.onChange(newTimeZone) + } + return props.label({ required: props.required, style: props.style, @@ -172,6 +180,7 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => { onMouseDown: (e) => e.stopPropagation(), children: ( { + props.userRangeTimeZone.onChange(newTimeZone) + } const children = ( { - const mom = Boolean(input.value) ? dayjs(input.value, TimeParser) : null; - const tz = input.timeZone || 'UTC'; - const formattedTime = mom?.tz(tz).format("HH:mm:ss"); + let mom = null; + + // Loop through TimeParser to find a valid format + for (const format of TimeParser) { + if (dayjs.utc(input.value, format).isValid()) { + mom = dayjs.utc(input.value, format); + break; + } + } + + const tz = input.timeZone === 'UserChoice' ? input.userTimeZone : input.timeZone || 'UTC'; return mom?.isValid() ? mom.tz(tz).format(input.format) : ''; }, }), + depsConfig({ name: "timeZone", desc: trans("export.timeZoneDesc"), - depKeys: ["timeZone"], + depKeys: ["timeZone", "userTimeZone"], func: (input) => { - return input.timeZone || 'UTC'; + return input.timeZone === 'UserChoice' ? input.userTimeZone : input.timeZone || 'UTC'; }, }), + depsConfig({ name: "invalid", desc: trans("export.invalidDesc"), @@ -434,72 +460,158 @@ export const TimePickerComp = withExposingConfigs(timePickerControl, [ validate({ ...input, value: { value: input.value }, - } as any).validateStatus !== "success", + }).validateStatus !== "success", }), + ...CommonNameConfig, ]); + export let TimeRangeComp = withExposingConfigs(timeRangeControl, [ - new NameConfig("start", trans("export.timeRangeStartDesc")), - new NameConfig("end", trans("export.timeRangeEndDesc")), + // new NameConfig("start", trans("export.timeRangeStartDesc")), + // new NameConfig("end", trans("export.timeRangeEndDesc")), + depsConfig({ + name: "start", + desc: trans("export.timeRangeStartDesc"), + depKeys: ["start", "timeZone", "userRangeTimeZone"], + func: (input) => { + let start = null; + + // Loop through TimeParser to find a valid format for start + for (const format of TimeParser) { + if (dayjs.utc(input.start, format).isValid()) { + start = dayjs.utc(input.start, format); + break; + } + } + + if (start?.hour() === 0 && start?.minute() === 0 && start?.second() === 0) { + start = start?.hour(12); + } + + // Apply timezone conversion if valid + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + return start?.isValid() ? start.tz(tz).format(input.format || "HH:mm:ss") : null; + }, + }), + + depsConfig({ + name: "end", + desc: trans("export.timeRangeEndDesc"), + depKeys: ["end", "timeZone", "userRangeTimeZone"], + func: (input) => { + let end = null; + + // Loop through TimeParser to find a valid format for end + for (const format of TimeParser) { + if (dayjs.utc(input.end, format).isValid()) { + end = dayjs.utc(input.end, format); + break; + } + } + + // Apply timezone conversion if valid + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + return end?.isValid() ? end.tz(tz).format(input.format || "HH:mm:ss") : null; + }, + }), + depsConfig({ name: "formattedValue", desc: trans("export.timeRangeFormattedValueDesc"), - depKeys: ["start", "end", "format", "timeZone"], + depKeys: ["start", "end", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null; - const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null; - const tz = input.timeZone || 'UTC'; - const formattedStart = start?.isValid() && start.tz(tz).format(input.format); - const formattedEnd = end?.isValid() && end.tz(tz).format(input.format); - return [formattedStart, formattedEnd].filter((item) => item).join(" - "); + let start = null; + let end = null; + for (const format of TimeParser) { + if (dayjs.utc(input.start, format).isValid()) { + start = dayjs.utc(input.start, format); + break; + } + } + for (const format of TimeParser) { + if (dayjs.utc(input.end, format).isValid()) { + end = dayjs.utc(input.end, format); + break; + } + } + + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + const formattedStart = start?.isValid() ? start.tz(tz).format(input.format) : ''; + const formattedEnd = end?.isValid() ? end.tz(tz).format(input.format) : ''; + + return [formattedStart, formattedEnd].filter(Boolean).join(" - "); }, }), + depsConfig({ name: "formattedStartValue", desc: trans("export.timeRangeFormattedStartValueDesc"), - depKeys: ["start", "format", "timeZone"], + depKeys: ["start", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null; - const tz = input.timeZone || 'UTC'; - return start?.isValid() && start.tz(tz).format(input.format); + let start = null; + for (const format of TimeParser) { + if (dayjs.utc(input.start, format).isValid()) { + start = dayjs.utc(input.start, format); + break; + } + } + + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + return start?.isValid() ? start.tz(tz).format(input.format) : ''; }, }), + depsConfig({ name: "formattedEndValue", desc: trans("export.timeRangeFormattedEndValueDesc"), - depKeys: ["end", "format", "timeZone"], + depKeys: ["end", "format", "timeZone", "userRangeTimeZone"], func: (input) => { - const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null; - const tz = input.timeZone || 'UTC'; - return end?.isValid() && end.tz(tz).format(input.format); + let end = null; + for (const format of TimeParser) { + if (dayjs.utc(input.end, format).isValid()) { + end = dayjs.utc(input.end, format); + break; + } + } + + const tz = input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; + return end?.isValid() ? end.tz(tz).format(input.format) : ''; }, }), + depsConfig({ name: "timeZone", desc: trans("export.timeZoneDesc"), - depKeys: ["timeZone"], + depKeys: ["timeZone", "userRangeTimeZone"], func: (input) => { - return input.timeZone || 'UTC'; + return input.timeZone === 'UserChoice' ? input.userRangeTimeZone : input.timeZone || 'UTC'; }, }), + depsConfig({ name: "invalid", desc: trans("export.invalidDesc"), depKeys: ["start", "end", "required", "minTime", "maxTime", "customRule"], - func: (input) => - validate({ + func: (input) => { + const startInvalid = validate({ ...input, value: { value: input.start }, - }).validateStatus !== "success" || - validate({ + }).validateStatus !== "success"; + + const endInvalid = validate({ ...input, value: { value: input.end }, - }).validateStatus !== "success", + }).validateStatus !== "success"; + + return startInvalid || endInvalid; + }, }), + ...CommonNameConfig, ]); + TimeRangeComp = withMethodExposing(TimeRangeComp, [ ...dateRefMethods, { diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx index a07c499f4..4d837b94a 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeRangeUIView.tsx @@ -38,6 +38,7 @@ export interface TimeRangeUIViewProps extends TimeCompViewProps { end: dayjs.Dayjs | null; placeholder?: string | [string, string]; onChange: (start?: dayjs.Dayjs | null, end?: dayjs.Dayjs | null) => void; + handleTimeRangeZoneChange: (value:any) => void; } export const TimeRangeUIView = (props: TimeRangeUIViewProps) => { @@ -69,8 +70,9 @@ export const TimeRangeUIView = (props: TimeRangeUIViewProps) => { props.timeZone === "UserChoice" && ( {console.log("handleTimeZoneChange")}} + options={timeZoneOptions.filter(option => option.value !== 'UserChoice')} // Filter out 'userChoice' + defaultValue={'Etc/UTC'} + onChange={props.handleTimeRangeZoneChange} /> ) )} diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx index 1915d8b02..942061e68 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeUIView.tsx @@ -32,6 +32,7 @@ const StyledAntdSelect = styled(AntdSelect)` export interface TimeUIViewProps extends TimeCompViewProps { value: dayjs.Dayjs | null; onChange: (value: dayjs.Dayjs | null) => void; + handleTimeZoneChange: (value:any) => void; } export const TimeUIView = (props: TimeUIViewProps) => { @@ -51,8 +52,9 @@ export const TimeUIView = (props: TimeUIViewProps) => { props.timeZone === "UserChoice" && ( {console.log("handleTimeZoneChange")}} + options={timeZoneOptions.filter(option => option.value !== 'UserChoice')} // Filter out 'userChoice' + onChange={props?.handleTimeZoneChange} + defaultValue={'Etc/UTC'} /> ) )} From 74d39e464e689b669fcf3774c1cd045b9b7b04e1 Mon Sep 17 00:00:00 2001 From: MenamAfzal Date: Thu, 5 Sep 2024 23:12:00 +0500 Subject: [PATCH 6/6] translation added --- .../src/comps/comps/dateComp/timeZone.ts | 51 ++++++++++--------- .../packages/lowcoder/src/i18n/locales/en.ts | 28 ++++++++++ 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts index ff807c060..33108bcad 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts +++ b/client/packages/lowcoder/src/comps/comps/dateComp/timeZone.ts @@ -1,26 +1,29 @@ +import { trans } from "i18n"; + export const timeZoneOptions = [ - { label: "(UTC-12:00) International Date Line West", value: "Etc/GMT+12" }, - { label: "(UTC-11:00) Coordinated Universal Time-11", value: "Etc/GMT+11" }, - { label: "(UTC-10:00) Hawaii", value: "Pacific/Honolulu" }, - { label: "(UTC-09:00) Alaska", value: "America/Anchorage" }, - { label: "(UTC-08:00) Baja California", value: "America/Tijuana" }, - { label: "(UTC-07:00) Pacific Daylight Time (US & Canada)", value: "America/Los_Angeles" }, { label: "(UTC-06:00) Central Time (US & Canada)", value: "America/Chicago" }, - { label: "(UTC-05:00) Eastern Time (US & Canada)", value: "America/New_York" }, - { label: "(UTC-04:00) Atlantic Time (Canada)", value: "America/Halifax" }, - { label: "(UTC-03:00) Buenos Aires", value: "America/Argentina/Buenos_Aires" }, - { label: "(UTC-02:00) Coordinated Universal Time-02", value: "Etc/GMT+2" }, - { label: "(UTC-01:00) Cape Verde Is.", value: "Atlantic/Cape_Verde" }, - { label: "Etc/UTC", value: "Etc/UTC" }, - { label: "(UTC+01:00) Amsterdam, Berlin, Rome, Vienna", value: "Europe/Berlin" }, - { label: "(UTC+02:00) Athens, Bucharest", value: "Europe/Bucharest" }, - { label: "(UTC+03:00) Moscow, St. Petersburg", value: "Europe/Moscow" }, - { label: "(UTC+04:00) Abu Dhabi, Muscat", value: "Asia/Dubai" }, - { label: "(UTC+05:00) Islamabad, Karachi", value: "Asia/Karachi" }, - { label: "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", value: "Asia/Kolkata" }, - { label: "(UTC+06:00) Dhaka", value: "Asia/Dhaka" }, - { label: "(UTC+07:00) Bangkok, Hanoi, Jakarta", value: "Asia/Bangkok" }, - { label: "(UTC+08:00) Beijing, Chongqing, Hong Kong", value: "Asia/Shanghai" }, - { label: "(UTC+09:00) Tokyo, Seoul", value: "Asia/Tokyo" }, - { label: "(UTC+10:00) Sydney, Melbourne", value: "Australia/Sydney" }, - { label: "User Choice", value: "UserChoice" }, + { label: trans("timeZone.UTC-12:00"), value: "Etc/GMT+12" }, + { label: trans("timeZone.UTC-11:00"), value: "Etc/GMT+11" }, + { label: trans("timeZone.UTC-10:00"), value: "Pacific/Honolulu" }, + { label: trans("timeZone.UTC-09:00"), value: "America/Anchorage" }, + { label: trans("timeZone.UTC-08:00"), value: "America/Tijuana" }, + { label: trans("timeZone.UTC-07:00"), value: "America/Los_Angeles" }, + { label: trans("timeZone.UTC-06:00"), value: "America/Chicago" }, + { label: trans("timeZone.UTC-05:00"), value: "America/New_York" }, + { label: trans("timeZone.UTC-04:00"), value: "America/Halifax" }, + { label: trans("timeZone.UTC-03:00"), value: "America/Argentina/Buenos_Aires" }, + { label: trans("timeZone.UTC-02:00"), value: "Etc/GMT+2" }, + { label: trans("timeZone.UTC-01:00"), value: "Atlantic/Cape_Verde" }, + { label: trans("timeZone.UTC+00:00"), value: "Etc/UTC" }, + { label: trans("timeZone.UTC+01:00"), value: "Europe/Berlin" }, + { label: trans("timeZone.UTC+02:00"), value: "Europe/Bucharest" }, + { label: trans("timeZone.UTC+03:00"), value: "Europe/Moscow" }, + { label: trans("timeZone.UTC+04:00"), value: "Asia/Dubai" }, + { label: trans("timeZone.UTC+05:00"), value: "Asia/Karachi" }, + { label: trans("timeZone.UTC+05:30"), value: "Asia/Kolkata" }, + { label: trans("timeZone.UTC+06:00"), value: "Asia/Dhaka" }, + { label: trans("timeZone.UTC+07:00"), value: "Asia/Bangkok" }, + { label: trans("timeZone.UTC+08:00"), value: "Asia/Shanghai" }, + { label: trans("timeZone.UTC+09:00"), value: "Asia/Tokyo" }, + { label: trans("timeZone.UTC+10:00"), value: "Australia/Sydney" }, + { label: trans("timeZone.UserChoice"), value: "UserChoice" }, ]; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 2087f4f87..aadc4f5d6 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -3612,6 +3612,34 @@ export const en = { "mobileNavIconSize": "Icon Size", }, +"timeZone": { + "UTC-12:00": "(UTC-12:00) Int'l Date Line W", + "UTC-11:00": "(UTC-11:00) UTC-11", + "UTC-10:00": "(UTC-10:00) Hawaii", + "UTC-09:00": "(UTC-09:00) Alaska", + "UTC-08:00": "(UTC-08:00) Baja CA", + "UTC-07:00": "(UTC-07:00) Pacific Time (US)", + "UTC-06:00": "(UTC-06:00) Central Time (US)", + "UTC-05:00": "(UTC-05:00) Eastern Time (US)", + "UTC-04:00": "(UTC-04:00) Atlantic Time", + "UTC-03:00": "(UTC-03:00) Buenos Aires", + "UTC-02:00": "(UTC-02:00) UTC-02", + "UTC-01:00": "(UTC-01:00) Cape Verde", + "UTC+00:00": "(UTC 00:00) UTC", + "UTC+01:00": "(UTC+01:00) Berlin, Rome", + "UTC+02:00": "(UTC+02:00) Athens, Bucharest", + "UTC+03:00": "(UTC+03:00) Moscow", + "UTC+04:00": "(UTC+04:00) Dubai, Muscat", + "UTC+05:00": "(UTC+05:00) Karachi", + "UTC+05:30": "(UTC+05:30) New Delhi", + "UTC+06:00": "(UTC+06:00) Dhaka", + "UTC+07:00": "(UTC+07:00) Bangkok", + "UTC+08:00": "(UTC+08:00) Beijing, HK", + "UTC+09:00": "(UTC+09:00) Tokyo, Seoul", + "UTC+10:00": "(UTC+10:00) Sydney", + "UserChoice": "User Choice" +}, + tour: { section1Title: "Steps", section1Subtitle: "Steps",