github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/timeutil/since.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 package timeutil 7 8 import ( 9 "fmt" 10 "html/template" 11 "math" 12 "strings" 13 "time" 14 15 "github.com/gitbundle/modules/setting" 16 "github.com/gitbundle/modules/translation/i18n" 17 ) 18 19 // Seconds-based time units 20 const ( 21 Minute = 60 22 Hour = 60 * Minute 23 Day = 24 * Hour 24 Week = 7 * Day 25 Month = 30 * Day 26 Year = 12 * Month 27 ) 28 29 func round(s float64) int64 { 30 return int64(math.Round(s)) 31 } 32 33 func computeTimeDiffFloor(diff int64, lang string) (int64, string) { 34 diffStr := "" 35 switch { 36 case diff <= 0: 37 diff = 0 38 diffStr = i18n.Tr(lang, "tool.now") 39 case diff < 2: 40 diff = 0 41 diffStr = i18n.Tr(lang, "tool.1s") 42 case diff < 1*Minute: 43 diffStr = i18n.Tr(lang, "tool.seconds", diff) 44 diff = 0 45 46 case diff < 2*Minute: 47 diff -= 1 * Minute 48 diffStr = i18n.Tr(lang, "tool.1m") 49 case diff < 1*Hour: 50 diffStr = i18n.Tr(lang, "tool.minutes", diff/Minute) 51 diff -= diff / Minute * Minute 52 53 case diff < 2*Hour: 54 diff -= 1 * Hour 55 diffStr = i18n.Tr(lang, "tool.1h") 56 case diff < 1*Day: 57 diffStr = i18n.Tr(lang, "tool.hours", diff/Hour) 58 diff -= diff / Hour * Hour 59 60 case diff < 2*Day: 61 diff -= 1 * Day 62 diffStr = i18n.Tr(lang, "tool.1d") 63 case diff < 1*Week: 64 diffStr = i18n.Tr(lang, "tool.days", diff/Day) 65 diff -= diff / Day * Day 66 67 case diff < 2*Week: 68 diff -= 1 * Week 69 diffStr = i18n.Tr(lang, "tool.1w") 70 case diff < 1*Month: 71 diffStr = i18n.Tr(lang, "tool.weeks", diff/Week) 72 diff -= diff / Week * Week 73 74 case diff < 2*Month: 75 diff -= 1 * Month 76 diffStr = i18n.Tr(lang, "tool.1mon") 77 case diff < 1*Year: 78 diffStr = i18n.Tr(lang, "tool.months", diff/Month) 79 diff -= diff / Month * Month 80 81 case diff < 2*Year: 82 diff -= 1 * Year 83 diffStr = i18n.Tr(lang, "tool.1y") 84 default: 85 diffStr = i18n.Tr(lang, "tool.years", diff/Year) 86 diff -= (diff / Year) * Year 87 } 88 return diff, diffStr 89 } 90 91 func computeTimeDiff(diff int64, lang string) (int64, string) { 92 diffStr := "" 93 switch { 94 case diff <= 0: 95 diff = 0 96 diffStr = i18n.Tr(lang, "tool.now") 97 case diff < 2: 98 diff = 0 99 diffStr = i18n.Tr(lang, "tool.1s") 100 case diff < 1*Minute: 101 diffStr = i18n.Tr(lang, "tool.seconds", diff) 102 diff = 0 103 104 case diff < Minute+Minute/2: 105 diff -= 1 * Minute 106 diffStr = i18n.Tr(lang, "tool.1m") 107 case diff < 1*Hour: 108 minutes := round(float64(diff) / Minute) 109 if minutes > 1 { 110 diffStr = i18n.Tr(lang, "tool.minutes", minutes) 111 } else { 112 diffStr = i18n.Tr(lang, "tool.1m") 113 } 114 diff -= diff / Minute * Minute 115 116 case diff < Hour+Hour/2: 117 diff -= 1 * Hour 118 diffStr = i18n.Tr(lang, "tool.1h") 119 case diff < 1*Day: 120 hours := round(float64(diff) / Hour) 121 if hours > 1 { 122 diffStr = i18n.Tr(lang, "tool.hours", hours) 123 } else { 124 diffStr = i18n.Tr(lang, "tool.1h") 125 } 126 diff -= diff / Hour * Hour 127 128 case diff < Day+Day/2: 129 diff -= 1 * Day 130 diffStr = i18n.Tr(lang, "tool.1d") 131 case diff < 1*Week: 132 days := round(float64(diff) / Day) 133 if days > 1 { 134 diffStr = i18n.Tr(lang, "tool.days", days) 135 } else { 136 diffStr = i18n.Tr(lang, "tool.1d") 137 } 138 diff -= diff / Day * Day 139 140 case diff < Week+Week/2: 141 diff -= 1 * Week 142 diffStr = i18n.Tr(lang, "tool.1w") 143 case diff < 1*Month: 144 weeks := round(float64(diff) / Week) 145 if weeks > 1 { 146 diffStr = i18n.Tr(lang, "tool.weeks", weeks) 147 } else { 148 diffStr = i18n.Tr(lang, "tool.1w") 149 } 150 diff -= diff / Week * Week 151 152 case diff < 1*Month+Month/2: 153 diff -= 1 * Month 154 diffStr = i18n.Tr(lang, "tool.1mon") 155 case diff < 1*Year: 156 months := round(float64(diff) / Month) 157 if months > 1 { 158 diffStr = i18n.Tr(lang, "tool.months", months) 159 } else { 160 diffStr = i18n.Tr(lang, "tool.1mon") 161 } 162 diff -= diff / Month * Month 163 164 case diff < Year+Year/2: 165 diff -= 1 * Year 166 diffStr = i18n.Tr(lang, "tool.1y") 167 default: 168 years := round(float64(diff) / Year) 169 if years > 1 { 170 diffStr = i18n.Tr(lang, "tool.years", years) 171 } else { 172 diffStr = i18n.Tr(lang, "tool.1y") 173 } 174 diff -= (diff / Year) * Year 175 } 176 return diff, diffStr 177 } 178 179 // MinutesToFriendly returns a user friendly string with number of minutes 180 // converted to hours and minutes. 181 func MinutesToFriendly(minutes int, lang string) string { 182 duration := time.Duration(minutes) * time.Minute 183 return TimeSincePro(time.Now().Add(-duration), lang) 184 } 185 186 // TimeSincePro calculates the time interval and generate full user-friendly string. 187 func TimeSincePro(then time.Time, lang string) string { 188 return timeSincePro(then, time.Now(), lang) 189 } 190 191 func timeSincePro(then, now time.Time, lang string) string { 192 diff := now.Unix() - then.Unix() 193 194 if then.After(now) { 195 return i18n.Tr(lang, "tool.future") 196 } 197 if diff == 0 { 198 return i18n.Tr(lang, "tool.now") 199 } 200 201 var timeStr, diffStr string 202 for { 203 if diff == 0 { 204 break 205 } 206 207 diff, diffStr = computeTimeDiffFloor(diff, lang) 208 timeStr += ", " + diffStr 209 } 210 return strings.TrimPrefix(timeStr, ", ") 211 } 212 213 func timeSince(then, now time.Time, lang string) string { 214 return timeSinceUnix(then.Unix(), now.Unix(), lang) 215 } 216 217 func timeSinceUnix(then, now int64, lang string) string { 218 lbl := "tool.ago" 219 diff := now - then 220 if then > now { 221 lbl = "tool.from_now" 222 diff = then - now 223 } 224 if diff <= 0 { 225 return i18n.Tr(lang, "tool.now") 226 } 227 228 _, diffStr := computeTimeDiff(diff, lang) 229 return i18n.Tr(lang, lbl, diffStr) 230 } 231 232 // RawTimeSince retrieves i18n key of time since t 233 func RawTimeSince(t time.Time, lang string) string { 234 return timeSince(t, time.Now(), lang) 235 } 236 237 // TimeSince calculates the time interval and generate user-friendly string. 238 func TimeSince(then time.Time, lang string) template.HTML { 239 return htmlTimeSince(then, time.Now(), lang) 240 } 241 242 func htmlTimeSince(then, now time.Time, lang string) template.HTML { 243 return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`, 244 then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang)), 245 timeSince(then, now, lang))) 246 } 247 248 // TimeSinceUnix calculates the time interval and generate user-friendly string. 249 func TimeSinceUnix(then TimeStamp, lang string) template.HTML { 250 return htmlTimeSinceUnix(then, TimeStamp(time.Now().Unix()), lang) 251 } 252 253 func htmlTimeSinceUnix(then, now TimeStamp, lang string) template.HTML { 254 return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`, 255 then.FormatInLocation(GetTimeFormat(lang), setting.DefaultUILocation), 256 timeSinceUnix(int64(then), int64(now), lang))) 257 }