mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-30 22:11:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			117 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			117 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package humanize
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"math"
 | |
| 	"sort"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| // Seconds-based time units
 | |
| const (
 | |
| 	Day      = 24 * time.Hour
 | |
| 	Week     = 7 * Day
 | |
| 	Month    = 30 * Day
 | |
| 	Year     = 12 * Month
 | |
| 	LongTime = 37 * Year
 | |
| )
 | |
| 
 | |
| // Time formats a time into a relative string.
 | |
| //
 | |
| // Time(someT) -> "3 weeks ago"
 | |
| func Time(then time.Time) string {
 | |
| 	return RelTime(then, time.Now(), "ago", "from now")
 | |
| }
 | |
| 
 | |
| // A RelTimeMagnitude struct contains a relative time point at which
 | |
| // the relative format of time will switch to a new format string.  A
 | |
| // slice of these in ascending order by their "D" field is passed to
 | |
| // CustomRelTime to format durations.
 | |
| //
 | |
| // The Format field is a string that may contain a "%s" which will be
 | |
| // replaced with the appropriate signed label (e.g. "ago" or "from
 | |
| // now") and a "%d" that will be replaced by the quantity.
 | |
| //
 | |
| // The DivBy field is the amount of time the time difference must be
 | |
| // divided by in order to display correctly.
 | |
| //
 | |
| // e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
 | |
| // DivBy should be time.Minute so whatever the duration is will be
 | |
| // expressed in minutes.
 | |
| type RelTimeMagnitude struct {
 | |
| 	D      time.Duration
 | |
| 	Format string
 | |
| 	DivBy  time.Duration
 | |
| }
 | |
| 
 | |
| var defaultMagnitudes = []RelTimeMagnitude{
 | |
| 	{time.Second, "now", time.Second},
 | |
| 	{2 * time.Second, "1 second %s", 1},
 | |
| 	{time.Minute, "%d seconds %s", time.Second},
 | |
| 	{2 * time.Minute, "1 minute %s", 1},
 | |
| 	{time.Hour, "%d minutes %s", time.Minute},
 | |
| 	{2 * time.Hour, "1 hour %s", 1},
 | |
| 	{Day, "%d hours %s", time.Hour},
 | |
| 	{2 * Day, "1 day %s", 1},
 | |
| 	{Week, "%d days %s", Day},
 | |
| 	{2 * Week, "1 week %s", 1},
 | |
| 	{Month, "%d weeks %s", Week},
 | |
| 	{2 * Month, "1 month %s", 1},
 | |
| 	{Year, "%d months %s", Month},
 | |
| 	{18 * Month, "1 year %s", 1},
 | |
| 	{2 * Year, "2 years %s", 1},
 | |
| 	{LongTime, "%d years %s", Year},
 | |
| 	{math.MaxInt64, "a long while %s", 1},
 | |
| }
 | |
| 
 | |
| // RelTime formats a time into a relative string.
 | |
| //
 | |
| // It takes two times and two labels.  In addition to the generic time
 | |
| // delta string (e.g. 5 minutes), the labels are used applied so that
 | |
| // the label corresponding to the smaller time is applied.
 | |
| //
 | |
| // RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
 | |
| func RelTime(a, b time.Time, albl, blbl string) string {
 | |
| 	return CustomRelTime(a, b, albl, blbl, defaultMagnitudes)
 | |
| }
 | |
| 
 | |
| // CustomRelTime formats a time into a relative string.
 | |
| //
 | |
| // It takes two times two labels and a table of relative time formats.
 | |
| // In addition to the generic time delta string (e.g. 5 minutes), the
 | |
| // labels are used applied so that the label corresponding to the
 | |
| // smaller time is applied.
 | |
| func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string {
 | |
| 	lbl := albl
 | |
| 	diff := b.Sub(a)
 | |
| 
 | |
| 	if a.After(b) {
 | |
| 		lbl = blbl
 | |
| 		diff = a.Sub(b)
 | |
| 	}
 | |
| 
 | |
| 	n := sort.Search(len(magnitudes), func(i int) bool {
 | |
| 		return magnitudes[i].D > diff
 | |
| 	})
 | |
| 
 | |
| 	if n >= len(magnitudes) {
 | |
| 		n = len(magnitudes) - 1
 | |
| 	}
 | |
| 	mag := magnitudes[n]
 | |
| 	args := []interface{}{}
 | |
| 	escaped := false
 | |
| 	for _, ch := range mag.Format {
 | |
| 		if escaped {
 | |
| 			switch ch {
 | |
| 			case 's':
 | |
| 				args = append(args, lbl)
 | |
| 			case 'd':
 | |
| 				args = append(args, diff/mag.DivBy)
 | |
| 			}
 | |
| 			escaped = false
 | |
| 		} else {
 | |
| 			escaped = ch == '%'
 | |
| 		}
 | |
| 	}
 | |
| 	return fmt.Sprintf(mag.Format, args...)
 | |
| }
 |