github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/common/htime/time.go (about)

     1  // Copyright 2021 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package htime
    15  
    16  import (
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/bep/clock"
    21  	"github.com/spf13/cast"
    22  
    23  	"github.com/gohugoio/locales"
    24  )
    25  
    26  var (
    27  	longDayNames = []string{
    28  		"Sunday",
    29  		"Monday",
    30  		"Tuesday",
    31  		"Wednesday",
    32  		"Thursday",
    33  		"Friday",
    34  		"Saturday",
    35  	}
    36  
    37  	shortDayNames = []string{
    38  		"Sun",
    39  		"Mon",
    40  		"Tue",
    41  		"Wed",
    42  		"Thu",
    43  		"Fri",
    44  		"Sat",
    45  	}
    46  
    47  	shortMonthNames = []string{
    48  		"Jan",
    49  		"Feb",
    50  		"Mar",
    51  		"Apr",
    52  		"May",
    53  		"Jun",
    54  		"Jul",
    55  		"Aug",
    56  		"Sep",
    57  		"Oct",
    58  		"Nov",
    59  		"Dec",
    60  	}
    61  
    62  	longMonthNames = []string{
    63  		"January",
    64  		"February",
    65  		"March",
    66  		"April",
    67  		"May",
    68  		"June",
    69  		"July",
    70  		"August",
    71  		"September",
    72  		"October",
    73  		"November",
    74  		"December",
    75  	}
    76  
    77  	Clock = clock.System()
    78  )
    79  
    80  func NewTimeFormatter(ltr locales.Translator) TimeFormatter {
    81  	if ltr == nil {
    82  		panic("must provide a locales.Translator")
    83  	}
    84  	return TimeFormatter{
    85  		ltr: ltr,
    86  	}
    87  }
    88  
    89  // TimeFormatter is locale aware.
    90  type TimeFormatter struct {
    91  	ltr locales.Translator
    92  }
    93  
    94  func (f TimeFormatter) Format(t time.Time, layout string) string {
    95  	if layout == "" {
    96  		return ""
    97  	}
    98  
    99  	if layout[0] == ':' {
   100  		// It may be one of Hugo's custom layouts.
   101  		switch strings.ToLower(layout[1:]) {
   102  		case "date_full":
   103  			return f.ltr.FmtDateFull(t)
   104  		case "date_long":
   105  			return f.ltr.FmtDateLong(t)
   106  		case "date_medium":
   107  			return f.ltr.FmtDateMedium(t)
   108  		case "date_short":
   109  			return f.ltr.FmtDateShort(t)
   110  		case "time_full":
   111  			return f.ltr.FmtTimeFull(t)
   112  		case "time_long":
   113  			return f.ltr.FmtTimeLong(t)
   114  		case "time_medium":
   115  			return f.ltr.FmtTimeMedium(t)
   116  		case "time_short":
   117  			return f.ltr.FmtTimeShort(t)
   118  		}
   119  	}
   120  
   121  	s := t.Format(layout)
   122  
   123  	monthIdx := t.Month() - 1 // Month() starts at 1.
   124  	dayIdx := t.Weekday()
   125  
   126  	s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month()))
   127  	if !strings.Contains(s, f.ltr.MonthWide(t.Month())) {
   128  		s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthAbbreviated(t.Month()))
   129  	}
   130  	s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday()))
   131  	if !strings.Contains(s, f.ltr.WeekdayWide(t.Weekday())) {
   132  		s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdayAbbreviated(t.Weekday()))
   133  	}
   134  
   135  	return s
   136  }
   137  
   138  func ToTimeInDefaultLocationE(i any, location *time.Location) (tim time.Time, err error) {
   139  	switch vv := i.(type) {
   140  	case AsTimeProvider:
   141  		return vv.AsTime(location), nil
   142  	// issue #8895
   143  	// datetimes parsed by `go-toml` have empty zone name
   144  	// convert back them into string and use `cast`
   145  	// TODO(bep) add tests, make sure we really need this.
   146  	case time.Time:
   147  		i = vv.Format(time.RFC3339)
   148  	}
   149  	return cast.ToTimeInDefaultLocationE(i, location)
   150  }
   151  
   152  // Now returns time.Now() or time value based on the `clock` flag.
   153  // Use this function to fake time inside hugo.
   154  func Now() time.Time {
   155  	return Clock.Now()
   156  }
   157  
   158  func Since(t time.Time) time.Duration {
   159  	return Clock.Since(t)
   160  }
   161  
   162  // AsTimeProvider is implemented by go-toml's LocalDate and LocalDateTime.
   163  type AsTimeProvider interface {
   164  	AsTime(zone *time.Location) time.Time
   165  }