1package i18n
2
3import (
4 "fmt"
5 "time"
6)
7
8// DateFormatter formats dates and times according to locale rules.
9type DateFormatter struct {
10 locale *Locale
11}
12
13// NewDateFormatter creates a date formatter for a locale.
14func NewDateFormatter(locale *Locale) *DateFormatter {
15 return &DateFormatter{
16 locale: locale,
17 }
18}
19
20// FormatDate formats a time according to the given layout.
21func (f *DateFormatter) FormatDate(t time.Time, layout string) string {
22 return t.Format(layout)
23}
24
25// FormatTime formats just the time portion.
26func (f *DateFormatter) FormatTime(t time.Time) string {
27 return t.Format("15:04")
28}
29
30// FormatDateTime formats both date and time.
31func (f *DateFormatter) FormatDateTime(t time.Time) string {
32 return t.Format("2006-01-02 15:04")
33}
34
35// FormatRelative formats a time relative to now (e.g., "5 minutes ago").
36// This should use translated strings from the message catalog.
37func (f *DateFormatter) FormatRelative(t time.Time) string {
38 now := time.Now()
39 duration := now.Sub(t)
40
41 // Future times
42 if duration < 0 {
43 duration = -duration
44 return formatFutureDuration(duration)
45 }
46
47 // Past times
48 return formatPastDuration(duration)
49}
50
51// formatPastDuration formats a duration as "X ago".
52func formatPastDuration(d time.Duration) string {
53 seconds := int(d.Seconds())
54 minutes := seconds / 60
55 hours := minutes / 60
56 days := hours / 24
57
58 switch {
59 case seconds < 60:
60 return "just now"
61 case minutes == 1:
62 return "1 minute ago"
63 case minutes < 60:
64 return fmt.Sprintf("%d minutes ago", minutes)
65 case hours == 1:
66 return "1 hour ago"
67 case hours < 24:
68 return fmt.Sprintf("%d hours ago", hours)
69 case days == 1:
70 return "1 day ago"
71 case days < 7:
72 return fmt.Sprintf("%d days ago", days)
73 case days < 30:
74 weeks := days / 7
75 if weeks == 1 {
76 return "1 week ago"
77 }
78 return fmt.Sprintf("%d weeks ago", weeks)
79 case days < 365:
80 months := days / 30
81 if months == 1 {
82 return "1 month ago"
83 }
84 return fmt.Sprintf("%d months ago", months)
85 default:
86 years := days / 365
87 if years == 1 {
88 return "1 year ago"
89 }
90 return fmt.Sprintf("%d years ago", years)
91 }
92}
93
94// formatFutureDuration formats a duration as "in X".
95func formatFutureDuration(d time.Duration) string {
96 seconds := int(d.Seconds())
97 minutes := seconds / 60
98 hours := minutes / 60
99 days := hours / 24
100
101 switch {
102 case seconds < 60:
103 return "in a moment"
104 case minutes == 1:
105 return "in 1 minute"
106 case minutes < 60:
107 return fmt.Sprintf("in %d minutes", minutes)
108 case hours == 1:
109 return "in 1 hour"
110 case hours < 24:
111 return fmt.Sprintf("in %d hours", hours)
112 case days == 1:
113 return "in 1 day"
114 case days < 7:
115 return fmt.Sprintf("in %d days", days)
116 default:
117 return "in the future"
118 }
119}