1
1
import _ , { noop } from "lodash" ;
2
2
import dayjs from "dayjs" ;
3
+ import utc from 'dayjs/plugin/utc' ;
4
+ import timezone from 'dayjs/plugin/timezone' ;
3
5
import { RecordConstructorToComp , RecordConstructorToView } from "lowcoder-core" ;
4
6
import {
5
7
BoolCodeControl ,
@@ -51,6 +53,10 @@ import { EditorContext } from "comps/editorState";
51
53
import { dropdownControl } from "comps/controls/dropdownControl" ;
52
54
import { timeZoneOptions } from "./timeZone" ;
53
55
56
+
57
+ dayjs . extend ( utc ) ;
58
+ dayjs . extend ( timezone ) ;
59
+
54
60
const EventOptions = [ changeEvent , focusEvent , blurEvent ] as const ;
55
61
56
62
const validationChildren = {
@@ -82,7 +88,7 @@ const commonChildren = {
82
88
...validationChildren ,
83
89
viewRef : RefControl < CommonPickerMethods > ,
84
90
inputFieldStyle : styleControl ( DateTimeStyle , 'inputFieldStyle' ) ,
85
- timeZone : dropdownControl ( timeZoneOptions , "DatelineStandard " ) ,
91
+ timeZone : dropdownControl ( timeZoneOptions , "Etc/UTC " ) ,
86
92
} ;
87
93
type CommonChildrenType = RecordConstructorToComp < typeof commonChildren > ;
88
94
@@ -452,21 +458,42 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [
452
458
depsConfig ( {
453
459
name : "value" ,
454
460
desc : trans ( "export.datePickerValueDesc" ) ,
455
- depKeys : [ "value" , "showTime" ] ,
461
+ depKeys : [ "value" , "showTime" , "timeZone" ] , // Include timeZone as a dependency
456
462
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 ;
459
474
} ,
460
475
} ) ,
461
476
depsConfig ( {
462
477
name : "formattedValue" ,
463
478
desc : trans ( "export.datePickerFormattedValueDesc" ) ,
464
- depKeys : [ "value" , "format" ] ,
479
+ depKeys : [ "value" , "format" , "timeZone" ] ,
465
480
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 '' ;
468
494
} ,
469
495
} ) ,
496
+
470
497
depsConfig ( {
471
498
name : "timestamp" ,
472
499
desc : trans ( "export.datePickerTimestampDesc" ) ,
@@ -486,92 +513,148 @@ export const DatePickerComp = withExposingConfigs(datePickerControl, [
486
513
value : { value : input . value } ,
487
514
} as any ) . validateStatus !== "success" ,
488
515
} ) ,
516
+ depsConfig ( {
517
+ name : "timeZone" ,
518
+ desc : trans ( "export.timeZoneDesc" ) ,
519
+ depKeys : [ "timeZone" ] ,
520
+ func : ( input ) => {
521
+ return input . timeZone ;
522
+ } ,
523
+ } ) ,
489
524
...CommonNameConfig ,
490
525
] ) ;
491
526
492
527
export let DateRangeComp = withExposingConfigs ( dateRangeControl , [
493
528
depsConfig ( {
494
529
name : "start" ,
495
530
desc : trans ( "export.dateRangeStartDesc" ) ,
496
- depKeys : [ "start" , "showTime" ] ,
531
+ depKeys : [ "start" , "showTime" , "timeZone" ] ,
497
532
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 ;
500
541
} ,
501
542
} ) ,
543
+
502
544
depsConfig ( {
503
545
name : "end" ,
504
546
desc : trans ( "export.dateRangeEndDesc" ) ,
505
- depKeys : [ "end" , "showTime" ] ,
547
+ depKeys : [ "end" , "showTime" , "timeZone" ] ,
506
548
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 ;
509
561
} ,
510
562
} ) ,
563
+
511
564
depsConfig ( {
512
565
name : "startTimestamp" ,
513
566
desc : trans ( "export.dateRangeStartTimestampDesc" ) ,
514
- depKeys : [ "start" ] ,
567
+ depKeys : [ "start" , "timeZone" ] ,
515
568
func : ( input ) => {
516
569
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 "" ;
518
575
} ,
519
576
} ) ,
520
577
depsConfig ( {
521
578
name : "endTimestamp" ,
522
579
desc : trans ( "export.dateRangeEndTimestampDesc" ) ,
523
- depKeys : [ "end" ] ,
580
+ depKeys : [ "end" , "timeZone" ] ,
524
581
func : ( input ) => {
525
582
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 "" ;
527
588
} ,
528
589
} ) ,
529
590
depsConfig ( {
530
591
name : "formattedValue" ,
531
592
desc : trans ( "export.dateRangeFormattedValueDesc" ) ,
532
- depKeys : [ "start" , "end" , "format" ] ,
593
+ depKeys : [ "start" , "end" , "format" , "timeZone" ] ,
533
594
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 '' ;
542
606
} ,
543
607
} ) ,
608
+
544
609
depsConfig ( {
545
610
name : "formattedStartValue" ,
546
611
desc : trans ( "export.dateRangeFormattedStartValueDesc" ) ,
547
- depKeys : [ "start" , "format" ] ,
612
+ depKeys : [ "start" , "format" , "timeZone" ] ,
548
613
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 '' ;
551
621
} ,
552
622
} ) ,
553
623
depsConfig ( {
554
624
name : "formattedEndValue" ,
555
625
desc : trans ( "export.dateRangeFormattedEndValueDesc" ) ,
556
- depKeys : [ "end" , "format" ] ,
626
+ depKeys : [ "end" , "format" , "timeZone" ] ,
557
627
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 '' ;
560
636
} ,
561
637
} ) ,
562
638
depsConfig ( {
563
639
name : "invalid" ,
564
640
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
+ } ,
575
658
} ) ,
576
659
...CommonNameConfig ,
577
660
] ) ;
0 commit comments