Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 191 lines 5.0 kB view raw
1import {useCallback} from 'react' 2import {type I18n} from '@lingui/core' 3import {defineMessage, msg, plural} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {differenceInSeconds} from 'date-fns' 6 7export type DateDiffFormat = 'long' | 'short' 8 9type DateDiff = { 10 value: number 11 unit: 'now' | 'second' | 'minute' | 'hour' | 'day' | 'month' 12 earlier: Date 13 later: Date 14} 15 16const NOW = 5 17const MINUTE = 60 18const HOUR = MINUTE * 60 19const DAY = HOUR * 24 20const MONTH_30 = DAY * 30 21 22export function useGetTimeAgo({future = false}: {future?: boolean} = {}) { 23 const {i18n} = useLingui() 24 return useCallback( 25 ( 26 earlier: number | string | Date, 27 later: number | string | Date, 28 options?: {format: DateDiffFormat}, 29 ) => { 30 const diff = dateDiff(earlier, later, future ? 'up' : 'down') 31 return formatDateDiff({diff, i18n, format: options?.format}) 32 }, 33 [i18n, future], 34 ) 35} 36 37/** 38 * Returns the difference between `earlier` and `later` dates, based on 39 * opinionated rules. 40 * 41 * - All month are considered exactly 30 days. 42 * - Dates assume `earlier` <= `later`, and will otherwise return 'now'. 43 * - All values round down 44 */ 45export function dateDiff( 46 earlier: number | string | Date, 47 later: number | string | Date, 48 rounding: 'up' | 'down' = 'down', 49): DateDiff { 50 let diff = { 51 value: 0, 52 unit: 'now' as DateDiff['unit'], 53 } 54 const e = new Date(earlier) 55 const l = new Date(later) 56 const diffSeconds = differenceInSeconds(l, e) 57 58 if (diffSeconds < NOW) { 59 diff = { 60 value: 0, 61 unit: 'now' as DateDiff['unit'], 62 } 63 } else if (diffSeconds < MINUTE) { 64 diff = { 65 value: diffSeconds, 66 unit: 'second' as DateDiff['unit'], 67 } 68 } else if (diffSeconds < HOUR) { 69 const value = 70 rounding === 'up' 71 ? Math.ceil(diffSeconds / MINUTE) 72 : Math.floor(diffSeconds / MINUTE) 73 diff = { 74 value, 75 unit: 'minute' as DateDiff['unit'], 76 } 77 } else if (diffSeconds < DAY) { 78 const value = 79 rounding === 'up' 80 ? Math.ceil(diffSeconds / HOUR) 81 : Math.floor(diffSeconds / HOUR) 82 diff = { 83 value, 84 unit: 'hour' as DateDiff['unit'], 85 } 86 } else if (diffSeconds < MONTH_30) { 87 const value = 88 rounding === 'up' 89 ? Math.ceil(diffSeconds / DAY) 90 : Math.floor(diffSeconds / DAY) 91 diff = { 92 value, 93 unit: 'day' as DateDiff['unit'], 94 } 95 } else { 96 const value = 97 rounding === 'up' 98 ? Math.ceil(diffSeconds / MONTH_30) 99 : Math.floor(diffSeconds / MONTH_30) 100 diff = { 101 value, 102 unit: 'month' as DateDiff['unit'], 103 } 104 } 105 106 return { 107 ...diff, 108 earlier: e, 109 later: l, 110 } 111} 112 113/** 114 * Accepts a `DateDiff` and teturns the difference between `earlier` and 115 * `later` dates, formatted as a natural language string. 116 * 117 * - All month are considered exactly 30 days. 118 * - Dates assume `earlier` <= `later`, and will otherwise return 'now'. 119 * - Differences >= 360 days are returned as the "M/D/YYYY" string 120 * - All values round down 121 */ 122export function formatDateDiff({ 123 diff, 124 format = 'short', 125 i18n, 126}: { 127 diff: DateDiff 128 format?: DateDiffFormat 129 i18n: I18n 130}): string { 131 const long = format === 'long' 132 133 switch (diff.unit) { 134 case 'now': { 135 return i18n._(msg`now`) 136 } 137 case 'second': { 138 return long 139 ? i18n._(plural(diff.value, {one: '# second', other: '# seconds'})) 140 : i18n._( 141 defineMessage({ 142 message: `${diff.value}s`, 143 comment: `How many seconds have passed, displayed in a narrow form`, 144 }), 145 ) 146 } 147 case 'minute': { 148 return long 149 ? i18n._(plural(diff.value, {one: '# minute', other: '# minutes'})) 150 : i18n._( 151 defineMessage({ 152 message: `${diff.value}m`, 153 comment: `How many minutes have passed, displayed in a narrow form`, 154 }), 155 ) 156 } 157 case 'hour': { 158 return long 159 ? i18n._(plural(diff.value, {one: '# hour', other: '# hours'})) 160 : i18n._( 161 defineMessage({ 162 message: `${diff.value}h`, 163 comment: `How many hours have passed, displayed in a narrow form`, 164 }), 165 ) 166 } 167 case 'day': { 168 return long 169 ? i18n._(plural(diff.value, {one: '# day', other: '# days'})) 170 : i18n._( 171 defineMessage({ 172 message: `${diff.value}d`, 173 comment: `How many days have passed, displayed in a narrow form`, 174 }), 175 ) 176 } 177 case 'month': { 178 if (diff.value < 12) { 179 return long 180 ? i18n._(plural(diff.value, {one: '# month', other: '# months'})) 181 : i18n._( 182 defineMessage({ 183 message: plural(diff.value, {one: '#mo', other: '#mo'}), 184 comment: `How many months have passed, displayed in a narrow form`, 185 }), 186 ) 187 } 188 return i18n.date(new Date(diff.earlier)) 189 } 190 } 191}