1
1
import _ from "lodash" ;
2
2
import dayjs from "dayjs" ;
3
- import utc from 'dayjs/plugin/utc' ;
4
- import timezone from 'dayjs/plugin/timezone' ;
5
- import customParseFormat from 'dayjs/plugin/customParseFormat' ;
6
3
import { RecordConstructorToComp , RecordConstructorToView } from "lowcoder-core" ;
7
4
import {
8
5
BoolCodeControl ,
@@ -58,9 +55,6 @@ import { EditorContext } from "comps/editorState";
58
55
import { dropdownControl } from "comps/controls/dropdownControl" ;
59
56
import { timeZoneOptions } from "./timeZone" ;
60
57
61
- dayjs . extend ( utc ) ;
62
- dayjs . extend ( timezone ) ;
63
- dayjs . extend ( customParseFormat ) ;
64
58
65
59
const EventOptions = [ changeEvent , focusEvent , blurEvent ] as const ;
66
60
@@ -90,7 +84,7 @@ const commonChildren = {
90
84
) ,
91
85
inputFieldStyle : styleControl ( DateTimeStyle , 'inputFieldStyle' ) ,
92
86
suffixIcon : withDefault ( IconControl , "/icon:regular/clock" ) ,
93
- timeZone : dropdownControl ( timeZoneOptions , "Etc/UTC" ) ,
87
+ timeZone : dropdownControl ( timeZoneOptions , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
94
88
viewRef : RefControl < CommonPickerMethods > ,
95
89
...validationChildren ,
96
90
} ;
@@ -130,7 +124,7 @@ function validate(
130
124
131
125
const childrenMap = {
132
126
value : stringExposingStateControl ( "value" ) ,
133
- userTimeZone : stringExposingStateControl ( "userTimeZone" , 'Etc/UTC' ) ,
127
+ userTimeZone : stringExposingStateControl ( "userTimeZone" , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
134
128
...commonChildren ,
135
129
...formDataChildren ,
136
130
} ;
@@ -275,7 +269,7 @@ export const timeRangeControl = (function () {
275
269
const childrenMap = {
276
270
start : stringExposingStateControl ( "start" ) ,
277
271
end : stringExposingStateControl ( "end" ) ,
278
- userRangeTimeZone : stringExposingStateControl ( "userRangeTimeZone" , 'Etc/UTC' ) ,
272
+ userRangeTimeZone : stringExposingStateControl ( "userRangeTimeZone" , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
279
273
...formDataChildren ,
280
274
...commonChildren ,
281
275
} ;
@@ -420,38 +414,39 @@ export const timeRangeControl = (function () {
420
414
. build ( ) ;
421
415
} ) ( ) ;
422
416
417
+ const getTimeZoneInfo = ( timeZone : any , othereTimeZone : any ) => {
418
+ const tz = timeZone === 'UserChoice' ? othereTimeZone : timeZone ;
419
+ return {
420
+ TimeZone : tz ,
421
+ Offset : dayjs ( ) . tz ( tz ) . format ( 'Z' ) // Get the UTC offset for the selected timezone
422
+ } ;
423
+ } ;
424
+
423
425
export const TimePickerComp = withExposingConfigs ( timePickerControl , [
424
426
new NameConfig ( "value" , trans ( "export.timePickerValueDesc" ) ) ,
425
427
426
428
depsConfig ( {
427
429
name : "formattedValue" ,
428
430
desc : trans ( "export.timePickerFormattedValueDesc" ) ,
429
- depKeys : [ "value" , "format" , "timeZone" , "userTimeZone" ] ,
431
+ depKeys : [ "value" , "format" , "timeZone" , "userTimeZone" ] ,
430
432
func : ( input ) => {
431
- let mom = null ;
432
-
433
- // Loop through TimeParser to find a valid format
434
- for ( const format of TimeParser ) {
435
- if ( dayjs . utc ( input . value , format ) . isValid ( ) ) {
436
- mom = dayjs . utc ( input . value , format ) ;
437
- break ;
438
- }
439
- }
440
-
441
- const tz = input . timeZone === 'UserChoice' ? input . userTimeZone : input . timeZone || 'UTC' ;
442
- return mom ?. isValid ( ) ? mom . tz ( tz ) . format ( input . format ) : '' ;
433
+ const mom = Boolean ( input . value ) ? dayjs ( input . value , TimeParser ) : null ;
434
+ const tz = input . timeZone === 'UserChoice' ? input . userTimeZone : input . timeZone ; // Get the selected timezone
435
+ const timeInTz = mom ?. clone ( ) . tz ( tz , true ) ; // Apply the selected timezone without altering the time itself (do not convert the time)
436
+ const formattedTimeWithoffset = timeInTz ?. format ( input ?. format ) ;
437
+ return mom ?. isValid ( ) ? ( ! input . format || input . format . includes ( 'Z' ) || input . format . includes ( 'z' ) ) // Check if format is not available or contains 'Z'
438
+ ? formattedTimeWithoffset // Return formattedDateWithoffset if format includes 'Z' or is not available
439
+ : mom . format ( input . format ) // Otherwise, return mom.format(input.format)
440
+ : "" ;
443
441
} ,
444
442
} ) ,
445
443
446
444
depsConfig ( {
447
445
name : "timeZone" ,
448
446
desc : trans ( "export.timeZoneDesc" ) ,
449
447
depKeys : [ "timeZone" , "userTimeZone" ] ,
450
- func : ( input ) => {
451
- return input . timeZone === 'UserChoice' ? input . userTimeZone : input . timeZone || 'UTC' ;
452
- } ,
448
+ func : ( input : { timeZone : any ; userTimeZone : any ; } ) => getTimeZoneInfo ( input . timeZone , input . userTimeZone )
453
449
} ) ,
454
-
455
450
depsConfig ( {
456
451
name : "invalid" ,
457
452
desc : trans ( "export.invalidDesc" ) ,
@@ -460,158 +455,87 @@ export const TimePickerComp = withExposingConfigs(timePickerControl, [
460
455
validate ( {
461
456
...input ,
462
457
value : { value : input . value } ,
463
- } ) . validateStatus !== "success" ,
458
+ } as any ) . validateStatus !== "success" ,
464
459
} ) ,
465
-
466
460
...CommonNameConfig ,
467
461
] ) ;
468
462
469
-
470
463
export let TimeRangeComp = withExposingConfigs ( timeRangeControl , [
471
- // new NameConfig("start", trans("export.timeRangeStartDesc")),
472
- // new NameConfig("end", trans("export.timeRangeEndDesc")),
473
- depsConfig ( {
474
- name : "start" ,
475
- desc : trans ( "export.timeRangeStartDesc" ) ,
476
- depKeys : [ "start" , "timeZone" , "userRangeTimeZone" ] ,
477
- func : ( input ) => {
478
- let start = null ;
479
-
480
- // Loop through TimeParser to find a valid format for start
481
- for ( const format of TimeParser ) {
482
- if ( dayjs . utc ( input . start , format ) . isValid ( ) ) {
483
- start = dayjs . utc ( input . start , format ) ;
484
- break ;
485
- }
486
- }
487
-
488
- if ( start ?. hour ( ) === 0 && start ?. minute ( ) === 0 && start ?. second ( ) === 0 ) {
489
- start = start ?. hour ( 12 ) ;
490
- }
491
-
492
- // Apply timezone conversion if valid
493
- const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
494
- return start ?. isValid ( ) ? start . tz ( tz ) . format ( input . format || "HH:mm:ss" ) : null ;
495
- } ,
496
- } ) ,
497
-
498
- depsConfig ( {
499
- name : "end" ,
500
- desc : trans ( "export.timeRangeEndDesc" ) ,
501
- depKeys : [ "end" , "timeZone" , "userRangeTimeZone" ] ,
502
- func : ( input ) => {
503
- let end = null ;
504
-
505
- // Loop through TimeParser to find a valid format for end
506
- for ( const format of TimeParser ) {
507
- if ( dayjs . utc ( input . end , format ) . isValid ( ) ) {
508
- end = dayjs . utc ( input . end , format ) ;
509
- break ;
510
- }
511
- }
512
-
513
- // Apply timezone conversion if valid
514
- const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
515
- return end ?. isValid ( ) ? end . tz ( tz ) . format ( input . format || "HH:mm:ss" ) : null ;
516
- } ,
517
- } ) ,
518
-
464
+ new NameConfig ( "start" , trans ( "export.timeRangeStartDesc" ) ) ,
465
+ new NameConfig ( "end" , trans ( "export.timeRangeEndDesc" ) ) ,
519
466
depsConfig ( {
520
467
name : "formattedValue" ,
521
468
desc : trans ( "export.timeRangeFormattedValueDesc" ) ,
522
469
depKeys : [ "start" , "end" , "format" , "timeZone" , "userRangeTimeZone" ] ,
523
470
func : ( input ) => {
524
- let start = null ;
525
- let end = null ;
526
- for ( const format of TimeParser ) {
527
- if ( dayjs . utc ( input . start , format ) . isValid ( ) ) {
528
- start = dayjs . utc ( input . start , format ) ;
529
- break ;
530
- }
531
- }
532
- for ( const format of TimeParser ) {
533
- if ( dayjs . utc ( input . end , format ) . isValid ( ) ) {
534
- end = dayjs . utc ( input . end , format ) ;
535
- break ;
536
- }
537
- }
538
-
539
- const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
540
- const formattedStart = start ?. isValid ( ) ? start . tz ( tz ) . format ( input . format ) : '' ;
541
- const formattedEnd = end ?. isValid ( ) ? end . tz ( tz ) . format ( input . format ) : '' ;
542
-
543
- return [ formattedStart , formattedEnd ] . filter ( Boolean ) . join ( " - " ) ;
471
+ const start = Boolean ( input . start ) ? dayjs ( input . start , TimeParser ) : null ;
472
+ const end = Boolean ( input . end ) ? dayjs ( input . end , TimeParser ) : null ;
473
+ const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone ; // Get the selected timezone
474
+ const startTimeInTz = start ?. clone ( ) . tz ( tz , true ) ; // Apply the selected timezone without altering the time itself (do not convert the time)
475
+ const endTimeInTz = end ?. clone ( ) . tz ( tz , true ) ;
476
+ return [
477
+ start ?. isValid ( ) && ( ! input . format || input . format . includes ( 'Z' ) || input . format . includes ( 'z' ) ) // Check if format is not available or contains 'Z'
478
+ ? startTimeInTz ?. format ( input ?. format ) // Return formattedTimeWithoffset if format includes 'Z' or is not available
479
+ : start ?. format ( input . format ) ,
480
+ end ?. isValid ( ) && ( ! input . format || input . format . includes ( 'Z' ) || input . format . includes ( 'z' ) )
481
+ ? endTimeInTz ?. format ( input ?. format )
482
+ : end ?. format ( input . format ) ,
483
+ ]
484
+ . filter ( ( item ) => item )
485
+ . join ( " - " ) ;
544
486
} ,
545
487
} ) ,
546
-
547
488
depsConfig ( {
548
489
name : "formattedStartValue" ,
549
490
desc : trans ( "export.timeRangeFormattedStartValueDesc" ) ,
550
- depKeys : [ "start" , "format" , "timeZone" , "userRangeTimeZone" ] ,
491
+ depKeys : [ "start" , "format" , "timeZone" , "userRangeTimeZone" ] ,
551
492
func : ( input ) => {
552
- let start = null ;
553
- for ( const format of TimeParser ) {
554
- if ( dayjs . utc ( input . start , format ) . isValid ( ) ) {
555
- start = dayjs . utc ( input . start , format ) ;
556
- break ;
557
- }
558
- }
559
-
560
- const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
561
- return start ?. isValid ( ) ? start . tz ( tz ) . format ( input . format ) : '' ;
493
+ const start = Boolean ( input . start ) ? dayjs ( input . start , TimeParser ) : null ;
494
+ const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone ;
495
+ const startTimeInTz = start ?. clone ( ) . tz ( tz , true ) ;
496
+ const formattedDate = startTimeInTz ?. format ( input ?. format ) ;
497
+ return start ?. isValid ( ) && ( ! input . format || input . format . includes ( 'Z' ) || input . format . includes ( 'z' ) )
498
+ ? formattedDate
499
+ : start ?. format ( input . format ) ;
562
500
} ,
563
501
} ) ,
564
-
565
502
depsConfig ( {
566
503
name : "formattedEndValue" ,
567
504
desc : trans ( "export.timeRangeFormattedEndValueDesc" ) ,
568
505
depKeys : [ "end" , "format" , "timeZone" , "userRangeTimeZone" ] ,
569
506
func : ( input ) => {
570
- let end = null ;
571
- for ( const format of TimeParser ) {
572
- if ( dayjs . utc ( input . end , format ) . isValid ( ) ) {
573
- end = dayjs . utc ( input . end , format ) ;
574
- break ;
575
- }
576
- }
577
-
578
- const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
579
- return end ?. isValid ( ) ? end . tz ( tz ) . format ( input . format ) : '' ;
507
+ const end = Boolean ( input . end ) ? dayjs ( input . end , TimeParser ) : null ;
508
+ const tz = input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone ;
509
+ const endTimeInTz = end ?. clone ( ) . tz ( tz , true ) ;
510
+ return end ?. isValid ( ) && ( ! input . format || input . format . includes ( 'Z' ) || input . format . includes ( 'z' ) )
511
+ ? endTimeInTz ?. format ( input ?. format )
512
+ : end ?. format ( input . format ) ;
580
513
} ,
581
514
} ) ,
582
-
583
515
depsConfig ( {
584
516
name : "timeZone" ,
585
517
desc : trans ( "export.timeZoneDesc" ) ,
586
518
depKeys : [ "timeZone" , "userRangeTimeZone" ] ,
587
- func : ( input ) => {
588
- return input . timeZone === 'UserChoice' ? input . userRangeTimeZone : input . timeZone || 'UTC' ;
589
- } ,
590
- } ) ,
519
+ func : ( input :any ) => getTimeZoneInfo ( input . timeZone , input . userRangeTimeZone )
591
520
521
+ } ) ,
592
522
depsConfig ( {
593
523
name : "invalid" ,
594
524
desc : trans ( "export.invalidDesc" ) ,
595
525
depKeys : [ "start" , "end" , "required" , "minTime" , "maxTime" , "customRule" ] ,
596
- func : ( input ) => {
597
- const startInvalid = validate ( {
526
+ func : ( input ) =>
527
+ validate ( {
598
528
...input ,
599
529
value : { value : input . start } ,
600
- } ) . validateStatus !== "success" ;
601
-
602
- const endInvalid = validate ( {
530
+ } ) . validateStatus !== "success" ||
531
+ validate ( {
603
532
...input ,
604
533
value : { value : input . end } ,
605
- } ) . validateStatus !== "success" ;
606
-
607
- return startInvalid || endInvalid ;
608
- } ,
534
+ } ) . validateStatus !== "success" ,
609
535
} ) ,
610
-
611
536
...CommonNameConfig ,
612
537
] ) ;
613
538
614
-
615
539
TimeRangeComp = withMethodExposing ( TimeRangeComp , [
616
540
...dateRefMethods ,
617
541
{
@@ -653,4 +577,4 @@ TimeRangeComp = withMethodExposing(TimeRangeComp, [
653
577
comp . children . end . getView ( ) . onChange ( data . end ) ;
654
578
} ,
655
579
} ,
656
- ] ) ;
580
+ ] ) ;
0 commit comments