gaoluyang
2026-06-29 27cd042df9aca0383a49f3514bc21958dd890912
src/views/im/utils/time.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,128 @@
import dayjs from 'dayjs'
// ====================================================================
// IM æ—¶é—´æ ¼å¼åŒ–
// ====================================================================
// 4 ç±»åœºæ™¯ï¼Œæ–‡æ¡ˆè§„则各有差异;统一走 dayjs,避免 raw Date æ•£ç‚¹å†™æ³•
const WEEKDAY_NAMES_FULL = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
const WEEKDAY_NAMES_SHORT = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
/**
 * æ¶ˆæ¯åˆ—表的时间分隔条
 *
 * - ä»Šå¤©ï¼šHH:mm
 * - æ˜¨å¤©ï¼šæ˜¨å¤© HH:mm
 * - ä¸€å‘¨å†…:周X HH:mm
 * - è¶…过一周:MM-DD HH:mm
 */
export function formatTimeTip(timestamp: number): string {
  if (!timestamp) {
    return ''
  }
  const target = dayjs(timestamp)
  const now = dayjs()
  const time = target.format('HH:mm')
  if (target.isSame(now, 'day')) {
    return time
  }
  if (target.isSame(now.subtract(1, 'day'), 'day')) {
    return `昨天 ${time}`
  }
  const diffDays = now.startOf('day').diff(target.startOf('day'), 'day')
  if (diffDays >= 2 && diffDays <= 6) {
    return `${WEEKDAY_NAMES_SHORT[target.day()]} ${time}`
  }
  return target.format('MM-DD HH:mm')
}
/**
 * ä¼šè¯åˆ—表里的时间(无 HH:mm åŽç¼€ï¼Œåªå±•示日期粒度)
 *
 * - ä»Šå¤©ï¼šHH:mm
 * - æ˜¨å¤©ï¼šæ˜¨å¤© HH:mm
 * - æœ¬å‘¨å†…(2-6 å¤©å‰ï¼‰ï¼šæ˜ŸæœŸX
 * - åŒå¹´å…¶ä»–:MM/DD
 * - è·¨å¹´ï¼šYYYY/MM/DD
 */
export function formatConversationTime(timestamp: number): string {
  if (!timestamp) {
    return ''
  }
  const target = dayjs(timestamp)
  const now = dayjs()
  if (target.isSame(now, 'day')) {
    return target.format('HH:mm')
  }
  if (target.isSame(now.subtract(1, 'day'), 'day')) {
    return `昨天 ${target.format('HH:mm')}`
  }
  // ç”¨ startOf('day') å…œåº•跨时间点的差值,避免接近凌晨时取到 1.x â†’ diff ç®—成 1 æ¼æŽ‰æ˜¨å¤©åˆ†æ”¯
  const diffDays = now.startOf('day').diff(target.startOf('day'), 'day')
  if (diffDays >= 2 && diffDays <= 6) {
    return WEEKDAY_NAMES_FULL[target.day()] || ''
  }
  return target.year() === now.year() ? target.format('MM/DD') : target.format('YYYY/MM/DD')
}
/**
 * åŽ†å²æ¶ˆæ¯æœç´¢åˆ—è¡¨çš„æ—¶é—´ï¼šå±•ç¤ºç»å¯¹æ—¥æœŸ
 *
 * - åŒå¹´ï¼šM月D日 HH:mm
 * - è·¨å¹´ï¼šYYYYå¹´M月D日 HH:mm
 */
export function formatHistoryTime(timestamp: number): string {
  if (!timestamp) {
    return ''
  }
  const target = dayjs(timestamp)
  return target.year() === dayjs().year()
    ? target.format('M月D日 HH:mm')
    : target.format('YYYYå¹´M月D日 HH:mm')
}
/** åˆå¹¶æ¶ˆæ¯è¯¦æƒ…列表里每行的时间:MM-DD HH:mm */
export function formatMergeItemTime(timestamp: number): string {
  if (!timestamp) {
    return ''
  }
  return dayjs(timestamp).format('MM-DD HH:mm')
}
/** RTC é€šè¯æ—¶é•¿ï¼ˆç§’)→ "00:06" / "1:23:45" */
export function formatCallDuration(seconds: number | undefined): string {
  const total = Math.max(0, Math.floor(seconds || 0))
  const h = Math.floor(total / 3600)
  const m = Math.floor((total % 3600) / 60)
  const s = total % 60
  const pad = (n: number) => String(n).padStart(2, '0')
  return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`
}
/** ç§’数格式化为 mm:ss */
export function formatSeconds(seconds?: number): string {
  const value = Math.max(0, Number(seconds || 0))
  const minute = Math.floor(value / 60)
  const second = Math.floor(value % 60)
  return `${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}`
}
/** æ ¼å¼åŒ–日期 */
export function formatDate(
  date?: Date | number | string,
  format = 'YYYY-MM-DD HH:mm:ss'
) {
  return dayjs(date).format(format)
}
/** æŽ¥é€šåˆ°ç»“束的通话时长;任一时间缺失返回 '-' */
export function resolveCallDuration(
  acceptTime: Date | string | undefined,
  endTime: Date | string | undefined
): string {
  if (!acceptTime || !endTime) {
    return '-'
  }
  const seconds = Math.floor((new Date(endTime).getTime() - new Date(acceptTime).getTime()) / 1000)
  return seconds > 0 ? formatCallDuration(seconds) : '-'
}