11import _ from "lodash" ;
22import dayjs from "dayjs" ;
3- import utc from 'dayjs/plugin/utc' ;
4- import timezone from 'dayjs/plugin/timezone' ;
5- import customParseFormat from 'dayjs/plugin/customParseFormat' ;
63import { RecordConstructorToComp , RecordConstructorToView } from "lowcoder-core" ;
74import {
85 BoolCodeControl ,
@@ -58,9 +55,6 @@ import { EditorContext } from "comps/editorState";
5855import { dropdownControl } from "comps/controls/dropdownControl" ;
5956import { timeZoneOptions } from "./timeZone" ;
6057
61- dayjs . extend ( utc ) ;
62- dayjs . extend ( timezone ) ;
63- dayjs . extend ( customParseFormat ) ;
6458
6559const EventOptions = [ changeEvent , focusEvent , blurEvent ] as const ;
6660
@@ -90,7 +84,7 @@ const commonChildren = {
9084 ) ,
9185 inputFieldStyle : styleControl ( DateTimeStyle , 'inputFieldStyle' ) ,
9286 suffixIcon : withDefault ( IconControl , "/icon:regular/clock" ) ,
93- timeZone : dropdownControl ( timeZoneOptions , "Etc/UTC" ) ,
87+ timeZone : dropdownControl ( timeZoneOptions , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
9488 viewRef : RefControl < CommonPickerMethods > ,
9589 ...validationChildren ,
9690} ;
@@ -130,7 +124,7 @@ function validate(
130124
131125const childrenMap = {
132126 value : stringExposingStateControl ( "value" ) ,
133- userTimeZone : stringExposingStateControl ( "userTimeZone" , 'Etc/UTC' ) ,
127+ userTimeZone : stringExposingStateControl ( "userTimeZone" , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
134128 ...commonChildren ,
135129 ...formDataChildren ,
136130} ;
@@ -275,7 +269,7 @@ export const timeRangeControl = (function () {
275269 const childrenMap = {
276270 start : stringExposingStateControl ( "start" ) ,
277271 end : stringExposingStateControl ( "end" ) ,
278- userRangeTimeZone : stringExposingStateControl ( "userRangeTimeZone" , 'Etc/UTC' ) ,
272+ userRangeTimeZone : stringExposingStateControl ( "userRangeTimeZone" , Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ) ,
279273 ...formDataChildren ,
280274 ...commonChildren ,
281275 } ;
@@ -420,38 +414,39 @@ export const timeRangeControl = (function () {
420414 . build ( ) ;
421415} ) ( ) ;
422416
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+
423425export const TimePickerComp = withExposingConfigs ( timePickerControl , [
424426 new NameConfig ( "value" , trans ( "export.timePickerValueDesc" ) ) ,
425427
426428 depsConfig ( {
427429 name : "formattedValue" ,
428430 desc : trans ( "export.timePickerFormattedValueDesc" ) ,
429- depKeys : [ "value" , "format" , "timeZone" , "userTimeZone" ] ,
431+ depKeys : [ "value" , "format" , "timeZone" , "userTimeZone" ] ,
430432 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+ : "" ;
443441 } ,
444442 } ) ,
445443
446444 depsConfig ( {
447445 name : "timeZone" ,
448446 desc : trans ( "export.timeZoneDesc" ) ,
449447 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 )
453449 } ) ,
454-
455450 depsConfig ( {
456451 name : "invalid" ,
457452 desc : trans ( "export.invalidDesc" ) ,
@@ -460,158 +455,87 @@ export const TimePickerComp = withExposingConfigs(timePickerControl, [
460455 validate ( {
461456 ...input ,
462457 value : { value : input . value } ,
463- } ) . validateStatus !== "success" ,
458+ } as any ) . validateStatus !== "success" ,
464459 } ) ,
465-
466460 ...CommonNameConfig ,
467461] ) ;
468462
469-
470463export 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" ) ) ,
519466 depsConfig ( {
520467 name : "formattedValue" ,
521468 desc : trans ( "export.timeRangeFormattedValueDesc" ) ,
522469 depKeys : [ "start" , "end" , "format" , "timeZone" , "userRangeTimeZone" ] ,
523470 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 ( " - " ) ;
544486 } ,
545487 } ) ,
546-
547488 depsConfig ( {
548489 name : "formattedStartValue" ,
549490 desc : trans ( "export.timeRangeFormattedStartValueDesc" ) ,
550- depKeys : [ "start" , "format" , "timeZone" , "userRangeTimeZone" ] ,
491+ depKeys : [ "start" , "format" , "timeZone" , "userRangeTimeZone" ] ,
551492 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 ) ;
562500 } ,
563501 } ) ,
564-
565502 depsConfig ( {
566503 name : "formattedEndValue" ,
567504 desc : trans ( "export.timeRangeFormattedEndValueDesc" ) ,
568505 depKeys : [ "end" , "format" , "timeZone" , "userRangeTimeZone" ] ,
569506 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 ) ;
580513 } ,
581514 } ) ,
582-
583515 depsConfig ( {
584516 name : "timeZone" ,
585517 desc : trans ( "export.timeZoneDesc" ) ,
586518 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 )
591520
521+ } ) ,
592522 depsConfig ( {
593523 name : "invalid" ,
594524 desc : trans ( "export.invalidDesc" ) ,
595525 depKeys : [ "start" , "end" , "required" , "minTime" , "maxTime" , "customRule" ] ,
596- func : ( input ) => {
597- const startInvalid = validate ( {
526+ func : ( input ) =>
527+ validate ( {
598528 ...input ,
599529 value : { value : input . start } ,
600- } ) . validateStatus !== "success" ;
601-
602- const endInvalid = validate ( {
530+ } ) . validateStatus !== "success" ||
531+ validate ( {
603532 ...input ,
604533 value : { value : input . end } ,
605- } ) . validateStatus !== "success" ;
606-
607- return startInvalid || endInvalid ;
608- } ,
534+ } ) . validateStatus !== "success" ,
609535 } ) ,
610-
611536 ...CommonNameConfig ,
612537] ) ;
613538
614-
615539TimeRangeComp = withMethodExposing ( TimeRangeComp , [
616540 ...dateRefMethods ,
617541 {
@@ -653,4 +577,4 @@ TimeRangeComp = withMethodExposing(TimeRangeComp, [
653577 comp . children . end . getView ( ) . onChange ( data . end ) ;
654578 } ,
655579 } ,
656- ] ) ;
580+ ] ) ;
0 commit comments