| // yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型 | 
| function pad(str, length = 2) { | 
|     str += '' | 
|     while (str.length < length) { | 
|         str = '0' + str | 
|     } | 
|     return str.slice(-length) | 
| } | 
|   | 
| const parser = { | 
|     yyyy: (dateObj) => { | 
|         return pad(dateObj.year, 4) | 
|     }, | 
|     yy: (dateObj) => { | 
|         return pad(dateObj.year) | 
|     }, | 
|     MM: (dateObj) => { | 
|         return pad(dateObj.month) | 
|     }, | 
|     M: (dateObj) => { | 
|         return dateObj.month | 
|     }, | 
|     dd: (dateObj) => { | 
|         return pad(dateObj.day) | 
|     }, | 
|     d: (dateObj) => { | 
|         return dateObj.day | 
|     }, | 
|     hh: (dateObj) => { | 
|         return pad(dateObj.hour) | 
|     }, | 
|     h: (dateObj) => { | 
|         return dateObj.hour | 
|     }, | 
|     mm: (dateObj) => { | 
|         return pad(dateObj.minute) | 
|     }, | 
|     m: (dateObj) => { | 
|         return dateObj.minute | 
|     }, | 
|     ss: (dateObj) => { | 
|         return pad(dateObj.second) | 
|     }, | 
|     s: (dateObj) => { | 
|         return dateObj.second | 
|     }, | 
|     SSS: (dateObj) => { | 
|         return pad(dateObj.millisecond, 3) | 
|     }, | 
|     S: (dateObj) => { | 
|         return dateObj.millisecond | 
|     }, | 
| } | 
|   | 
| // 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12 | 
| function getDate(time) { | 
|     if (time instanceof Date) { | 
|         return time | 
|     } | 
|     switch (typeof time) { | 
|         case 'string': | 
|             { | 
|                 // 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000 | 
|                 if (time.indexOf('T') > -1) { | 
|                     return new Date(time) | 
|                 } | 
|                 return new Date(time.replace(/-/g, '/')) | 
|             } | 
|         default: | 
|             return new Date(time) | 
|     } | 
| } | 
|   | 
| export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') { | 
|     if (!date && date !== 0) { | 
|         return '' | 
|     } | 
|     date = getDate(date) | 
|     const dateObj = { | 
|         year: date.getFullYear(), | 
|         month: date.getMonth() + 1, | 
|         day: date.getDate(), | 
|         hour: date.getHours(), | 
|         minute: date.getMinutes(), | 
|         second: date.getSeconds(), | 
|         millisecond: date.getMilliseconds() | 
|     } | 
|     const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/ | 
|     let flag = true | 
|     let result = format | 
|     while (flag) { | 
|         flag = false | 
|         result = result.replace(tokenRegExp, function(matched) { | 
|             flag = true | 
|             return parser[matched](dateObj) | 
|         }) | 
|     } | 
|     return result | 
| } | 
|   | 
| export function friendlyDate(time, { | 
|     locale = 'zh', | 
|     threshold = [60000, 3600000], | 
|     format = 'yyyy/MM/dd hh:mm:ss' | 
| }) { | 
|     if (time === '-') { | 
|         return time | 
|     } | 
|     if (!time && time !== 0) { | 
|         return '' | 
|     } | 
|     const localeText = { | 
|         zh: { | 
|             year: '年', | 
|             month: '月', | 
|             day: '天', | 
|             hour: '小时', | 
|             minute: '分钟', | 
|             second: '秒', | 
|             ago: '前', | 
|             later: '后', | 
|             justNow: '刚刚', | 
|             soon: '马上', | 
|             template: '{num}{unit}{suffix}' | 
|         }, | 
|         en: { | 
|             year: 'year', | 
|             month: 'month', | 
|             day: 'day', | 
|             hour: 'hour', | 
|             minute: 'minute', | 
|             second: 'second', | 
|             ago: 'ago', | 
|             later: 'later', | 
|             justNow: 'just now', | 
|             soon: 'soon', | 
|             template: '{num} {unit} {suffix}' | 
|         } | 
|     } | 
|     const text = localeText[locale] || localeText.zh | 
|     let date = getDate(time) | 
|     let ms = date.getTime() - Date.now() | 
|     let absMs = Math.abs(ms) | 
|     if (absMs < threshold[0]) { | 
|         return ms < 0 ? text.justNow : text.soon | 
|     } | 
|     if (absMs >= threshold[1]) { | 
|         return formatDate(date, format) | 
|     } | 
|     let num | 
|     let unit | 
|     let suffix = text.later | 
|     if (ms < 0) { | 
|         suffix = text.ago | 
|         ms = -ms | 
|     } | 
|     const seconds = Math.floor((ms) / 1000) | 
|     const minutes = Math.floor(seconds / 60) | 
|     const hours = Math.floor(minutes / 60) | 
|     const days = Math.floor(hours / 24) | 
|     const months = Math.floor(days / 30) | 
|     const years = Math.floor(months / 12) | 
|     switch (true) { | 
|         case years > 0: | 
|             num = years | 
|             unit = text.year | 
|             break | 
|         case months > 0: | 
|             num = months | 
|             unit = text.month | 
|             break | 
|         case days > 0: | 
|             num = days | 
|             unit = text.day | 
|             break | 
|         case hours > 0: | 
|             num = hours | 
|             unit = text.hour | 
|             break | 
|         case minutes > 0: | 
|             num = minutes | 
|             unit = text.minute | 
|             break | 
|         default: | 
|             num = seconds | 
|             unit = text.second | 
|             break | 
|     } | 
|   | 
|     if (locale === 'en') { | 
|         if (num === 1) { | 
|             num = 'a' | 
|         } else { | 
|             unit += 's' | 
|         } | 
|     } | 
|   | 
|     return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g, | 
|         suffix) | 
| } |