2019-08-15 22:46:21 +08:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package timeutil
import (
"fmt"
"html/template"
2021-01-28 20:29:22 +08:00
"math"
2019-08-15 22:46:21 +08:00
"strings"
"time"
"code.gitea.io/gitea/modules/setting"
2022-06-26 16:19:22 +02:00
"code.gitea.io/gitea/modules/translation"
2019-08-15 22:46:21 +08:00
)
// Seconds-based time units
const (
Minute = 60
Hour = 60 * Minute
Day = 24 * Hour
Week = 7 * Day
Month = 30 * Day
Year = 12 * Month
)
2021-01-28 20:29:22 +08:00
func round ( s float64 ) int64 {
return int64 ( math . Round ( s ) )
}
2022-06-26 16:19:22 +02:00
func computeTimeDiffFloor ( diff int64 , lang translation . Locale ) ( int64 , string ) {
diffStr := ""
2019-08-15 22:46:21 +08:00
switch {
case diff <= 0 :
diff = 0
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.now" )
2019-08-15 22:46:21 +08:00
case diff < 2 :
diff = 0
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1s" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Minute :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.seconds" , diff )
2019-08-15 22:46:21 +08:00
diff = 0
case diff < 2 * Minute :
diff -= 1 * Minute
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1m" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Hour :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.minutes" , diff / Minute )
2019-08-15 22:46:21 +08:00
diff -= diff / Minute * Minute
case diff < 2 * Hour :
diff -= 1 * Hour
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1h" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Day :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.hours" , diff / Hour )
2019-08-15 22:46:21 +08:00
diff -= diff / Hour * Hour
case diff < 2 * Day :
diff -= 1 * Day
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1d" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Week :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.days" , diff / Day )
2019-08-15 22:46:21 +08:00
diff -= diff / Day * Day
case diff < 2 * Week :
diff -= 1 * Week
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1w" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Month :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.weeks" , diff / Week )
2019-08-15 22:46:21 +08:00
diff -= diff / Week * Week
case diff < 2 * Month :
diff -= 1 * Month
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1mon" )
2019-08-15 22:46:21 +08:00
case diff < 1 * Year :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.months" , diff / Month )
2019-08-15 22:46:21 +08:00
diff -= diff / Month * Month
case diff < 2 * Year :
diff -= 1 * Year
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1y" )
2019-08-15 22:46:21 +08:00
default :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.years" , diff / Year )
2019-08-15 22:46:21 +08:00
diff -= ( diff / Year ) * Year
}
return diff , diffStr
}
2022-06-26 16:19:22 +02:00
func computeTimeDiff ( diff int64 , lang translation . Locale ) ( int64 , string ) {
diffStr := ""
2021-01-28 20:29:22 +08:00
switch {
case diff <= 0 :
diff = 0
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.now" )
2021-01-28 20:29:22 +08:00
case diff < 2 :
diff = 0
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1s" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Minute :
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.seconds" , diff )
2021-01-28 20:29:22 +08:00
diff = 0
case diff < Minute + Minute / 2 :
diff -= 1 * Minute
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1m" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Hour :
minutes := round ( float64 ( diff ) / Minute )
if minutes > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.minutes" , minutes )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1m" )
2021-01-28 20:29:22 +08:00
}
diff -= diff / Minute * Minute
case diff < Hour + Hour / 2 :
diff -= 1 * Hour
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1h" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Day :
hours := round ( float64 ( diff ) / Hour )
if hours > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.hours" , hours )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1h" )
2021-01-28 20:29:22 +08:00
}
diff -= diff / Hour * Hour
case diff < Day + Day / 2 :
diff -= 1 * Day
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1d" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Week :
days := round ( float64 ( diff ) / Day )
if days > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.days" , days )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1d" )
2021-01-28 20:29:22 +08:00
}
diff -= diff / Day * Day
case diff < Week + Week / 2 :
diff -= 1 * Week
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1w" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Month :
weeks := round ( float64 ( diff ) / Week )
if weeks > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.weeks" , weeks )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1w" )
2021-01-28 20:29:22 +08:00
}
diff -= diff / Week * Week
case diff < 1 * Month + Month / 2 :
diff -= 1 * Month
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1mon" )
2021-01-28 20:29:22 +08:00
case diff < 1 * Year :
months := round ( float64 ( diff ) / Month )
if months > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.months" , months )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1mon" )
2021-01-28 20:29:22 +08:00
}
diff -= diff / Month * Month
case diff < Year + Year / 2 :
diff -= 1 * Year
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1y" )
2021-01-28 20:29:22 +08:00
default :
years := round ( float64 ( diff ) / Year )
if years > 1 {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.years" , years )
2021-01-28 20:29:22 +08:00
} else {
2022-06-26 16:19:22 +02:00
diffStr = lang . Tr ( "tool.1y" )
2021-01-28 20:29:22 +08:00
}
diff -= ( diff / Year ) * Year
}
return diff , diffStr
}
2019-08-15 22:46:21 +08:00
// MinutesToFriendly returns a user friendly string with number of minutes
// converted to hours and minutes.
2022-06-26 16:19:22 +02:00
func MinutesToFriendly ( minutes int , lang translation . Locale ) string {
2019-08-15 22:46:21 +08:00
duration := time . Duration ( minutes ) * time . Minute
return TimeSincePro ( time . Now ( ) . Add ( - duration ) , lang )
}
// TimeSincePro calculates the time interval and generate full user-friendly string.
2022-06-26 16:19:22 +02:00
func TimeSincePro ( then time . Time , lang translation . Locale ) string {
2019-08-15 22:46:21 +08:00
return timeSincePro ( then , time . Now ( ) , lang )
}
2022-06-26 16:19:22 +02:00
func timeSincePro ( then , now time . Time , lang translation . Locale ) string {
2019-08-15 22:46:21 +08:00
diff := now . Unix ( ) - then . Unix ( )
if then . After ( now ) {
2022-06-26 16:19:22 +02:00
return lang . Tr ( "tool.future" )
2019-08-15 22:46:21 +08:00
}
if diff == 0 {
2022-06-26 16:19:22 +02:00
return lang . Tr ( "tool.now" )
2019-08-15 22:46:21 +08:00
}
var timeStr , diffStr string
for {
if diff == 0 {
break
}
2021-01-28 20:29:22 +08:00
diff , diffStr = computeTimeDiffFloor ( diff , lang )
2019-08-15 22:46:21 +08:00
timeStr += ", " + diffStr
}
return strings . TrimPrefix ( timeStr , ", " )
}
2022-06-26 16:19:22 +02:00
func timeSince ( then , now time . Time , lang translation . Locale ) string {
2019-08-15 22:46:21 +08:00
return timeSinceUnix ( then . Unix ( ) , now . Unix ( ) , lang )
}
2022-06-26 16:19:22 +02:00
func timeSinceUnix ( then , now int64 , lang translation . Locale ) string {
2019-08-15 22:46:21 +08:00
lbl := "tool.ago"
diff := now - then
if then > now {
lbl = "tool.from_now"
diff = then - now
}
if diff <= 0 {
2022-06-26 16:19:22 +02:00
return lang . Tr ( "tool.now" )
2019-08-15 22:46:21 +08:00
}
_ , diffStr := computeTimeDiff ( diff , lang )
2022-06-26 16:19:22 +02:00
return lang . Tr ( lbl , diffStr )
2019-08-15 22:46:21 +08:00
}
// TimeSince calculates the time interval and generate user-friendly string.
2022-06-26 16:19:22 +02:00
func TimeSince ( then time . Time , lang translation . Locale ) template . HTML {
2019-08-15 22:46:21 +08:00
return htmlTimeSince ( then , time . Now ( ) , lang )
}
2022-06-26 16:19:22 +02:00
func htmlTimeSince ( then , now time . Time , lang translation . Locale ) template . HTML {
2022-08-12 23:03:41 +02:00
return template . HTML ( fmt . Sprintf ( ` <span class="time-since tooltip" data-content="%s">%s</span> ` ,
2022-06-26 16:19:22 +02:00
then . In ( setting . DefaultUILocation ) . Format ( GetTimeFormat ( lang . Language ( ) ) ) ,
2019-08-15 22:46:21 +08:00
timeSince ( then , now , lang ) ) )
}
// TimeSinceUnix calculates the time interval and generate user-friendly string.
2022-06-26 16:19:22 +02:00
func TimeSinceUnix ( then TimeStamp , lang translation . Locale ) template . HTML {
2019-08-15 22:46:21 +08:00
return htmlTimeSinceUnix ( then , TimeStamp ( time . Now ( ) . Unix ( ) ) , lang )
}
2022-06-26 16:19:22 +02:00
func htmlTimeSinceUnix ( then , now TimeStamp , lang translation . Locale ) template . HTML {
2022-08-12 23:03:41 +02:00
return template . HTML ( fmt . Sprintf ( ` <span class="time-since tooltip" data-content="%s">%s</span> ` ,
2022-06-26 16:19:22 +02:00
then . FormatInLocation ( GetTimeFormat ( lang . Language ( ) ) , setting . DefaultUILocation ) ,
2019-08-15 22:46:21 +08:00
timeSinceUnix ( int64 ( then ) , int64 ( now ) , lang ) ) )
}