A fork of Gitea (see branch `mj`) adding Majority Judgment Polls 𐄷 over Issues and Merge Requests. https://git.mieuxvoter.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
6.2 KiB

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