Skip to content

Commit fb6330b

Browse files
committed
time zone activated
1 parent 8725cf7 commit fb6330b

File tree

4 files changed

+193
-85
lines changed

4 files changed

+193
-85
lines changed

client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx

Lines changed: 125 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import _, { noop } from "lodash";
22
import dayjs from "dayjs";
3+
import utc from 'dayjs/plugin/utc';
4+
import timezone from 'dayjs/plugin/timezone';
35
import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core";
46
import {
57
BoolCodeControl,
@@ -51,6 +53,10 @@ import { EditorContext } from "comps/editorState";
5153
import { dropdownControl } from "comps/controls/dropdownControl";
5254
import { timeZoneOptions } from "./timeZone";
5355

56+
57+
dayjs.extend(utc);
58+
dayjs.extend(timezone);
59+
5460
const EventOptions = [changeEvent, focusEvent, blurEvent] as const;
5561

5662
const validationChildren = {
@@ -82,7 +88,7 @@ const commonChildren = {
8288
...validationChildren,
8389
viewRef: RefControl<CommonPickerMethods>,
8490
inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'),
85-
timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"),
91+
timeZone: dropdownControl(timeZoneOptions, "Etc/UTC"),
8692
};
8793
type CommonChildrenType = RecordConstructorToComp<typeof commonChildren>;
8894

@@ -452,21 +458,42 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [
452458
depsConfig({
453459
name: "value",
454460
desc: trans("export.datePickerValueDesc"),
455-
depKeys: ["value", "showTime"],
461+
depKeys: ["value", "showTime", "timeZone"], // Include timeZone as a dependency
456462
func: (input) => {
457-
const mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null;
458-
return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null;
463+
let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null;
464+
465+
if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) {
466+
mom = mom?.hour(12); // Default to noon to avoid day shift
467+
}
468+
if (mom?.isValid()) {
469+
const tz = input.timeZone || 'UTC';
470+
const formattedDate = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT);
471+
return formattedDate;
472+
}
473+
return null;
459474
},
460475
}),
461476
depsConfig({
462477
name: "formattedValue",
463478
desc: trans("export.datePickerFormattedValueDesc"),
464-
depKeys: ["value", "format"],
479+
depKeys: ["value", "format", "timeZone"],
465480
func: (input) => {
466-
const mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null;
467-
return mom?.isValid() ? mom.format(input.format) : "";
481+
let mom = Boolean(input.value) ? dayjs(input.value, DateParser) : null;
482+
483+
if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) {
484+
mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts
485+
}
486+
487+
if (mom?.isValid()) {
488+
const tz = input.timeZone || 'UTC';
489+
const formattedTime = mom.tz(tz).format(input.format);
490+
491+
return formattedTime;
492+
}
493+
return '';
468494
},
469495
}),
496+
470497
depsConfig({
471498
name: "timestamp",
472499
desc: trans("export.datePickerTimestampDesc"),
@@ -486,92 +513,148 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [
486513
value: { value: input.value },
487514
} as any).validateStatus !== "success",
488515
}),
516+
depsConfig({
517+
name: "timeZone",
518+
desc: trans("export.timeZoneDesc"),
519+
depKeys: ["timeZone"],
520+
func: (input) => {
521+
return input.timeZone;
522+
},
523+
}),
489524
...CommonNameConfig,
490525
]);
491526

492527
export let DateRangeComp = withExposingConfigs(dateRangeControl, [
493528
depsConfig({
494529
name: "start",
495530
desc: trans("export.dateRangeStartDesc"),
496-
depKeys: ["start", "showTime"],
531+
depKeys: ["start", "showTime", "timeZone"],
497532
func: (input) => {
498-
const mom = Boolean(input.start) ? dayjs(input.start, DateParser): null;
499-
return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null;
533+
const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null;
534+
535+
if (mom?.isValid()) {
536+
const tz = input.timeZone || 'UTC';
537+
const formattedStart = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT);
538+
return formattedStart;
539+
}
540+
return null;
500541
},
501542
}),
543+
502544
depsConfig({
503545
name: "end",
504546
desc: trans("export.dateRangeEndDesc"),
505-
depKeys: ["end", "showTime"],
547+
depKeys: ["end", "showTime", "timeZone"],
506548
func: (input) => {
507-
const mom = Boolean(input.end) ? dayjs(input.end, DateParser): null;
508-
return mom?.isValid() ? mom.format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT) : null;
549+
let mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null;
550+
551+
if (!input.showTime && mom?.hour() === 0 && mom?.minute() === 0 && mom?.second() === 0) {
552+
mom = mom?.hour(12); // Default to noon to avoid timezone-related day shifts
553+
}
554+
555+
if (mom?.isValid()) {
556+
const tz = input.timeZone || 'UTC';
557+
const formattedEnd = mom.tz(tz).format(input.showTime ? DATE_TIME_FORMAT : DATE_FORMAT);
558+
return formattedEnd;
559+
}
560+
return null;
509561
},
510562
}),
563+
511564
depsConfig({
512565
name: "startTimestamp",
513566
desc: trans("export.dateRangeStartTimestampDesc"),
514-
depKeys: ["start"],
567+
depKeys: ["start", "timeZone"],
515568
func: (input) => {
516569
const mom = Boolean(input.start) ? dayjs(input.start, DateParser) : null;
517-
return mom?.isValid() ? mom.unix() : "";
570+
if (mom?.isValid()) {
571+
const tz = input.timeZone || 'UTC';
572+
return mom.tz(tz).unix();
573+
}
574+
return "";
518575
},
519576
}),
520577
depsConfig({
521578
name: "endTimestamp",
522579
desc: trans("export.dateRangeEndTimestampDesc"),
523-
depKeys: ["end"],
580+
depKeys: ["end", "timeZone"],
524581
func: (input) => {
525582
const mom = Boolean(input.end) ? dayjs(input.end, DateParser) : null;
526-
return mom?.isValid() ? mom.unix() : "";
583+
if (mom?.isValid()) {
584+
const tz = input.timeZone || 'UTC';
585+
return mom.tz(tz).unix();
586+
}
587+
return "";
527588
},
528589
}),
529590
depsConfig({
530591
name: "formattedValue",
531592
desc: trans("export.dateRangeFormattedValueDesc"),
532-
depKeys: ["start", "end", "format"],
593+
depKeys: ["start", "end", "format", "timeZone"],
533594
func: (input) => {
534-
const start = Boolean(input.start) ? dayjs(input.start, DateParser): null;
535-
const end = Boolean(input.end) ? dayjs(input.end, DateParser): null;
536-
return [
537-
start?.isValid() && start.format(input.format),
538-
end?.isValid() && end.format(input.format),
539-
]
540-
.filter((item) => item)
541-
.join(" - ");
595+
const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null;
596+
const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null;
597+
598+
if (start?.isValid() || end?.isValid()) {
599+
const tz = input.timeZone || 'UTC';
600+
const formattedStart = start?.isValid() ? start.tz(tz).format(input.format) : '';
601+
const formattedEnd = end?.isValid() ? end.tz(tz).format(input.format) : '';
602+
const formattedValue = [formattedStart, formattedEnd].filter(Boolean).join(" - ");
603+
return formattedValue;
604+
}
605+
return '';
542606
},
543607
}),
608+
544609
depsConfig({
545610
name: "formattedStartValue",
546611
desc: trans("export.dateRangeFormattedStartValueDesc"),
547-
depKeys: ["start", "format"],
612+
depKeys: ["start", "format", "timeZone"],
548613
func: (input) => {
549-
const start = Boolean(input.start) ? dayjs(input.start, DateParser): null;
550-
return start?.isValid() && start.format(input.format);
614+
const start = Boolean(input.start) ? dayjs(input.start, DateParser) : null;
615+
616+
if (start?.isValid()) {
617+
const tz = input.timeZone || 'UTC';
618+
const formattedStart = start.tz(tz).format(input.format);
619+
}
620+
return '';
551621
},
552622
}),
553623
depsConfig({
554624
name: "formattedEndValue",
555625
desc: trans("export.dateRangeFormattedEndValueDesc"),
556-
depKeys: ["end", "format"],
626+
depKeys: ["end", "format", "timeZone"],
557627
func: (input) => {
558-
const end = Boolean(input.end) ? dayjs(input.end, DateParser): null;
559-
return end?.isValid() && end.format(input.format);
628+
const end = Boolean(input.end) ? dayjs(input.end, DateParser) : null;
629+
630+
if (end?.isValid()) {
631+
const tz = input.timeZone || 'UTC';
632+
const formattedEnd = end.tz(tz).format(input.format);
633+
return formattedEnd;
634+
}
635+
return '';
560636
},
561637
}),
562638
depsConfig({
563639
name: "invalid",
564640
desc: trans("export.invalidDesc"),
565-
depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule"],
566-
func: (input) =>
567-
validate({
568-
...input,
569-
value: { value: input.start },
570-
}).validateStatus !== "success" ||
571-
validate({
572-
...input,
573-
value: { value: input.end },
574-
}).validateStatus !== "success",
641+
depKeys: ["start", "end", "required", "minTime", "maxTime", "minDate", "maxDate", "customRule", "timeZone"],
642+
func: (input) => {
643+
const tz = input.timeZone || 'UTC';
644+
const startDate = Boolean(input.start) ? dayjs(input.start, DateParser).tz(tz) : null;
645+
const endDate = Boolean(input.end) ? dayjs(input.end, DateParser).tz(tz) : null;
646+
const startInvalid = startDate && (!startDate.isValid() || (input.minDate && startDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && startDate.isAfter(dayjs(input.maxDate).tz(tz))));
647+
const endInvalid = endDate && (!endDate.isValid() || (input.minDate && endDate.isBefore(dayjs(input.minDate).tz(tz))) || (input.maxDate && endDate.isAfter(dayjs(input.maxDate).tz(tz))));
648+
return startInvalid || endInvalid;
649+
},
650+
}),
651+
depsConfig({
652+
name: "timeZone",
653+
desc: trans("export.timeZoneDesc"),
654+
depKeys: ["timeZone"],
655+
func: (input) => {
656+
return input.timeZone || 'UTC';
657+
},
575658
}),
576659
...CommonNameConfig,
577660
]);

client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import _ from "lodash";
22
import dayjs from "dayjs";
3+
import utc from 'dayjs/plugin/utc';
4+
import timezone from 'dayjs/plugin/timezone';
35
import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core";
46
import {
57
BoolCodeControl,
@@ -55,6 +57,8 @@ import { EditorContext } from "comps/editorState";
5557
import { dropdownControl } from "comps/controls/dropdownControl";
5658
import { timeZoneOptions } from "./timeZone";
5759

60+
dayjs.extend(utc);
61+
dayjs.extend(timezone);
5862
const EventOptions = [changeEvent, focusEvent, blurEvent] as const;
5963

6064
const validationChildren = {
@@ -83,7 +87,7 @@ const commonChildren = {
8387
),
8488
inputFieldStyle: styleControl(DateTimeStyle, 'inputFieldStyle'),
8589
suffixIcon: withDefault(IconControl, "/icon:regular/clock"),
86-
timeZone: dropdownControl(timeZoneOptions, "DatelineStandard"),
90+
timeZone: dropdownControl(timeZoneOptions, "Etc/UTC"),
8791
viewRef: RefControl<CommonPickerMethods>,
8892
...validationChildren,
8993
};
@@ -406,10 +410,20 @@ export const TimePickerComp = withExposingConfigs(timePickerControl, [
406410
depsConfig({
407411
name: "formattedValue",
408412
desc: trans("export.timePickerFormattedValueDesc"),
409-
depKeys: ["value", "format"],
413+
depKeys: ["value", "format", "timeZone"],
410414
func: (input) => {
411415
const mom = Boolean(input.value) ? dayjs(input.value, TimeParser) : null;
412-
return mom?.isValid() ? mom.format(input.format) : '';
416+
const tz = input.timeZone || 'UTC';
417+
const formattedTime = mom?.tz(tz).format("HH:mm:ss");
418+
return mom?.isValid() ? mom.tz(tz).format(input.format) : '';
419+
},
420+
}),
421+
depsConfig({
422+
name: "timeZone",
423+
desc: trans("export.timeZoneDesc"),
424+
depKeys: ["timeZone"],
425+
func: (input) => {
426+
return input.timeZone || 'UTC';
413427
},
414428
}),
415429
depsConfig({
@@ -431,34 +445,42 @@ export let TimeRangeComp = withExposingConfigs(timeRangeControl, [
431445
depsConfig({
432446
name: "formattedValue",
433447
desc: trans("export.timeRangeFormattedValueDesc"),
434-
depKeys: ["start", "end", "format"],
448+
depKeys: ["start", "end", "format", "timeZone"],
435449
func: (input) => {
436-
const start = Boolean(input.start) ? dayjs(input.start, TimeParser) : null;
437-
const end = Boolean(input.end) ? dayjs(input.end, TimeParser) : null;
438-
return [
439-
start?.isValid() && start.format(input.format),
440-
end?.isValid() && end.format(input.format),
441-
]
442-
.filter((item) => item)
443-
.join(" - ");
450+
const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null;
451+
const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null;
452+
const tz = input.timeZone || 'UTC';
453+
const formattedStart = start?.isValid() && start.tz(tz).format(input.format);
454+
const formattedEnd = end?.isValid() && end.tz(tz).format(input.format);
455+
return [formattedStart, formattedEnd].filter((item) => item).join(" - ");
444456
},
445457
}),
446458
depsConfig({
447459
name: "formattedStartValue",
448460
desc: trans("export.timeRangeFormattedStartValueDesc"),
449-
depKeys: ["start", "format"],
461+
depKeys: ["start", "format", "timeZone"],
450462
func: (input) => {
451-
const start = Boolean(input.start) ? dayjs(input.start, TimeParser) : null;
452-
return start?.isValid() && start.format(input.format);
463+
const start = Boolean(input.start) ? dayjs(input.start, TimeParser): null;
464+
const tz = input.timeZone || 'UTC';
465+
return start?.isValid() && start.tz(tz).format(input.format);
453466
},
454467
}),
455468
depsConfig({
456469
name: "formattedEndValue",
457470
desc: trans("export.timeRangeFormattedEndValueDesc"),
458-
depKeys: ["end", "format"],
471+
depKeys: ["end", "format", "timeZone"],
472+
func: (input) => {
473+
const end = Boolean(input.end) ? dayjs(input.end, TimeParser): null;
474+
const tz = input.timeZone || 'UTC';
475+
return end?.isValid() && end.tz(tz).format(input.format);
476+
},
477+
}),
478+
depsConfig({
479+
name: "timeZone",
480+
desc: trans("export.timeZoneDesc"),
481+
depKeys: ["timeZone"],
459482
func: (input) => {
460-
const end = Boolean(input.end) ? dayjs(input.end, TimeParser) : null;
461-
return end?.isValid() && end.format(input.format);
483+
return input.timeZone || 'UTC';
462484
},
463485
}),
464486
depsConfig({

0 commit comments

Comments
 (0)