date-format.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /**
  2. * Date Formatting Utilities with Locale Support
  3. * Provides locale-aware date formatting using date-fns and next-intl
  4. */
  5. import { format, formatDistance, formatRelative } from "date-fns";
  6. import { zhCN, zhTW, enUS, ru, ja } from "date-fns/locale";
  7. import type { Locale } from "date-fns";
  8. /**
  9. * Map next-intl locale codes to date-fns locale objects
  10. */
  11. const LOCALE_MAP: Record<string, Locale> = {
  12. "zh-CN": zhCN,
  13. "zh-TW": zhTW,
  14. en: enUS,
  15. ru: ru,
  16. ja: ja,
  17. };
  18. /**
  19. * Get date-fns locale object from next-intl locale string
  20. * @param locale - next-intl locale code (e.g., "zh-CN", "en")
  21. * @returns date-fns Locale object
  22. */
  23. export function getDateFnsLocale(locale: string): Locale {
  24. return LOCALE_MAP[locale] || enUS;
  25. }
  26. /**
  27. * Format date with locale support
  28. * @param date - Date to format
  29. * @param formatString - Format string (e.g., "yyyy-MM-dd", "PPP")
  30. * @param locale - next-intl locale code
  31. * @returns Formatted date string
  32. */
  33. export function formatDate(
  34. date: Date | number | string,
  35. formatString: string,
  36. locale: string = "zh-CN"
  37. ): string {
  38. const dateObj = typeof date === "string" ? new Date(date) : date;
  39. const dateFnsLocale = getDateFnsLocale(locale);
  40. return format(dateObj, formatString, { locale: dateFnsLocale });
  41. }
  42. /**
  43. * Format distance between two dates with locale support
  44. * @param date - Date to compare
  45. * @param baseDate - Base date (defaults to now)
  46. * @param locale - next-intl locale code
  47. * @param options - Additional options
  48. * @returns Formatted distance string (e.g., "3 days ago", "3天前")
  49. */
  50. export function formatDateDistance(
  51. date: Date | number | string,
  52. baseDate: Date | number = new Date(),
  53. locale: string = "zh-CN",
  54. options?: {
  55. addSuffix?: boolean;
  56. includeSeconds?: boolean;
  57. }
  58. ): string {
  59. const dateObj = typeof date === "string" ? new Date(date) : date;
  60. const baseDateObj = typeof baseDate === "string" ? new Date(baseDate) : baseDate;
  61. const dateFnsLocale = getDateFnsLocale(locale);
  62. return formatDistance(dateObj, baseDateObj, {
  63. locale: dateFnsLocale,
  64. addSuffix: options?.addSuffix ?? true,
  65. includeSeconds: options?.includeSeconds,
  66. });
  67. }
  68. /**
  69. * Format date relative to now with locale support
  70. * @param date - Date to format
  71. * @param baseDate - Base date (defaults to now)
  72. * @param locale - next-intl locale code
  73. * @returns Formatted relative string (e.g., "yesterday at 3:00 PM", "昨天下午3:00")
  74. */
  75. export function formatDateRelative(
  76. date: Date | number | string,
  77. baseDate: Date | number = new Date(),
  78. locale: string = "zh-CN"
  79. ): string {
  80. const dateObj = typeof date === "string" ? new Date(date) : date;
  81. const baseDateObj = typeof baseDate === "string" ? new Date(baseDate) : baseDate;
  82. const dateFnsLocale = getDateFnsLocale(locale);
  83. return formatRelative(dateObj, baseDateObj, { locale: dateFnsLocale });
  84. }
  85. /**
  86. * Common date format patterns for different locales
  87. */
  88. export const DATE_FORMATS = {
  89. "zh-CN": {
  90. short: "yyyy-MM-dd",
  91. medium: "yyyy年MM月dd日",
  92. long: "yyyy年MM月dd日 HH:mm:ss",
  93. time: "HH:mm:ss",
  94. monthDay: "MM月dd日",
  95. },
  96. "zh-TW": {
  97. short: "yyyy-MM-dd",
  98. medium: "yyyy年MM月dd日",
  99. long: "yyyy年MM月dd日 HH:mm:ss",
  100. time: "HH:mm:ss",
  101. monthDay: "MM月dd日",
  102. },
  103. en: {
  104. short: "MM/dd/yyyy",
  105. medium: "MMM dd, yyyy",
  106. long: "MMMM dd, yyyy HH:mm:ss",
  107. time: "HH:mm:ss",
  108. monthDay: "MMM dd",
  109. },
  110. ru: {
  111. short: "dd.MM.yyyy",
  112. medium: "dd MMM yyyy",
  113. long: "dd MMMM yyyy HH:mm:ss",
  114. time: "HH:mm:ss",
  115. monthDay: "dd MMM",
  116. },
  117. ja: {
  118. short: "yyyy/MM/dd",
  119. medium: "yyyy年MM月dd日",
  120. long: "yyyy年MM月dd日 HH:mm:ss",
  121. time: "HH:mm:ss",
  122. monthDay: "MM月dd日",
  123. },
  124. } as const;
  125. /**
  126. * Get locale-specific date format pattern
  127. * @param locale - next-intl locale code
  128. * @param type - Format type
  129. * @returns Format pattern string
  130. */
  131. export function getLocaleDateFormat(
  132. locale: string,
  133. type: "short" | "medium" | "long" | "time" | "monthDay" = "short"
  134. ): string {
  135. const formats = DATE_FORMATS[locale as keyof typeof DATE_FORMATS] || DATE_FORMATS["zh-CN"];
  136. return formats[type];
  137. }