package quando import ( "fmt" "time" ) // Lang represents a language for internationalization (i18n) in formatting. // // Currently supports 17 languages: EN, DE, ES, FR, IT, PT, NL, PL, RU, TR, VI, // JA, KO, ZhCN, ZhTW, HI, TH. // // Language affects: // - Format(Long): month and weekday names // - FormatLayout: custom layouts with month/weekday names // - Duration.Human(): time unit names // // Language does NOT affect: // - ISO, EU, US, RFC2822 formats (always language-independent) // - Numeric outputs (WeekNumber, Quarter, DayOfYear) // // See i18n.go for translation data and helper methods. type Lang string const ( // EN represents English language. EN Lang = "en" // DE represents German (Deutsch) language. DE Lang = "de" // ES represents Spanish (Español) language. ES Lang = "es" // FR represents French (Français) language. FR Lang = "fr" // IT represents Italian (Italiano) language. IT Lang = "it" // PT represents Portuguese (Português) language. PT Lang = "pt" // NL represents Dutch (Nederlands) language. NL Lang = "nl" // PL represents Polish (Polski) language. PL Lang = "pl" // RU represents Russian (Русский) language. RU Lang = "ru" // TR represents Turkish (Türkçe) language. TR Lang = "tr" // VI represents Vietnamese (Tiếng Việt) language. VI Lang = "vi" // JA represents Japanese (日本語) language. JA Lang = "ja" // KO represents Korean (한국어) language. KO Lang = "ko" // ZhCN represents Chinese Simplified (简体中文) language. ZhCN Lang = "zh-cn" // ZhTW represents Chinese Traditional (繁體中文) language. ZhTW Lang = "zh-tw" // HI represents Hindi (हिन्दी) language. HI Lang = "hi" // TH represents Thai (ไทย) language. TH Lang = "th" ) // Date wraps time.Time and provides a fluent API for date operations. // All operations return new Date instances, making Date immutable and thread-safe. // // The Date type supports the full range of Go's time.Time (approximately // year 0001 to year 9999, with extensions beyond that range). type Date struct { t time.Time lang Lang } // Now returns a Date representing the current moment in time. // The Date uses the local timezone by default. // // Example: // // now := quando.Now() func Now() Date { return Date{ t: time.Now(), lang: EN, // Default language } } // From converts a time.Time to a Date. // This is the primary way to create a Date from an existing time value. // // Example: // // t := time.Date(2026, 2, 9, 12, 0, 0, 0, time.UTC) // date := quando.From(t) func From(t time.Time) Date { return Date{ t: t, lang: EN, // Default language } } // FromUnix creates a Date from a Unix timestamp (seconds since January 1, 1970 UTC). // Supports negative timestamps for dates before 1970. // // Example: // // date := quando.FromUnix(1707480000) // Feb 9, 2024 // past := quando.FromUnix(-946684800) // Jan 1, 1940 func FromUnix(sec int64) Date { return Date{ t: time.Unix(sec, 0), lang: EN, // Default language } } // Time returns the underlying time.Time value. // Use this to convert back to standard library time when needed. // // Example: // // date := quando.Now() // t := date.Time() func (d Date) Time() time.Time { return d.t } // Unix returns the Unix timestamp (seconds since January 1, 1970 UTC). // The value may be negative for dates before 1970. // // Example: // // date := quando.Now() // timestamp := date.Unix() func (d Date) Unix() int64 { return d.t.Unix() } // WithLang returns a new Date with the specified language for formatting. // This does not modify the date or time, only the language used for formatting operations. // // Example: // // date := quando.Now().WithLang(quando.DE) func (d Date) WithLang(lang Lang) Date { return Date{ t: d.t, lang: lang, } } // In converts the date to the specified IANA timezone. // Returns error for invalid timezone names. Never panics. // // The method uses the IANA Timezone Database (e.g., "America/New_York", "Europe/Berlin", "UTC"). // Daylight Saving Time (DST) transitions are handled automatically by the timezone database. // // When combined with arithmetic operations, DST-safe behavior is preserved: // Add(1, Days) means "same wall clock time on next calendar day", not "24 hours later". // // Example: // // utc := quando.From(time.Date(2026, 6, 15, 12, 0, 0, 0, time.UTC)) // berlin, err := utc.In("Europe/Berlin") // // berlin is 2026-06-15 14:00:00 CEST (UTC+2 in summer) // // For a list of valid timezone names, see: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones func (d Date) In(location string) (Date, error) { // Validate input if location == "" { return Date{}, fmt.Errorf("timezone location is empty: %w", ErrInvalidTimezone) } // Load timezone from IANA database loc, err := time.LoadLocation(location) if err != nil { return Date{}, fmt.Errorf("loading timezone %q: %w", location, ErrInvalidTimezone) } // Convert time to new timezone converted := d.t.In(loc) // Return new Date with converted time, preserving language return Date{ t: converted, lang: d.lang, }, nil } // String returns the ISO 8601 representation of the date (YYYY-MM-DD HH:MM:SS). // This method is called automatically by fmt.Println and similar functions. func (d Date) String() string { return d.t.Format("2006-01-02 15:04:05") }