123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- 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
- }
|