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  }