11'use strict' ;
22
33/**
4- * formatTime - Convert a Date / timestamp into a human readable relative time.
4+ * zarcotime format function
55 *
6- * Supported inputs :
7- * - Date instance
8- * - number (milliseconds or seconds; if < 1e12 treated as seconds)
6+ * Accepts :
7+ * - Date
8+ * - number (ms or seconds)
99 * - ISO date string
1010 *
1111 * Options:
12- * - now: number|Date - override "now" (useful for tests)
13- * - numeric: 'auto' | 'always' - when 'auto' can return "yesterday"/"tomorrow" for +/-1 day
14- * - units: array - custom unit order
12+ * - now: Date|number|string - override current time
13+ * - numeric: 'auto' | 'always' (default: 'always')
14+ * - style: 'long' | 'short' (default: 'long')
15+ * - locale: string (e.g., 'en', 'fr', 'auto' to use system)
16+ * - units: custom unit definitions
1517 *
16- * Returns: string like "1 minute ago" or "in 2 days" or "just now"
18+ * Returns human-friendly relative time string.
1719 */
1820
1921const DEFAULT_UNITS = [
@@ -29,50 +31,74 @@ const DEFAULT_UNITS = [
2931function toMillis ( input ) {
3032 if ( input instanceof Date ) return input . getTime ( ) ;
3133 if ( typeof input === 'number' ) {
32- // if seems like seconds (10 digits), convert to ms
34+ // treat small numbers (<1e12) as seconds
3335 if ( Math . abs ( input ) < 1e12 ) return input * 1000 ;
3436 return input ;
3537 }
36- // try parse as string
37- const parsed = Date . parse ( String ( input ) ) ;
38- if ( ! isNaN ( parsed ) ) return parsed ;
38+ if ( typeof input === 'string' ) {
39+ const s = input . trim ( ) . toLowerCase ( ) ;
40+ if ( s === 'now' ) return Date . now ( ) ;
41+ const parsed = Date . parse ( input ) ;
42+ if ( ! isNaN ( parsed ) ) return parsed ;
43+ }
3944 throw new TypeError ( 'Invalid date input. Accepts Date, number (ms or s), or date string.' ) ;
4045}
4146
42- function pluralize ( value , unit ) {
47+ function fallbackPluralize ( value , unit ) {
4348 return value === 1 ? unit : unit + 's' ;
4449}
4550
51+ function tryIntlFormat ( value , unit , locale , style , isFuture , numericOpt = "always" ) {
52+ if ( typeof Intl !== 'undefined' && Intl . RelativeTimeFormat ) {
53+ try {
54+ const rtf = new Intl . RelativeTimeFormat ( locale || undefined , {
55+ numeric : numericOpt ,
56+ style : style || 'long'
57+ } ) ;
58+ const n = isFuture ? value : - value ;
59+ return rtf . format ( n , unit ) ;
60+ } catch ( e ) {
61+ return null ;
62+ }
63+ }
64+ return null ;
65+ }
66+
4667function formatTime ( then , opts = { } ) {
4768 if ( then == null ) throw new TypeError ( '`then` is required' ) ;
4869 const now = opts . now != null ? toMillis ( opts . now ) : Date . now ( ) ;
4970 const ts = toMillis ( then ) ;
50- const diff = now - ts ; // positive => past, negative => future
71+ const diff = now - ts ;
5172 const abs = Math . abs ( diff ) ;
5273
5374 const units = Array . isArray ( opts . units ) ? opts . units : DEFAULT_UNITS ;
75+ const style = opts . style || 'long' ;
76+ const locale = opts . locale || undefined ;
77+ const numeric = opts . numeric || 'always' ;
5478
55- // special case: very small diff
5679 if ( abs < 1000 ) {
5780 return diff >= 0 ? 'just now' : 'right now' ;
5881 }
5982
6083 for ( const u of units ) {
6184 if ( abs >= u . ms ) {
6285 const val = Math . floor ( abs / u . ms ) ;
63- // handle 'auto' numeric words for days
64- if ( opts . numeric === 'auto' && u . name === 'day' && ( val === 1 ) ) {
86+
87+ if ( numeric === 'auto' && u . name === 'day' && val === 1 ) {
6588 if ( diff >= 0 ) return 'yesterday' ;
6689 return 'tomorrow' ;
6790 }
6891
69- const unitName = pluralize ( val , u . name ) ;
92+ const isFuture = diff < 0 ;
93+ const intlResult = tryIntlFormat ( val , u . name , locale , style , isFuture , numeric ) ;
94+ if ( intlResult ) return intlResult ;
95+
96+ const unitName = fallbackPluralize ( val , u . name ) ;
7097 if ( diff >= 0 ) return `${ val } ${ unitName } ago` ;
7198 return `in ${ val } ${ unitName } ` ;
7299 }
73100 }
74101
75- // fallback if nothing matched (shouldn't happen)
76102 const seconds = Math . floor ( abs / 1000 ) ;
77103 return diff >= 0 ? `${ seconds } seconds ago` : `in ${ seconds } seconds` ;
78104}
0 commit comments