@@ -7,6 +7,7 @@ type DateTimeProps = {
77 includeSeconds ?: boolean ;
88 includeTime ?: boolean ;
99 showTimezone ?: boolean ;
10+ previousDate ?: Date | string | null ; // Add optional previous date for comparison
1011} ;
1112
1213export const DateTime = ( {
@@ -70,20 +71,116 @@ export function formatDateTime(
7071 } ) . format ( date ) ;
7172}
7273
73- export const DateTimeAccurate = ( { date, timeZone = "UTC" } : DateTimeProps ) => {
74+ // New component that only shows date when it changes
75+ export const SmartDateTime = ( { date, previousDate = null , timeZone = "UTC" } : DateTimeProps ) => {
7476 const locales = useLocales ( ) ;
75-
7677 const realDate = typeof date === "string" ? new Date ( date ) : date ;
78+ const realPrevDate = previousDate
79+ ? typeof previousDate === "string"
80+ ? new Date ( previousDate )
81+ : previousDate
82+ : null ;
83+
84+ // Initial formatted values
85+ const initialTimeOnly = formatTimeOnly ( realDate , timeZone , locales ) ;
86+ const initialWithDate = formatSmartDateTime ( realDate , timeZone , locales ) ;
87+
88+ // State for the formatted time
89+ const [ formattedDateTime , setFormattedDateTime ] = useState < string > (
90+ realPrevDate && isSameDay ( realDate , realPrevDate ) ? initialTimeOnly : initialWithDate
91+ ) ;
92+
93+ useEffect ( ( ) => {
94+ const resolvedOptions = Intl . DateTimeFormat ( ) . resolvedOptions ( ) ;
95+ const userTimeZone = resolvedOptions . timeZone ;
96+
97+ // Check if we should show the date
98+ const showDatePart = ! realPrevDate || ! isSameDay ( realDate , realPrevDate ) ;
99+
100+ // Format with appropriate function
101+ setFormattedDateTime (
102+ showDatePart
103+ ? formatSmartDateTime ( realDate , userTimeZone , locales )
104+ : formatTimeOnly ( realDate , userTimeZone , locales )
105+ ) ;
106+ } , [ locales , realDate , realPrevDate ] ) ;
107+
108+ return < Fragment > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ Fragment > ;
109+ } ;
110+
111+ // Helper function to check if two dates are on the same day
112+ function isSameDay ( date1 : Date , date2 : Date ) : boolean {
113+ return (
114+ date1 . getFullYear ( ) === date2 . getFullYear ( ) &&
115+ date1 . getMonth ( ) === date2 . getMonth ( ) &&
116+ date1 . getDate ( ) === date2 . getDate ( )
117+ ) ;
118+ }
119+
120+ // Format with date and time
121+ function formatSmartDateTime ( date : Date , timeZone : string , locales : string [ ] ) : string {
122+ return new Intl . DateTimeFormat ( locales , {
123+ month : "short" ,
124+ day : "numeric" ,
125+ hour : "numeric" ,
126+ minute : "numeric" ,
127+ second : "numeric" ,
128+ timeZone,
129+ // @ts -ignore fractionalSecondDigits works in most modern browsers
130+ fractionalSecondDigits : 3 ,
131+ } ) . format ( date ) ;
132+ }
133+
134+ // Format time only
135+ function formatTimeOnly ( date : Date , timeZone : string , locales : string [ ] ) : string {
136+ return new Intl . DateTimeFormat ( locales , {
137+ hour : "numeric" ,
138+ minute : "numeric" ,
139+ second : "numeric" ,
140+ timeZone,
141+ // @ts -ignore fractionalSecondDigits works in most modern browsers
142+ fractionalSecondDigits : 3 ,
143+ } ) . format ( date ) ;
144+ }
77145
78- const initialFormattedDateTime = formatDateTimeAccurate ( realDate , timeZone , locales ) ;
146+ export const DateTimeAccurate = ( {
147+ date,
148+ timeZone = "UTC" ,
149+ previousDate = null ,
150+ } : DateTimeProps ) => {
151+ const locales = useLocales ( ) ;
152+ const realDate = typeof date === "string" ? new Date ( date ) : date ;
153+ const realPrevDate = previousDate
154+ ? typeof previousDate === "string"
155+ ? new Date ( previousDate )
156+ : previousDate
157+ : null ;
158+
159+ // Use the new Smart formatting if previousDate is provided
160+ const initialFormattedDateTime = realPrevDate
161+ ? isSameDay ( realDate , realPrevDate )
162+ ? formatTimeOnly ( realDate , timeZone , locales )
163+ : formatDateTimeAccurate ( realDate , timeZone , locales )
164+ : formatDateTimeAccurate ( realDate , timeZone , locales ) ;
79165
80166 const [ formattedDateTime , setFormattedDateTime ] = useState < string > ( initialFormattedDateTime ) ;
81167
82168 useEffect ( ( ) => {
83169 const resolvedOptions = Intl . DateTimeFormat ( ) . resolvedOptions ( ) ;
84-
85- setFormattedDateTime ( formatDateTimeAccurate ( realDate , resolvedOptions . timeZone , locales ) ) ;
86- } , [ locales , realDate ] ) ;
170+ const userTimeZone = resolvedOptions . timeZone ;
171+
172+ if ( realPrevDate ) {
173+ // Smart formatting based on whether date changed
174+ setFormattedDateTime (
175+ isSameDay ( realDate , realPrevDate )
176+ ? formatTimeOnly ( realDate , userTimeZone , locales )
177+ : formatDateTimeAccurate ( realDate , userTimeZone , locales )
178+ ) ;
179+ } else {
180+ // Default behavior when no previous date
181+ setFormattedDateTime ( formatDateTimeAccurate ( realDate , userTimeZone , locales ) ) ;
182+ }
183+ } , [ locales , realDate , realPrevDate ] ) ;
87184
88185 return < Fragment > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ Fragment > ;
89186} ;
@@ -96,7 +193,34 @@ function formatDateTimeAccurate(date: Date, timeZone: string, locales: string[])
96193 minute : "numeric" ,
97194 second : "numeric" ,
98195 timeZone,
99- // @ts -ignore this works in 92.5% of browsers https://caniuse.com/mdn-javascript_builtins_intl_datetimeformat_datetimeformat_options_parameter_options_fractionalseconddigits_parameter
196+ // @ts -ignore fractionalSecondDigits works in most modern browsers
197+ fractionalSecondDigits : 3 ,
198+ } ) . format ( date ) ;
199+
200+ return formattedDateTime ;
201+ }
202+
203+ export const DateTimeShort = ( { date, timeZone = "UTC" } : DateTimeProps ) => {
204+ const locales = useLocales ( ) ;
205+ const realDate = typeof date === "string" ? new Date ( date ) : date ;
206+ const initialFormattedDateTime = formatDateTimeShort ( realDate , timeZone , locales ) ;
207+ const [ formattedDateTime , setFormattedDateTime ] = useState < string > ( initialFormattedDateTime ) ;
208+
209+ useEffect ( ( ) => {
210+ const resolvedOptions = Intl . DateTimeFormat ( ) . resolvedOptions ( ) ;
211+ setFormattedDateTime ( formatDateTimeShort ( realDate , resolvedOptions . timeZone , locales ) ) ;
212+ } , [ locales , realDate ] ) ;
213+
214+ return < Fragment > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ Fragment > ;
215+ } ;
216+
217+ function formatDateTimeShort ( date : Date , timeZone : string , locales : string [ ] ) : string {
218+ const formattedDateTime = new Intl . DateTimeFormat ( locales , {
219+ hour : "numeric" ,
220+ minute : "numeric" ,
221+ second : "numeric" ,
222+ timeZone,
223+ // @ts -ignore fractionalSecondDigits works in most modern browsers
100224 fractionalSecondDigits : 3 ,
101225 } ) . format ( date ) ;
102226
0 commit comments