1package sprig
2
3import (
4	"strconv"
5	"time"
6)
7
8// Given a format and a date, format the date string.
9//
10// Date can be a `time.Time` or an `int, int32, int64`.
11// In the later case, it is treated as seconds since UNIX
12// epoch.
13func date(fmt string, date interface{}) string {
14	return dateInZone(fmt, date, "Local")
15}
16
17func htmlDate(date interface{}) string {
18	return dateInZone("2006-01-02", date, "Local")
19}
20
21func htmlDateInZone(date interface{}, zone string) string {
22	return dateInZone("2006-01-02", date, zone)
23}
24
25func dateInZone(fmt string, date interface{}, zone string) string {
26	var t time.Time
27	switch date := date.(type) {
28	default:
29		t = time.Now()
30	case time.Time:
31		t = date
32	case *time.Time:
33		t = *date
34	case int64:
35		t = time.Unix(date, 0)
36	case int:
37		t = time.Unix(int64(date), 0)
38	case int32:
39		t = time.Unix(int64(date), 0)
40	}
41
42	loc, err := time.LoadLocation(zone)
43	if err != nil {
44		loc, _ = time.LoadLocation("UTC")
45	}
46
47	return t.In(loc).Format(fmt)
48}
49
50func dateModify(fmt string, date time.Time) time.Time {
51	d, err := time.ParseDuration(fmt)
52	if err != nil {
53		return date
54	}
55	return date.Add(d)
56}
57
58func mustDateModify(fmt string, date time.Time) (time.Time, error) {
59	d, err := time.ParseDuration(fmt)
60	if err != nil {
61		return time.Time{}, err
62	}
63	return date.Add(d), nil
64}
65
66func dateAgo(date interface{}) string {
67	var t time.Time
68
69	switch date := date.(type) {
70	default:
71		t = time.Now()
72	case time.Time:
73		t = date
74	case int64:
75		t = time.Unix(date, 0)
76	case int:
77		t = time.Unix(int64(date), 0)
78	}
79	// Drop resolution to seconds
80	duration := time.Since(t).Round(time.Second)
81	return duration.String()
82}
83
84func duration(sec interface{}) string {
85	var n int64
86	switch value := sec.(type) {
87	default:
88		n = 0
89	case string:
90		n, _ = strconv.ParseInt(value, 10, 64)
91	case int64:
92		n = value
93	}
94	return (time.Duration(n) * time.Second).String()
95}
96
97func durationRound(duration interface{}) string {
98	var d time.Duration
99	switch duration := duration.(type) {
100	default:
101		d = 0
102	case string:
103		d, _ = time.ParseDuration(duration)
104	case int64:
105		d = time.Duration(duration)
106	case time.Time:
107		d = time.Since(duration)
108	}
109
110	u := uint64(d)
111	neg := d < 0
112	if neg {
113		u = -u
114	}
115
116	var (
117		year   = uint64(time.Hour) * 24 * 365
118		month  = uint64(time.Hour) * 24 * 30
119		day    = uint64(time.Hour) * 24
120		hour   = uint64(time.Hour)
121		minute = uint64(time.Minute)
122		second = uint64(time.Second)
123	)
124	switch {
125	case u > year:
126		return strconv.FormatUint(u/year, 10) + "y"
127	case u > month:
128		return strconv.FormatUint(u/month, 10) + "mo"
129	case u > day:
130		return strconv.FormatUint(u/day, 10) + "d"
131	case u > hour:
132		return strconv.FormatUint(u/hour, 10) + "h"
133	case u > minute:
134		return strconv.FormatUint(u/minute, 10) + "m"
135	case u > second:
136		return strconv.FormatUint(u/second, 10) + "s"
137	}
138	return "0s"
139}
140
141func toDate(fmt, str string) time.Time {
142	t, _ := time.ParseInLocation(fmt, str, time.Local)
143	return t
144}
145
146func mustToDate(fmt, str string) (time.Time, error) {
147	return time.ParseInLocation(fmt, str, time.Local)
148}
149
150func unixEpoch(date time.Time) string {
151	return strconv.FormatInt(date.Unix(), 10)
152}
153