diff options
Diffstat (limited to 'pkg/humanize')
| -rw-r--r-- | pkg/humanize/times.go | 141 | 
1 files changed, 141 insertions, 0 deletions
| diff --git a/pkg/humanize/times.go b/pkg/humanize/times.go new file mode 100644 index 0000000..1bd5166 --- /dev/null +++ b/pkg/humanize/times.go @@ -0,0 +1,141 @@ +// This code includes software originally developed by Dustin Sallings. +// +// Copyright (c) 2005-2008  Dustin Sallings <dustin@spy.net> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//<http://www.opensource.org/licenses/mit-license.php> + +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...) +} | 
