cerrado @ 72ead32e2d7967bddf39b79fa3bde769860e9ac7

  1// This code includes software originally developed by Dustin Sallings.
  2//
  3// Copyright (c) 2005-2008  Dustin Sallings <dustin@spy.net>
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to deal
  7// in the Software without restriction, including without limitation the rights
  8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9// copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21// SOFTWARE.
 22//
 23//<http://www.opensource.org/licenses/mit-license.php>
 24
 25package humanize
 26
 27import (
 28	"fmt"
 29	"math"
 30	"sort"
 31	"time"
 32)
 33
 34// Seconds-based time units
 35const (
 36	Day      = 24 * time.Hour
 37	Week     = 7 * Day
 38	Month    = 30 * Day
 39	Year     = 12 * Month
 40	LongTime = 37 * Year
 41)
 42
 43// Time formats a time into a relative string.
 44//
 45// Time(someT) -> "3 weeks ago"
 46func Time(then time.Time) string {
 47	return RelTime(then, time.Now(), "ago", "from now")
 48}
 49
 50// A RelTimeMagnitude struct contains a relative time point at which
 51// the relative format of time will switch to a new format string.  A
 52// slice of these in ascending order by their "D" field is passed to
 53// CustomRelTime to format durations.
 54//
 55// The Format field is a string that may contain a "%s" which will be
 56// replaced with the appropriate signed label (e.g. "ago" or "from
 57// now") and a "%d" that will be replaced by the quantity.
 58//
 59// The DivBy field is the amount of time the time difference must be
 60// divided by in order to display correctly.
 61//
 62// e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
 63// DivBy should be time.Minute so whatever the duration is will be
 64// expressed in minutes.
 65type RelTimeMagnitude struct {
 66	D      time.Duration
 67	Format string
 68	DivBy  time.Duration
 69}
 70
 71var defaultMagnitudes = []RelTimeMagnitude{
 72	{time.Second, "now", time.Second},
 73	{2 * time.Second, "1 second %s", 1},
 74	{time.Minute, "%d seconds %s", time.Second},
 75	{2 * time.Minute, "1 minute %s", 1},
 76	{time.Hour, "%d minutes %s", time.Minute},
 77	{2 * time.Hour, "1 hour %s", 1},
 78	{Day, "%d hours %s", time.Hour},
 79	{2 * Day, "1 day %s", 1},
 80	{Week, "%d days %s", Day},
 81	{2 * Week, "1 week %s", 1},
 82	{Month, "%d weeks %s", Week},
 83	{2 * Month, "1 month %s", 1},
 84	{Year, "%d months %s", Month},
 85	{18 * Month, "1 year %s", 1},
 86	{2 * Year, "2 years %s", 1},
 87	{LongTime, "%d years %s", Year},
 88	{math.MaxInt64, "a long while %s", 1},
 89}
 90
 91// RelTime formats a time into a relative string.
 92//
 93// It takes two times and two labels.  In addition to the generic time
 94// delta string (e.g. 5 minutes), the labels are used applied so that
 95// the label corresponding to the smaller time is applied.
 96//
 97// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
 98func RelTime(a, b time.Time, albl, blbl string) string {
 99	return CustomRelTime(a, b, albl, blbl, defaultMagnitudes)
100}
101
102// CustomRelTime formats a time into a relative string.
103//
104// It takes two times two labels and a table of relative time formats.
105// In addition to the generic time delta string (e.g. 5 minutes), the
106// labels are used applied so that the label corresponding to the
107// smaller time is applied.
108func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string {
109	lbl := albl
110	diff := b.Sub(a)
111
112	if a.After(b) {
113		lbl = blbl
114		diff = a.Sub(b)
115	}
116
117	n := sort.Search(len(magnitudes), func(i int) bool {
118		return magnitudes[i].D > diff
119	})
120
121	if n >= len(magnitudes) {
122		n = len(magnitudes) - 1
123	}
124	mag := magnitudes[n]
125	args := []interface{}{}
126	escaped := false
127	for _, ch := range mag.Format {
128		if escaped {
129			switch ch {
130			case 's':
131				args = append(args, lbl)
132			case 'd':
133				args = append(args, diff/mag.DivBy)
134			}
135			escaped = false
136		} else {
137			escaped = ch == '%'
138		}
139	}
140	return fmt.Sprintf(mag.Format, args...)
141}