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