github.com/hairyhenderson/templater@v3.5.0+incompatible/funcs/time.go (about) 1 package funcs 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "sync" 8 gotime "time" 9 10 "github.com/hairyhenderson/gomplate/conv" 11 "github.com/hairyhenderson/gomplate/time" 12 ) 13 14 var ( 15 timeNS *TimeFuncs 16 timeNSInit sync.Once 17 ) 18 19 // TimeNS - 20 func TimeNS() *TimeFuncs { 21 timeNSInit.Do(func() { 22 timeNS = &TimeFuncs{ 23 ANSIC: gotime.ANSIC, 24 UnixDate: gotime.UnixDate, 25 RubyDate: gotime.RubyDate, 26 RFC822: gotime.RFC822, 27 RFC822Z: gotime.RFC822Z, 28 RFC850: gotime.RFC850, 29 RFC1123: gotime.RFC1123, 30 RFC1123Z: gotime.RFC1123Z, 31 RFC3339: gotime.RFC3339, 32 RFC3339Nano: gotime.RFC3339Nano, 33 Kitchen: gotime.Kitchen, 34 Stamp: gotime.Stamp, 35 StampMilli: gotime.StampMilli, 36 StampMicro: gotime.StampMicro, 37 StampNano: gotime.StampNano, 38 } 39 }) 40 return timeNS 41 } 42 43 // AddTimeFuncs - 44 func AddTimeFuncs(f map[string]interface{}) { 45 f["time"] = TimeNS 46 } 47 48 // TimeFuncs - 49 type TimeFuncs struct { 50 ANSIC string 51 UnixDate string 52 RubyDate string 53 RFC822 string 54 RFC822Z string 55 RFC850 string 56 RFC1123 string 57 RFC1123Z string 58 RFC3339 string 59 RFC3339Nano string 60 Kitchen string 61 Stamp string 62 StampMilli string 63 StampMicro string 64 StampNano string 65 } 66 67 // ZoneName - return the local system's time zone's name 68 func (f *TimeFuncs) ZoneName() string { 69 return time.ZoneName() 70 } 71 72 // ZoneOffset - return the local system's time zone's name 73 func (f *TimeFuncs) ZoneOffset() int { 74 return time.ZoneOffset() 75 } 76 77 // Parse - 78 func (f *TimeFuncs) Parse(layout string, value interface{}) (gotime.Time, error) { 79 return gotime.Parse(layout, conv.ToString(value)) 80 } 81 82 // ParseLocal - 83 func (f *TimeFuncs) ParseLocal(layout string, value interface{}) (gotime.Time, error) { 84 return gotime.ParseInLocation(layout, conv.ToString(value), gotime.Local) 85 } 86 87 // ParseInLocation - 88 func (f *TimeFuncs) ParseInLocation(layout, location string, value interface{}) (gotime.Time, error) { 89 loc, err := gotime.LoadLocation(location) 90 if err != nil { 91 return gotime.Time{}, err 92 } 93 return gotime.ParseInLocation(layout, conv.ToString(value), loc) 94 } 95 96 // Now - 97 func (f *TimeFuncs) Now() gotime.Time { 98 return gotime.Now() 99 } 100 101 // Unix - convert UNIX time (in seconds since the UNIX epoch) into a time.Time for further processing 102 // Takes a string or number (int or float) 103 func (f *TimeFuncs) Unix(in interface{}) (gotime.Time, error) { 104 sec, nsec, err := parseNum(in) 105 if err != nil { 106 return gotime.Time{}, err 107 } 108 return gotime.Unix(sec, nsec), nil 109 } 110 111 // Nanosecond - 112 func (f *TimeFuncs) Nanosecond(n interface{}) gotime.Duration { 113 return gotime.Nanosecond * gotime.Duration(conv.ToInt64(n)) 114 } 115 116 // Microsecond - 117 func (f *TimeFuncs) Microsecond(n interface{}) gotime.Duration { 118 return gotime.Microsecond * gotime.Duration(conv.ToInt64(n)) 119 } 120 121 // Millisecond - 122 func (f *TimeFuncs) Millisecond(n interface{}) gotime.Duration { 123 return gotime.Millisecond * gotime.Duration(conv.ToInt64(n)) 124 } 125 126 // Second - 127 func (f *TimeFuncs) Second(n interface{}) gotime.Duration { 128 return gotime.Second * gotime.Duration(conv.ToInt64(n)) 129 } 130 131 // Minute - 132 func (f *TimeFuncs) Minute(n interface{}) gotime.Duration { 133 return gotime.Minute * gotime.Duration(conv.ToInt64(n)) 134 } 135 136 // Hour - 137 func (f *TimeFuncs) Hour(n interface{}) gotime.Duration { 138 return gotime.Hour * gotime.Duration(conv.ToInt64(n)) 139 } 140 141 // ParseDuration - 142 func (f *TimeFuncs) ParseDuration(n interface{}) (gotime.Duration, error) { 143 return gotime.ParseDuration(conv.ToString(n)) 144 } 145 146 // Since - 147 func (f *TimeFuncs) Since(n gotime.Time) gotime.Duration { 148 return gotime.Since(n) 149 } 150 151 // Until - 152 func (f *TimeFuncs) Until(n gotime.Time) gotime.Duration { 153 return gotime.Until(n) 154 } 155 156 // convert a number input to a pair of int64s, representing the integer portion and the decimal remainder 157 // this can handle a string as well as any integer or float type 158 // precision is at the "nano" level (i.e. 1e+9) 159 func parseNum(in interface{}) (integral int64, fractional int64, err error) { 160 if s, ok := in.(string); ok { 161 ss := strings.Split(s, ".") 162 if len(ss) > 2 { 163 return 0, 0, fmt.Errorf("can not parse '%s' as a number - too many decimal points", s) 164 } 165 if len(ss) == 1 { 166 integral, err := strconv.ParseInt(s, 0, 64) 167 return integral, 0, err 168 } 169 integral, err := strconv.ParseInt(ss[0], 0, 64) 170 if err != nil { 171 return integral, 0, err 172 } 173 fractional, err = strconv.ParseInt(padRight(ss[1], "0", 9), 0, 64) 174 return integral, fractional, err 175 } 176 if s, ok := in.(fmt.Stringer); ok { 177 return parseNum(s.String()) 178 } 179 if i, ok := in.(int); ok { 180 return int64(i), 0, nil 181 } 182 if u, ok := in.(uint64); ok { 183 return int64(u), 0, nil 184 } 185 if f, ok := in.(float64); ok { 186 return 0, 0, fmt.Errorf("can not parse floating point number (%f) - use a string instead", f) 187 } 188 if in == nil { 189 return 0, 0, nil 190 } 191 return 0, 0, nil 192 } 193 194 // pads a number with zeroes 195 func padRight(in, pad string, length int) string { 196 for { 197 in += pad 198 if len(in) > length { 199 return in[0:length] 200 } 201 } 202 }