|
|
@@ -1,837 +0,0 @@
|
|
|
-package ut
|
|
|
-
|
|
|
-import (
|
|
|
- "errors"
|
|
|
- "fmt"
|
|
|
- "strings"
|
|
|
- "time"
|
|
|
-)
|
|
|
-
|
|
|
-// // Era denotes the Era types
|
|
|
-// type Era uint8
|
|
|
-
|
|
|
-// // Era types
|
|
|
-// const (
|
|
|
-// AD Era = iota
|
|
|
-// BC
|
|
|
-// )
|
|
|
-
|
|
|
-const (
|
|
|
- am = "am"
|
|
|
- pm = "pm"
|
|
|
-)
|
|
|
-
|
|
|
-// Standard Formats for Dates, Times & DateTimes
|
|
|
-// These are the options to pass to the Format method.
|
|
|
-const (
|
|
|
- DateFormatFull = iota
|
|
|
- DateFormatLong
|
|
|
- DateFormatMedium
|
|
|
- DateFormatShort
|
|
|
- TimeFormatFull
|
|
|
- TimeFormatLong
|
|
|
- TimeFormatMedium
|
|
|
- TimeFormatShort
|
|
|
- DateTimeFormatFull
|
|
|
- DateTimeFormatLong
|
|
|
- DateTimeFormatMedium
|
|
|
- DateTimeFormatShort
|
|
|
-)
|
|
|
-
|
|
|
-// Characters with special meaning in a datetime string:
|
|
|
-// Technically, all a-z,A-Z characters should be treated as if they represent a
|
|
|
-// datetime unit - but not all actually do. Any a-z,A-Z character that is
|
|
|
-// intended to be rendered as a literal a-z,A-Z character should be surrounded
|
|
|
-// by single quotes. There is currently no support for rendering a single quote
|
|
|
-// literal.
|
|
|
-const (
|
|
|
- datetimeFormatUnitEra = 'G'
|
|
|
- datetimeFormatUnitYear = 'y'
|
|
|
- datetimeFormatUnitMonth = 'M'
|
|
|
- datetimeFormatUnitDayOfWeek = 'E'
|
|
|
- datetimeFormatUnitDay = 'd'
|
|
|
- datetimeFormatUnitHour12 = 'h'
|
|
|
- datetimeFormatUnitHour24 = 'H'
|
|
|
- datetimeFormatUnitMinute = 'm'
|
|
|
- datetimeFormatUnitSecond = 's'
|
|
|
- datetimeFormatUnitPeriod = 'a'
|
|
|
- datetimeForamtUnitQuarter = 'Q'
|
|
|
- datetimeFormatUnitTimeZone1 = 'z'
|
|
|
- datetimeFormatUnitTimeZone2 = 'v'
|
|
|
-
|
|
|
- datetimeFormatTimeSeparator = ':'
|
|
|
- datetimeFormatLiteral = '\''
|
|
|
-)
|
|
|
-
|
|
|
-// The sequence length of datetime unit characters indicates how they should be
|
|
|
-// rendered.
|
|
|
-const (
|
|
|
- datetimeFormatLength1Plus = 1
|
|
|
- datetimeFormatLength2Plus = 2
|
|
|
- datetimeFormatLengthAbbreviated = 3
|
|
|
- datetimeFormatLengthWide = 4
|
|
|
- datetimeFormatLengthNarrow = 5
|
|
|
-)
|
|
|
-
|
|
|
-// datetime formats are a sequences off datetime components and string literals
|
|
|
-const (
|
|
|
- datetimePatternComponentUnit = iota
|
|
|
- datetimePatternComponentLiteral
|
|
|
-)
|
|
|
-
|
|
|
-// A list of currently unsupported units:
|
|
|
-// These still need to be implemented. For now they are ignored.
|
|
|
-var (
|
|
|
- datetimeFormatUnitCutset = []rune{
|
|
|
- datetimeForamtUnitQuarter,
|
|
|
- datetimeFormatUnitTimeZone1,
|
|
|
- datetimeFormatUnitTimeZone2,
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-type datetimePatternComponent struct {
|
|
|
- pattern string
|
|
|
- componentType int
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateFull formats the time with the current locales full date format
|
|
|
-func (c Calendar) FmtDateFull(t time.Time) string {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.Format(t, c.Formats.DateEra.BC.Full)
|
|
|
- }
|
|
|
-
|
|
|
- return c.Format(t, c.Formats.DateEra.AD.Full)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateLong formats the time with the current locales long date format
|
|
|
-func (c Calendar) FmtDateLong(t time.Time) string {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.Format(t, c.Formats.DateEra.BC.Long)
|
|
|
- }
|
|
|
-
|
|
|
- return c.Format(t, c.Formats.DateEra.AD.Long)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateMedium formats the time with the current locales medium date format
|
|
|
-func (c Calendar) FmtDateMedium(t time.Time) string {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.Format(t, c.Formats.DateEra.BC.Medium)
|
|
|
- }
|
|
|
-
|
|
|
- return c.Format(t, c.Formats.DateEra.AD.Medium)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateShort formats the time with the current locales short date format
|
|
|
-func (c Calendar) FmtDateShort(t time.Time) string {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.Format(t, c.Formats.DateEra.BC.Short)
|
|
|
- }
|
|
|
-
|
|
|
- return c.Format(t, c.Formats.DateEra.AD.Short)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeFull formats the time with the current locales full time format
|
|
|
-func (c Calendar) FmtTimeFull(t time.Time) string {
|
|
|
- return c.Format(t, c.Formats.Time.Full)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeLong formats the time with the current locales long time format
|
|
|
-func (c Calendar) FmtTimeLong(t time.Time) string {
|
|
|
- return c.Format(t, c.Formats.Time.Long)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeMedium formats the time with the current locales medium time format
|
|
|
-func (c Calendar) FmtTimeMedium(t time.Time) string {
|
|
|
- return c.Format(t, c.Formats.Time.Medium)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeShort formats the time with the current locales short time format
|
|
|
-func (c Calendar) FmtTimeShort(t time.Time) string {
|
|
|
- return c.Format(t, c.Formats.Time.Short)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeFull formats the time with the current locales full data & time format
|
|
|
-func (c Calendar) FmtDateTimeFull(t time.Time) string {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Full
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Full
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Full, dt, c.Formats.Time.Full)
|
|
|
- return c.Format(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeLong formats the time with the current locales long data & time format
|
|
|
-func (c Calendar) FmtDateTimeLong(t time.Time) string {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Long
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Long
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Long, dt, c.Formats.Time.Long)
|
|
|
- return c.Format(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeMedium formats the time with the current locales medium data & time format
|
|
|
-func (c Calendar) FmtDateTimeMedium(t time.Time) string {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Medium
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Medium
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Medium, dt, c.Formats.Time.Medium)
|
|
|
- return c.Format(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeShort formats the time with the current locales short data & time format
|
|
|
-func (c Calendar) FmtDateTimeShort(t time.Time) string {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Short
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Short
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Short, dt, c.Formats.Time.Short)
|
|
|
- return c.Format(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateFullSafe formats the time with the current locales full date format
|
|
|
-func (c Calendar) FmtDateFullSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.BC.Full)
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.AD.Full)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateLongSafe formats the time with the current locales long date format
|
|
|
-func (c Calendar) FmtDateLongSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.BC.Long)
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.AD.Long)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateMediumSafe formats the time with the current locales medium date format
|
|
|
-func (c Calendar) FmtDateMediumSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.BC.Medium)
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.AD.Medium)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateShortSafe formats the time with the current locales short date format
|
|
|
-func (c Calendar) FmtDateShortSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.BC.Short)
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatSafe(t, c.Formats.DateEra.AD.Short)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeFullSafe formats the time with the current locales full time format
|
|
|
-func (c Calendar) FmtTimeFullSafe(t time.Time) (string, error) {
|
|
|
- return c.FormatSafe(t, c.Formats.Time.Full)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeLongSafe formats the time with the current locales long time format
|
|
|
-func (c Calendar) FmtTimeLongSafe(t time.Time) (string, error) {
|
|
|
- return c.FormatSafe(t, c.Formats.Time.Long)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeMediumSafe formats the time with the current locales medium time format
|
|
|
-func (c Calendar) FmtTimeMediumSafe(t time.Time) (string, error) {
|
|
|
- return c.FormatSafe(t, c.Formats.Time.Medium)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtTimeShortSafe formats the time with the current locales short time format
|
|
|
-func (c Calendar) FmtTimeShortSafe(t time.Time) (string, error) {
|
|
|
- return c.FormatSafe(t, c.Formats.Time.Short)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeFullSafe formats the time with the current locales full data & time format
|
|
|
-func (c Calendar) FmtDateTimeFullSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Full
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Full
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Full, dt, c.Formats.Time.Full)
|
|
|
- return c.FormatSafe(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeLongSafe formats the time with the current locales long data & time format
|
|
|
-func (c Calendar) FmtDateTimeLongSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Long
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Long
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Long, dt, c.Formats.Time.Long)
|
|
|
- return c.FormatSafe(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeMediumSafe formats the time with the current locales medium data & time format
|
|
|
-func (c Calendar) FmtDateTimeMediumSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Medium
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Medium
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Medium, dt, c.Formats.Time.Medium)
|
|
|
- return c.FormatSafe(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FmtDateTimeShortSafe formats the time with the current locales short data & time format
|
|
|
-func (c Calendar) FmtDateTimeShortSafe(t time.Time) (string, error) {
|
|
|
-
|
|
|
- dt := c.Formats.DateEra.AD.Short
|
|
|
-
|
|
|
- if t.Year() < 0 {
|
|
|
- dt = c.Formats.DateEra.BC.Short
|
|
|
- }
|
|
|
-
|
|
|
- pattern := getDateTimePattern(c.Formats.DateTime.Short, dt, c.Formats.Time.Short)
|
|
|
- return c.FormatSafe(t, pattern)
|
|
|
-}
|
|
|
-
|
|
|
-// FormatSafe takes a time struct and a format and returns a formatted
|
|
|
-// string. Callers should use a DateFormat, TimeFormat, or DateTimeFormat
|
|
|
-// constant.
|
|
|
-func (c Calendar) FormatSafe(datetime time.Time, pattern string) (string, error) {
|
|
|
- parsed, err := c.parseDateTimeFormat(pattern)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
-
|
|
|
- return c.formatDateTime(datetime, parsed)
|
|
|
-}
|
|
|
-
|
|
|
-// Format takes a time struct and a format and returns a formatted
|
|
|
-// string. Callers should use a DateFormat, TimeFormat, or DateTimeFormat
|
|
|
-// constant.
|
|
|
-// NOTE: this function returns blank when an error occurs
|
|
|
-func (c Calendar) Format(datetime time.Time, pattern string) string {
|
|
|
-
|
|
|
- dt, err := c.FormatSafe(datetime, pattern)
|
|
|
- if err != nil {
|
|
|
- return ""
|
|
|
- }
|
|
|
-
|
|
|
- return dt
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTime takes a time.Time and a sequence of parsed pattern components
|
|
|
-// and returns an internationalized string representation.
|
|
|
-func (c Calendar) formatDateTime(datetime time.Time, pattern []*datetimePatternComponent) (string, error) {
|
|
|
- formatted := ""
|
|
|
- for _, component := range pattern {
|
|
|
- if component.componentType == datetimePatternComponentLiteral {
|
|
|
- formatted += component.pattern
|
|
|
- } else {
|
|
|
- f, err := c.formatDateTimeComponent(datetime, component.pattern)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
- formatted += f
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return strings.Trim(formatted, " ,"), nil
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponent renders a single component of a datetime format
|
|
|
-// pattern.
|
|
|
-func (c Calendar) formatDateTimeComponent(datetime time.Time, pattern string) (string, error) {
|
|
|
- switch pattern[0:1] {
|
|
|
- case string(datetimeFormatUnitEra):
|
|
|
- return c.formatDateTimeComponentEra(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitYear):
|
|
|
- return c.formatDateTimeComponentYear(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitMonth):
|
|
|
- return c.formatDateTimeComponentMonth(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitDayOfWeek):
|
|
|
- return c.formatDateTimeComponentDayOfWeek(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitDay):
|
|
|
- return c.formatDateTimeComponentDay(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitHour12):
|
|
|
- return c.formatDateTimeComponentHour12(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitHour24):
|
|
|
- return c.formatDateTimeComponentHour24(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitMinute):
|
|
|
- return c.formatDateTimeComponentMinute(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitSecond):
|
|
|
- return c.formatDateTimeComponentSecond(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitPeriod):
|
|
|
- return c.formatDateTimeComponentPeriod(datetime, len(pattern))
|
|
|
- case string(datetimeForamtUnitQuarter):
|
|
|
- return c.formatDateTimeComponentQuarter(datetime, len(pattern))
|
|
|
- case string(datetimeFormatUnitTimeZone1):
|
|
|
- fallthrough
|
|
|
- case string(datetimeFormatUnitTimeZone2):
|
|
|
- return c.formatDateTimeComponentTimeZone(datetime, len(pattern))
|
|
|
- }
|
|
|
-
|
|
|
- return "", errors.New("unknown datetime format unit: " + pattern[0:1])
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentEra renders an era component.
|
|
|
-// TODO: not yet implemented
|
|
|
-func (c Calendar) formatDateTimeComponentEra(datetime time.Time, length int) (string, error) {
|
|
|
-
|
|
|
- if datetime.Year() < 0 {
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.FormatNames.Eras.BC.Narrow, nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- return c.FormatNames.Eras.BC.Abbrev, nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.FormatNames.Eras.BC.Full, nil
|
|
|
- default:
|
|
|
- return "", nil
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.FormatNames.Eras.AD.Narrow, nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- return c.FormatNames.Eras.AD.Abbrev, nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.FormatNames.Eras.AD.Full, nil
|
|
|
- default:
|
|
|
- return "", nil
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentYear renders a year component.
|
|
|
-func (c Calendar) formatDateTimeComponentYear(datetime time.Time, length int) (string, error) {
|
|
|
- year := datetime.Year()
|
|
|
-
|
|
|
- if year < 0 {
|
|
|
- year = year * -1
|
|
|
- }
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.formatDateTimeComponentYearLengthWide(year), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- return c.formatDateTimeComponentYearLength2Plus(year), nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.formatDateTimeComponentYearLengthWide(year), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported year length: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentYearLength2Plus renders a 2-digit year component.
|
|
|
-func (c Calendar) formatDateTimeComponentYearLength2Plus(year int) string {
|
|
|
- yearShort := year % 100
|
|
|
-
|
|
|
- if yearShort < 10 {
|
|
|
- return fmt.Sprintf("0%d", yearShort)
|
|
|
- }
|
|
|
-
|
|
|
- return fmt.Sprintf("%d", yearShort)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentYearLength2Plus renders a full-year component - for
|
|
|
-// all modern dates, that's four digits.
|
|
|
-func (c Calendar) formatDateTimeComponentYearLengthWide(year int) string {
|
|
|
- return fmt.Sprintf("%d", year)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonth renders a month component.
|
|
|
-func (c Calendar) formatDateTimeComponentMonth(datetime time.Time, length int) (string, error) {
|
|
|
-
|
|
|
- month := datetime.Month()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.formatDateTimeComponentMonth1Plus(month), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- return c.formatDateTimeComponentMonth2Plus(month), nil
|
|
|
- case datetimeFormatLengthAbbreviated:
|
|
|
- return c.formatDateTimeComponentMonthAbbreviated(month), nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.formatDateTimeComponentMonthWide(month), nil
|
|
|
- case datetimeFormatLengthNarrow:
|
|
|
- return c.formatDateTimeComponentMonthNarrow(month), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported month length: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonth1Plus renders a numeric month component with 1 or
|
|
|
-// 2 digits depending on value.
|
|
|
-func (c Calendar) formatDateTimeComponentMonth1Plus(month time.Month) string {
|
|
|
- return fmt.Sprintf("%d", month)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonth2Plus renders a numeric month component always
|
|
|
-// with 2 digits.
|
|
|
-func (c Calendar) formatDateTimeComponentMonth2Plus(month time.Month) string {
|
|
|
- if month < 10 {
|
|
|
- return fmt.Sprintf("0%d", month)
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", month)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonthAbbreviated renders an abbreviated text month
|
|
|
-// component.
|
|
|
-func (c Calendar) formatDateTimeComponentMonthAbbreviated(month time.Month) string {
|
|
|
- return c.FormatNames.Months.Abbreviated[month]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonthWide renders a full text month component.
|
|
|
-func (c Calendar) formatDateTimeComponentMonthWide(month time.Month) string {
|
|
|
- return c.FormatNames.Months.Wide[month]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMonthNarrow renders a super-short month compontent -
|
|
|
-// not guaranteed to be unique for different months.
|
|
|
-func (c Calendar) formatDateTimeComponentMonthNarrow(month time.Month) string {
|
|
|
- return c.FormatNames.Months.Narrow[month]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDayOfWeek renders a day-of-week component.
|
|
|
-func (c Calendar) formatDateTimeComponentDayOfWeek(datetime time.Time, length int) (string, error) {
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.formatDateTimeComponentDayOfWeekWide(datetime.Weekday()), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- return c.formatDateTimeComponentDayOfWeekShort(datetime.Weekday()), nil
|
|
|
- case datetimeFormatLengthAbbreviated:
|
|
|
- return c.formatDateTimeComponentDayOfWeekAbbreviated(datetime.Weekday()), nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.formatDateTimeComponentDayOfWeekWide(datetime.Weekday()), nil
|
|
|
- case datetimeFormatLengthNarrow:
|
|
|
- return c.formatDateTimeComponentDayOfWeekNarrow(datetime.Weekday()), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported year day-of-week: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDayOfWeekAbbreviated renders an abbreviated text
|
|
|
-// day-of-week component.
|
|
|
-func (c Calendar) formatDateTimeComponentDayOfWeekAbbreviated(weekday time.Weekday) string {
|
|
|
- return c.FormatNames.Days.Abbreviated[weekday]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDayOfWeekAbbreviated renders a
|
|
|
-// shorter-then-abbreviated but still unique text day-of-week component.
|
|
|
-func (c Calendar) formatDateTimeComponentDayOfWeekShort(weekday time.Weekday) string {
|
|
|
- return c.FormatNames.Days.Short[weekday]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDayOfWeekWide renders a full text day-of-week
|
|
|
-// component.
|
|
|
-func (c Calendar) formatDateTimeComponentDayOfWeekWide(weekday time.Weekday) string {
|
|
|
- return c.FormatNames.Days.Wide[weekday]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDayOfWeekNarrow renders a super-short day-of-week
|
|
|
-// compontent - not guaranteed to be unique for different days.
|
|
|
-func (c Calendar) formatDateTimeComponentDayOfWeekNarrow(weekday time.Weekday) string {
|
|
|
- return c.FormatNames.Days.Narrow[weekday]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentDay renders a day-of-year component.
|
|
|
-func (c Calendar) formatDateTimeComponentDay(datetime time.Time, length int) (string, error) {
|
|
|
- day := datetime.Day()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return fmt.Sprintf("%d", day), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- if day < 10 {
|
|
|
- return fmt.Sprintf("0%d", day), nil
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", day), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported day-of-year: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentHour12 renders an hour-component using a 12-hour
|
|
|
-// clock.
|
|
|
-func (c Calendar) formatDateTimeComponentHour12(datetime time.Time, length int) (string, error) {
|
|
|
- hour := datetime.Hour()
|
|
|
- if hour > 12 {
|
|
|
- hour = hour - 12
|
|
|
- }
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return fmt.Sprintf("%d", hour), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- if hour < 10 {
|
|
|
- return fmt.Sprintf("0%d", hour), nil
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", hour), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported hour-12: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentHour24 renders an hour-component using a 24-hour
|
|
|
-// clock.
|
|
|
-func (c Calendar) formatDateTimeComponentHour24(datetime time.Time, length int) (string, error) {
|
|
|
- hour := datetime.Hour()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return fmt.Sprintf("%d", hour), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- if hour < 10 {
|
|
|
- return fmt.Sprintf("0%d", hour), nil
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", hour), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported hour-24: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentMinute renders a minute component.
|
|
|
-func (c Calendar) formatDateTimeComponentMinute(datetime time.Time, length int) (string, error) {
|
|
|
- minute := datetime.Minute()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return fmt.Sprintf("%d", minute), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- if minute < 10 {
|
|
|
- return fmt.Sprintf("0%d", minute), nil
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", minute), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported minute: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentSecond renders a second component
|
|
|
-func (c Calendar) formatDateTimeComponentSecond(datetime time.Time, length int) (string, error) {
|
|
|
- second := datetime.Second()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return fmt.Sprintf("%d", second), nil
|
|
|
- case datetimeFormatLength2Plus:
|
|
|
- if second < 10 {
|
|
|
- return fmt.Sprintf("0%d", second), nil
|
|
|
- }
|
|
|
- return fmt.Sprintf("%d", second), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported second: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentPeriod renders a period component (AM/PM).
|
|
|
-func (c Calendar) formatDateTimeComponentPeriod(datetime time.Time, length int) (string, error) {
|
|
|
- hour := datetime.Hour()
|
|
|
-
|
|
|
- switch length {
|
|
|
- case datetimeFormatLength1Plus:
|
|
|
- return c.formatDateTimeComponentPeriodWide(hour), nil
|
|
|
- case datetimeFormatLengthAbbreviated:
|
|
|
- return c.formatDateTimeComponentPeriodAbbreviated(hour), nil
|
|
|
- case datetimeFormatLengthWide:
|
|
|
- return c.formatDateTimeComponentPeriodWide(hour), nil
|
|
|
- case datetimeFormatLengthNarrow:
|
|
|
- return c.formatDateTimeComponentPeriodNarrow(hour), nil
|
|
|
- }
|
|
|
-
|
|
|
- return "", fmt.Errorf("unsupported day-period: %d", length)
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentPeriodAbbreviated renders an abbreviated period
|
|
|
-// component.
|
|
|
-func (c Calendar) formatDateTimeComponentPeriodAbbreviated(hour int) string {
|
|
|
- if hour < 12 {
|
|
|
- return c.FormatNames.Periods.Abbreviated[am]
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatNames.Periods.Abbreviated[pm]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentPeriodWide renders a full period component.
|
|
|
-func (c Calendar) formatDateTimeComponentPeriodWide(hour int) string {
|
|
|
- if hour < 12 {
|
|
|
- return c.FormatNames.Periods.Wide[am]
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatNames.Periods.Wide[pm]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentPeriodNarrow renders a super-short period component.
|
|
|
-func (c Calendar) formatDateTimeComponentPeriodNarrow(hour int) string {
|
|
|
- if hour < 12 {
|
|
|
- return c.FormatNames.Periods.Narrow[am]
|
|
|
- }
|
|
|
-
|
|
|
- return c.FormatNames.Periods.Narrow[pm]
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentQuarter renders a calendar quarter component - this
|
|
|
-// is calendar quarters and not fiscal quarters.
|
|
|
-// - Q1: Jan-Mar
|
|
|
-// - Q2: Apr-Jun
|
|
|
-// - Q3: Jul-Sep
|
|
|
-// - Q4: Oct-Dec
|
|
|
-// TODO: not yet implemented
|
|
|
-func (c Calendar) formatDateTimeComponentQuarter(datetime time.Time, length int) (string, error) {
|
|
|
- return "", nil
|
|
|
-}
|
|
|
-
|
|
|
-// formatDateTimeComponentTimeZone renders a time zone component.
|
|
|
-// TODO: this has not yet been implemented
|
|
|
-func (c Calendar) formatDateTimeComponentTimeZone(datetime time.Time, length int) (string, error) {
|
|
|
- return "", nil
|
|
|
-}
|
|
|
-
|
|
|
-// parseDateTimeFormat takes a format pattern string and returns a sequence of
|
|
|
-// components.
|
|
|
-func (c Calendar) parseDateTimeFormat(pattern string) ([]*datetimePatternComponent, error) {
|
|
|
- // every thing between single quotes should become a literal
|
|
|
- // all non a-z, A-Z characters become a literal
|
|
|
- // everything else, repeat character sequences become a component
|
|
|
- format := []*datetimePatternComponent{}
|
|
|
- for i := 0; i < len(pattern); {
|
|
|
- char := pattern[i : i+1]
|
|
|
-
|
|
|
- skip := false
|
|
|
- // for units we don't support yet, just skip over them
|
|
|
- for _, r := range datetimeFormatUnitCutset {
|
|
|
- if char == string(r) {
|
|
|
- skip = true
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if skip {
|
|
|
- i++
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- if char == string(datetimeFormatLiteral) {
|
|
|
- // find the next single quote
|
|
|
- // create a literal out of everything between the quotes
|
|
|
- // and set i to the position after the second quote
|
|
|
-
|
|
|
- if i == len(pattern)-1 {
|
|
|
- return []*datetimePatternComponent{}, errors.New("malformed datetime format")
|
|
|
- }
|
|
|
-
|
|
|
- nextQuote := strings.Index(pattern[i+1:], string(datetimeFormatLiteral))
|
|
|
- if nextQuote == -1 {
|
|
|
- return []*datetimePatternComponent{}, errors.New("malformed datetime format")
|
|
|
- }
|
|
|
-
|
|
|
- component := &datetimePatternComponent{
|
|
|
- pattern: pattern[i+1 : nextQuote+i+1],
|
|
|
- componentType: datetimePatternComponentLiteral,
|
|
|
- }
|
|
|
-
|
|
|
- format = append(format, component)
|
|
|
- i = nextQuote + i + 2
|
|
|
- continue
|
|
|
-
|
|
|
- }
|
|
|
- if (char >= "a" && char <= "z") || (char >= "A" && char <= "Z") {
|
|
|
- // this represents a format unit
|
|
|
- // find the entire sequence of the same character
|
|
|
- endChar := lastSequenceIndex(pattern[i:]) + i
|
|
|
-
|
|
|
- component := &datetimePatternComponent{
|
|
|
- pattern: pattern[i : endChar+1],
|
|
|
- componentType: datetimePatternComponentUnit,
|
|
|
- }
|
|
|
-
|
|
|
- format = append(format, component)
|
|
|
- i = endChar + 1
|
|
|
- continue
|
|
|
-
|
|
|
- }
|
|
|
- if char == string(datetimeFormatTimeSeparator) {
|
|
|
- component := &datetimePatternComponent{
|
|
|
- // pattern: c.TimeSeparator,
|
|
|
- pattern: string(datetimeFormatTimeSeparator),
|
|
|
- componentType: datetimePatternComponentLiteral,
|
|
|
- }
|
|
|
- format = append(format, component)
|
|
|
- i++
|
|
|
- continue
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- component := &datetimePatternComponent{
|
|
|
- pattern: char,
|
|
|
- componentType: datetimePatternComponentLiteral,
|
|
|
- }
|
|
|
-
|
|
|
- format = append(format, component)
|
|
|
- i++
|
|
|
- continue
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return format, nil
|
|
|
-}
|
|
|
-
|
|
|
-// getDateTimePattern combines a date pattern and a time pattern into a datetime
|
|
|
-// pattern. The datetimePattern argument includes a {0} placeholder for the time
|
|
|
-// pattern, and a {1} placeholder for the date component.
|
|
|
-func getDateTimePattern(datetimePattern, datePattern, timePattern string) string {
|
|
|
- return strings.Replace(strings.Replace(datetimePattern, "{1}", datePattern, 1), "{0}", timePattern, 1)
|
|
|
-}
|
|
|
-
|
|
|
-// lastSequenceIndex looks at the first character in a string and returns the
|
|
|
-// last digits of the first sequence of that character. For example:
|
|
|
-// - ABC: 0
|
|
|
-// - AAB: 1
|
|
|
-// - ABA: 0
|
|
|
-// - AAA: 2
|
|
|
-func lastSequenceIndex(str string) int {
|
|
|
- if len(str) == 0 {
|
|
|
- return -1
|
|
|
- }
|
|
|
-
|
|
|
- if len(str) == 1 {
|
|
|
- return 0
|
|
|
- }
|
|
|
-
|
|
|
- sequenceChar := str[0:1]
|
|
|
- lastPos := 0
|
|
|
- for i := 1; i < len(str); i++ {
|
|
|
- if str[i:i+1] != sequenceChar {
|
|
|
- break
|
|
|
- }
|
|
|
-
|
|
|
- lastPos = i
|
|
|
- }
|
|
|
-
|
|
|
- return lastPos
|
|
|
-}
|