11import _ , { noop } from "lodash" ;
22import dayjs from "dayjs" ;
3+ import utc from 'dayjs/plugin/utc' ;
4+ import timezone from 'dayjs/plugin/timezone' ;
35import { RecordConstructorToComp , RecordConstructorToView } from "lowcoder-core" ;
46import {
57 BoolCodeControl ,
@@ -51,6 +53,10 @@ import { EditorContext } from "comps/editorState";
5153import { dropdownControl } from "comps/controls/dropdownControl" ;
5254import { timeZoneOptions } from "./timeZone" ;
5355
56+
57+ dayjs . extend ( utc ) ;
58+ dayjs . extend ( timezone ) ;
59+
5460const EventOptions = [ changeEvent , focusEvent , blurEvent ] as const ;
5561
5662const 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} ;
8793type 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
492527export 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] ) ;
0 commit comments