date_formatter.go

  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}