A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package util
18
19import (
20 "bytes"
21 "fmt"
22 "math"
23 "strings"
24 "time"
25
26 "github.com/88250/go-humanize"
27)
28
29func IsTimeStr(str string) bool {
30 _, err := time.Parse("20060102150405", str)
31 return nil == err
32}
33
34func GetTodayStart() (ret time.Time) {
35 ret = time.Now()
36 ret = time.Date(ret.Year(), ret.Month(), ret.Day(), 0, 0, 0, 0, time.Local)
37 return
38}
39
40// Weekday returns the day of the week specified by date.
41// Sunday=0, Monday=1, ..., Saturday=6.
42func Weekday(date time.Time) int {
43 return int(date.Weekday())
44}
45
46// WeekdayCN returns the day of the week specified by date.
47// Sunday=日, Monday=一, ..., Saturday=六.
48func WeekdayCN(date time.Time) string {
49 week := Weekday(date)
50 weekdayCN := []string{"日", "一", "二", "三", "四", "五", "六"}
51 return weekdayCN[week]
52}
53
54// WeekdayCN2 returns the day of the week specified by date.
55// Sunday=天, Monday=一, ..., Saturday=六.
56func WeekdayCN2(date time.Time) string {
57 week := Weekday(date)
58 weekdayCN2 := []string{"天", "一", "二", "三", "四", "五", "六"}
59 return weekdayCN2[week]
60}
61
62// ISOWeek returns the ISO 8601 week number in which date occurs.
63// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to week 52 or 53 of year n-1,
64// and Dec 29 to Dec 31 might belong to week 1 of year n+1.
65func ISOWeek(date time.Time) int {
66 _, week := date.ISOWeek()
67 return week
68}
69
70// ISOYear returns the ISO 8601 year in which date occurs.
71func ISOYear(date time.Time) int {
72 year, _ := date.ISOWeek()
73 return year
74}
75
76// ISOMonth returns the month in which the Thursday of the ISO 8601 week of date occurs.
77func ISOMonth(date time.Time) int {
78 isoYear, isoWeek := date.ISOWeek()
79
80 // 1. 找到该 ISO 年份的 1 月 4 日(它必然属于第 1 周)
81 jan4 := time.Date(isoYear, time.January, 4, 0, 0, 0, 0, date.Location())
82
83 // 2. 找到第 1 周的周四
84 // (jan4.Weekday() + 6) % 7 将周一~周日映射为 0~6
85 daysToMonday := (int(jan4.Weekday()) + 6) % 7
86 mondayOfWeek1 := jan4.AddDate(0, 0, -daysToMonday)
87 thursdayOfWeek1 := mondayOfWeek1.AddDate(0, 0, 3)
88
89 // 3. 计算目标周的周四
90 // 目标周四 = 第一周周四 + (isoWeek-1) * 7天
91 targetThursday := thursdayOfWeek1.AddDate(0, 0, (isoWeek-1)*7)
92
93 // 4. 返回该周四所在的自然月份
94 return int(targetThursday.Month())
95}
96
97// ISOWeekDate returns the date of the specified day of the week in the ISO 8601 week of date.
98// day: Monday=1, ..., Sunday=7.
99func ISOWeekDate(day int, date time.Time) time.Time {
100 weekday := int(date.Weekday())
101 if weekday == 0 {
102 weekday = 7
103 }
104
105 daysToMonday := weekday - 1
106 monday := date.AddDate(0, 0, -daysToMonday)
107 return monday.AddDate(0, 0, day-1)
108}
109
110func Millisecond2Time(t int64) time.Time {
111 sec := t / 1000
112 msec := t % 1000
113 return time.Unix(sec, msec*int64(time.Millisecond))
114}
115
116func CurrentTimeMillis() int64 {
117 return time.Now().UnixMilli()
118}
119
120func CurrentTimeSecondsStr() string {
121 return time.Now().Format("20060102150405")
122}
123
124func HumanizeDiffTime(a, b time.Time, lang string) string {
125 labels := TimeLangs[lang]
126 year, month, day, hour, min, _ := humanizeDiffTime(a, b)
127 buf := bytes.Buffer{}
128 if 0 < year {
129 if 1 == year {
130 buf.WriteString(fmt.Sprintf(labels["1y"].(string), " "))
131 } else {
132 buf.WriteString(fmt.Sprintf(labels["xy"].(string), year, " "))
133 }
134 }
135 if 0 < month {
136 if 1 == month {
137 buf.WriteString(fmt.Sprintf(labels["1M"].(string), " "))
138 } else {
139 buf.WriteString(fmt.Sprintf(labels["xM"].(string), month, " "))
140 }
141 }
142 if 0 < day {
143 if 1 == day {
144 buf.WriteString(fmt.Sprintf(labels["1d"].(string), " "))
145 } else {
146 buf.WriteString(fmt.Sprintf(labels["xd"].(string), day, " "))
147 }
148 }
149 if 0 < hour {
150 if 1 == hour {
151 buf.WriteString(fmt.Sprintf(labels["1h"].(string), " "))
152 } else {
153 buf.WriteString(fmt.Sprintf(labels["xh"].(string), hour, " "))
154 }
155 }
156 if 0 < min {
157 if 1 == min {
158 buf.WriteString(fmt.Sprintf(labels["1m"].(string), " "))
159 } else {
160 buf.WriteString(fmt.Sprintf(labels["xm"].(string), min, " "))
161 }
162 }
163 return strings.TrimSpace(buf.String())
164}
165
166func humanizeDiffTime(a, b time.Time) (year, month, day, hour, min, sec int) {
167 // 感谢 https://stackoverflow.com/a/36531443/1043233
168
169 if a.Location() != b.Location() {
170 b = b.In(a.Location())
171 }
172 if a.After(b) {
173 a, b = b, a
174 }
175 y1, M1, d1 := a.Date()
176 y2, M2, d2 := b.Date()
177
178 h1, m1, s1 := a.Clock()
179 h2, m2, s2 := b.Clock()
180
181 year = y2 - y1
182 month = int(M2 - M1)
183 day = d2 - d1
184 hour = h2 - h1
185 min = m2 - m1
186 sec = s2 - s1
187
188 // Normalize negative values
189 if sec < 0 {
190 sec += 60
191 min--
192 }
193 if min < 0 {
194 min += 60
195 hour--
196 }
197 if hour < 0 {
198 hour += 24
199 day--
200 }
201 if day < 0 {
202 // days in month:
203 t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
204 day += 32 - t.Day()
205 month--
206 }
207 if month < 0 {
208 month += 12
209 year--
210 }
211 return
212}
213
214func HumanizeRelTime(a time.Time, b time.Time, lang string) string {
215 _, magnitudes := humanizeTimeMagnitudes(lang)
216 return strings.TrimSpace(humanize.CustomRelTime(a, b, "", "", magnitudes))
217}
218
219func HumanizeTime(then time.Time, lang string) string {
220 labels, magnitudes := humanizeTimeMagnitudes(lang)
221 return strings.TrimSpace(humanize.CustomRelTime(then, time.Now(), labels["albl"].(string), labels["blbl"].(string), magnitudes))
222}
223
224func humanizeTimeMagnitudes(lang string) (labels map[string]interface{}, magnitudes []humanize.RelTimeMagnitude) {
225 labels = TimeLangs[lang]
226 magnitudes = []humanize.RelTimeMagnitude{
227 {time.Second, labels["now"].(string), time.Second},
228 {2 * time.Second, labels["1s"].(string), 1},
229 {time.Minute, labels["xs"].(string), time.Second},
230 {2 * time.Minute, labels["1m"].(string), 1},
231 {time.Hour, labels["xm"].(string), time.Minute},
232 {2 * time.Hour, labels["1h"].(string), 1},
233 {humanize.Day, labels["xh"].(string), time.Hour},
234 {2 * humanize.Day, labels["1d"].(string), 1},
235 {humanize.Week, labels["xd"].(string), humanize.Day},
236 {2 * humanize.Week, labels["1w"].(string), 1},
237 {humanize.Month, labels["xw"].(string), humanize.Week},
238 {2 * humanize.Month, labels["1M"].(string), 1},
239 {humanize.Year, labels["xM"].(string), humanize.Month},
240 {23 * humanize.Month, labels["1y"].(string), 1},
241 {2 * humanize.Year, labels["2y"].(string), 1},
242 {humanize.LongTime, labels["xy"].(string), humanize.Year},
243 {math.MaxInt64, labels["max"].(string), 1},
244 }
245 return
246}