diff options
Diffstat (limited to 'common/htime/time.go')
-rw-r--r-- | common/htime/time.go | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/common/htime/time.go b/common/htime/time.go new file mode 100644 index 000000000..d30ecf7e1 --- /dev/null +++ b/common/htime/time.go @@ -0,0 +1,165 @@ +// Copyright 2021 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package htime + +import ( + "strings" + "time" + + "github.com/bep/clock" + "github.com/spf13/cast" + + "github.com/gohugoio/locales" +) + +var ( + longDayNames = []string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + } + + shortDayNames = []string{ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + } + + shortMonthNames = []string{ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + } + + longMonthNames = []string{ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + } + + Clock = clock.System() +) + +func NewTimeFormatter(ltr locales.Translator) TimeFormatter { + if ltr == nil { + panic("must provide a locales.Translator") + } + return TimeFormatter{ + ltr: ltr, + } +} + +// TimeFormatter is locale aware. +type TimeFormatter struct { + ltr locales.Translator +} + +func (f TimeFormatter) Format(t time.Time, layout string) string { + if layout == "" { + return "" + } + + if layout[0] == ':' { + // It may be one of Hugo's custom layouts. + switch strings.ToLower(layout[1:]) { + case "date_full": + return f.ltr.FmtDateFull(t) + case "date_long": + return f.ltr.FmtDateLong(t) + case "date_medium": + return f.ltr.FmtDateMedium(t) + case "date_short": + return f.ltr.FmtDateShort(t) + case "time_full": + return f.ltr.FmtTimeFull(t) + case "time_long": + return f.ltr.FmtTimeLong(t) + case "time_medium": + return f.ltr.FmtTimeMedium(t) + case "time_short": + return f.ltr.FmtTimeShort(t) + } + } + + s := t.Format(layout) + + monthIdx := t.Month() - 1 // Month() starts at 1. + dayIdx := t.Weekday() + + s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month())) + if !strings.Contains(s, f.ltr.MonthWide(t.Month())) { + s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthAbbreviated(t.Month())) + } + s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday())) + if !strings.Contains(s, f.ltr.WeekdayWide(t.Weekday())) { + s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdayAbbreviated(t.Weekday())) + } + + return s +} + +func ToTimeInDefaultLocationE(i any, location *time.Location) (tim time.Time, err error) { + switch vv := i.(type) { + case AsTimeProvider: + return vv.AsTime(location), nil + // issue #8895 + // datetimes parsed by `go-toml` have empty zone name + // convert back them into string and use `cast` + // TODO(bep) add tests, make sure we really need this. + case time.Time: + i = vv.Format(time.RFC3339) + } + return cast.ToTimeInDefaultLocationE(i, location) +} + +// Now returns time.Now() or time value based on the `clock` flag. +// Use this function to fake time inside hugo. +func Now() time.Time { + return Clock.Now() +} + +func Since(t time.Time) time.Duration { + return Clock.Since(t) +} + +// AsTimeProvider is implemented by go-toml's LocalDate and LocalDateTime. +type AsTimeProvider interface { + AsTime(zone *time.Location) time.Time +} |