mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-07-06 20:04:04 +00:00
Update vendor yaegashi/msgraph.go to v0.1.2 (2)
This commit is contained in:
27
vendor/github.com/rickb777/date/LICENSE
generated
vendored
Normal file
27
vendor/github.com/rickb777/date/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2015 The Go Authors & Rick Beton. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
44
vendor/github.com/rickb777/date/period/doc.go
generated
vendored
Normal file
44
vendor/github.com/rickb777/date/period/doc.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2016 Rick Beton. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package period provides functionality for periods of time using ISO-8601 conventions.
|
||||
// This deals with years, months, weeks/days, hours, minutes and seconds.
|
||||
//
|
||||
// Because of the vagaries of calendar systems, the meaning of year lengths, month lengths
|
||||
// and even day lengths depends on context. So a period is not necessarily a fixed duration
|
||||
// of time in terms of seconds.
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/ISO_8601#Durations
|
||||
//
|
||||
// Example representations:
|
||||
//
|
||||
// * "P2Y" is two years;
|
||||
//
|
||||
// * "P6M" is six months;
|
||||
//
|
||||
// * "P4D" is four days;
|
||||
//
|
||||
// * "P1W" is one week (seven days);
|
||||
//
|
||||
// * "PT3H" is three hours.
|
||||
//
|
||||
// * "PT20M" is twenty minutes.
|
||||
//
|
||||
// * "PT30S" is thirty seconds.
|
||||
//
|
||||
// These can be combined, for example:
|
||||
//
|
||||
// * "P3Y6M4W1D" is three years, 6 months, 4 weeks and one day.
|
||||
//
|
||||
// * "P2DT12H" is 2 days and 12 hours.
|
||||
//
|
||||
// Also, decimal fractions are supported to one decimal place. To comply with
|
||||
// the standard, only the last non-zero component is allowed to have a fraction.
|
||||
// For example
|
||||
//
|
||||
// * "P2.5Y" is 2.5 years.
|
||||
//
|
||||
// * "PT12M7.5S" is 12 minutes and 7.5 seconds.
|
||||
//
|
||||
package period
|
128
vendor/github.com/rickb777/date/period/format.go
generated
vendored
Normal file
128
vendor/github.com/rickb777/date/period/format.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2015 Rick Beton. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package period
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rickb777/plural"
|
||||
)
|
||||
|
||||
// Format converts the period to human-readable form using the default localisation.
|
||||
func (period Period) Format() string {
|
||||
return period.FormatWithPeriodNames(PeriodYearNames, PeriodMonthNames, PeriodWeekNames, PeriodDayNames, PeriodHourNames, PeriodMinuteNames, PeriodSecondNames)
|
||||
}
|
||||
|
||||
// FormatWithPeriodNames converts the period to human-readable form in a localisable way.
|
||||
func (period Period) FormatWithPeriodNames(yearNames, monthNames, weekNames, dayNames, hourNames, minNames, secNames plural.Plurals) string {
|
||||
period = period.Abs()
|
||||
|
||||
parts := make([]string, 0)
|
||||
parts = appendNonBlank(parts, yearNames.FormatFloat(absFloat10(period.years)))
|
||||
parts = appendNonBlank(parts, monthNames.FormatFloat(absFloat10(period.months)))
|
||||
|
||||
if period.days > 0 || (period.IsZero()) {
|
||||
if len(weekNames) > 0 {
|
||||
weeks := period.days / 70
|
||||
mdays := period.days % 70
|
||||
//fmt.Printf("%v %#v - %d %d\n", period, period, weeks, mdays)
|
||||
if weeks > 0 {
|
||||
parts = appendNonBlank(parts, weekNames.FormatInt(int(weeks)))
|
||||
}
|
||||
if mdays > 0 || weeks == 0 {
|
||||
parts = appendNonBlank(parts, dayNames.FormatFloat(absFloat10(mdays)))
|
||||
}
|
||||
} else {
|
||||
parts = appendNonBlank(parts, dayNames.FormatFloat(absFloat10(period.days)))
|
||||
}
|
||||
}
|
||||
parts = appendNonBlank(parts, hourNames.FormatFloat(absFloat10(period.hours)))
|
||||
parts = appendNonBlank(parts, minNames.FormatFloat(absFloat10(period.minutes)))
|
||||
parts = appendNonBlank(parts, secNames.FormatFloat(absFloat10(period.seconds)))
|
||||
|
||||
return strings.Join(parts, ", ")
|
||||
}
|
||||
|
||||
func appendNonBlank(parts []string, s string) []string {
|
||||
if s == "" {
|
||||
return parts
|
||||
}
|
||||
return append(parts, s)
|
||||
}
|
||||
|
||||
// PeriodDayNames provides the English default format names for the days part of the period.
|
||||
// This is a sequence of plurals where the first match is used, otherwise the last one is used.
|
||||
// The last one must include a "%v" placeholder for the number.
|
||||
var PeriodDayNames = plural.FromZero("%v days", "%v day", "%v days")
|
||||
|
||||
// PeriodWeekNames is as for PeriodDayNames but for weeks.
|
||||
var PeriodWeekNames = plural.FromZero("", "%v week", "%v weeks")
|
||||
|
||||
// PeriodMonthNames is as for PeriodDayNames but for months.
|
||||
var PeriodMonthNames = plural.FromZero("", "%v month", "%v months")
|
||||
|
||||
// PeriodYearNames is as for PeriodDayNames but for years.
|
||||
var PeriodYearNames = plural.FromZero("", "%v year", "%v years")
|
||||
|
||||
// PeriodHourNames is as for PeriodDayNames but for hours.
|
||||
var PeriodHourNames = plural.FromZero("", "%v hour", "%v hours")
|
||||
|
||||
// PeriodMinuteNames is as for PeriodDayNames but for minutes.
|
||||
var PeriodMinuteNames = plural.FromZero("", "%v minute", "%v minutes")
|
||||
|
||||
// PeriodSecondNames is as for PeriodDayNames but for seconds.
|
||||
var PeriodSecondNames = plural.FromZero("", "%v second", "%v seconds")
|
||||
|
||||
// String converts the period to ISO-8601 form.
|
||||
func (period Period) String() string {
|
||||
if period.IsZero() {
|
||||
return "P0D"
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
if period.Sign() < 0 {
|
||||
buf.WriteByte('-')
|
||||
}
|
||||
|
||||
buf.WriteByte('P')
|
||||
|
||||
if period.years != 0 {
|
||||
fmt.Fprintf(buf, "%gY", absFloat10(period.years))
|
||||
}
|
||||
if period.months != 0 {
|
||||
fmt.Fprintf(buf, "%gM", absFloat10(period.months))
|
||||
}
|
||||
if period.days != 0 {
|
||||
if period.days%70 == 0 {
|
||||
fmt.Fprintf(buf, "%gW", absFloat10(period.days/7))
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%gD", absFloat10(period.days))
|
||||
}
|
||||
}
|
||||
if period.hours != 0 || period.minutes != 0 || period.seconds != 0 {
|
||||
buf.WriteByte('T')
|
||||
}
|
||||
if period.hours != 0 {
|
||||
fmt.Fprintf(buf, "%gH", absFloat10(period.hours))
|
||||
}
|
||||
if period.minutes != 0 {
|
||||
fmt.Fprintf(buf, "%gM", absFloat10(period.minutes))
|
||||
}
|
||||
if period.seconds != 0 {
|
||||
fmt.Fprintf(buf, "%gS", absFloat10(period.seconds))
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func absFloat10(v int16) float32 {
|
||||
f := float32(v) / 10
|
||||
if v < 0 {
|
||||
return -f
|
||||
}
|
||||
return f
|
||||
}
|
32
vendor/github.com/rickb777/date/period/marshal.go
generated
vendored
Normal file
32
vendor/github.com/rickb777/date/period/marshal.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package period
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||
// This also provides support for gob encoding.
|
||||
func (period Period) MarshalBinary() ([]byte, error) {
|
||||
// binary method would take more space in many cases, so we simply use text
|
||||
return period.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
||||
// This also provides support for gob encoding.
|
||||
func (period *Period) UnmarshalBinary(data []byte) error {
|
||||
return period.UnmarshalText(data)
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface for Periods.
|
||||
func (period Period) MarshalText() ([]byte, error) {
|
||||
return []byte(period.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface for Periods.
|
||||
func (period *Period) UnmarshalText(data []byte) (err error) {
|
||||
u, err := Parse(string(data))
|
||||
if err == nil {
|
||||
*period = u
|
||||
}
|
||||
return err
|
||||
}
|
152
vendor/github.com/rickb777/date/period/parse.go
generated
vendored
Normal file
152
vendor/github.com/rickb777/date/period/parse.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2015 Rick Beton. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package period
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MustParse is as per Parse except that it panics if the string cannot be parsed.
|
||||
// This is intended for setup code; don't use it for user inputs.
|
||||
func MustParse(value string) Period {
|
||||
d, err := Parse(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Parse parses strings that specify periods using ISO-8601 rules.
|
||||
//
|
||||
// In addition, a plus or minus sign can precede the period, e.g. "-P10D"
|
||||
//
|
||||
// The value is normalised, e.g. multiple of 12 months become years so "P24M"
|
||||
// is the same as "P2Y". However, this is done without loss of precision, so
|
||||
// for example whole numbers of days do not contribute to the months tally
|
||||
// because the number of days per month is variable.
|
||||
//
|
||||
// The zero value can be represented in several ways: all of the following
|
||||
// are equivalent: "P0Y", "P0M", "P0W", "P0D", "PT0H", PT0M", PT0S", and "P0".
|
||||
// The canonical zero is "P0D".
|
||||
func Parse(period string) (Period, error) {
|
||||
if period == "" {
|
||||
return Period{}, fmt.Errorf("cannot parse a blank string as a period")
|
||||
}
|
||||
|
||||
if period == "P0" {
|
||||
return Period{}, nil
|
||||
}
|
||||
|
||||
result := period64{}
|
||||
pcopy := period
|
||||
if pcopy[0] == '-' {
|
||||
result.neg = true
|
||||
pcopy = pcopy[1:]
|
||||
} else if pcopy[0] == '+' {
|
||||
pcopy = pcopy[1:]
|
||||
}
|
||||
|
||||
if pcopy[0] != 'P' {
|
||||
return Period{}, fmt.Errorf("expected 'P' period mark at the start: %s", period)
|
||||
}
|
||||
pcopy = pcopy[1:]
|
||||
|
||||
st := parseState{period, pcopy, false, nil}
|
||||
t := strings.IndexByte(pcopy, 'T')
|
||||
if t >= 0 {
|
||||
st.pcopy = pcopy[t+1:]
|
||||
|
||||
result.hours, st = parseField(st, 'H')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'H' marker: %s", period)
|
||||
}
|
||||
|
||||
result.minutes, st = parseField(st, 'M')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'M' marker: %s", period)
|
||||
}
|
||||
|
||||
result.seconds, st = parseField(st, 'S')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'S' marker: %s", period)
|
||||
}
|
||||
|
||||
st.pcopy = pcopy[:t]
|
||||
}
|
||||
|
||||
result.years, st = parseField(st, 'Y')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'Y' marker: %s", period)
|
||||
}
|
||||
|
||||
result.months, st = parseField(st, 'M')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'M' marker: %s", period)
|
||||
}
|
||||
|
||||
weeks, st := parseField(st, 'W')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'W' marker: %s", period)
|
||||
}
|
||||
|
||||
days, st := parseField(st, 'D')
|
||||
if st.err != nil {
|
||||
return Period{}, fmt.Errorf("expected a number before the 'D' marker: %s", period)
|
||||
}
|
||||
|
||||
result.days = weeks*7 + days
|
||||
//fmt.Printf("%#v\n", st)
|
||||
|
||||
if !st.ok {
|
||||
return Period{}, fmt.Errorf("expected 'Y', 'M', 'W', 'D', 'H', 'M', or 'S' marker: %s", period)
|
||||
}
|
||||
|
||||
return result.normalise64(true).toPeriod(), nil
|
||||
}
|
||||
|
||||
type parseState struct {
|
||||
period, pcopy string
|
||||
ok bool
|
||||
err error
|
||||
}
|
||||
|
||||
func parseField(st parseState, mark byte) (int64, parseState) {
|
||||
//fmt.Printf("%c %#v\n", mark, st)
|
||||
r := int64(0)
|
||||
m := strings.IndexByte(st.pcopy, mark)
|
||||
if m > 0 {
|
||||
r, st.err = parseDecimalFixedPoint(st.pcopy[:m], st.period)
|
||||
if st.err != nil {
|
||||
return 0, st
|
||||
}
|
||||
st.pcopy = st.pcopy[m+1:]
|
||||
st.ok = true
|
||||
}
|
||||
return r, st
|
||||
}
|
||||
|
||||
// Fixed-point three decimal places
|
||||
func parseDecimalFixedPoint(s, original string) (int64, error) {
|
||||
//was := s
|
||||
dec := strings.IndexByte(s, '.')
|
||||
if dec < 0 {
|
||||
dec = strings.IndexByte(s, ',')
|
||||
}
|
||||
|
||||
if dec >= 0 {
|
||||
dp := len(s) - dec
|
||||
if dp > 1 {
|
||||
s = s[:dec] + s[dec+1:dec+2]
|
||||
} else {
|
||||
s = s[:dec] + s[dec+1:] + "0"
|
||||
}
|
||||
} else {
|
||||
s = s + "0"
|
||||
}
|
||||
|
||||
return strconv.ParseInt(s, 10, 64)
|
||||
}
|
739
vendor/github.com/rickb777/date/period/period.go
generated
vendored
Normal file
739
vendor/github.com/rickb777/date/period/period.go
generated
vendored
Normal file
@ -0,0 +1,739 @@
|
||||
// Copyright 2015 Rick Beton. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package period
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const daysPerYearE4 int64 = 3652425 // 365.2425 days by the Gregorian rule
|
||||
const daysPerMonthE4 int64 = 304375 // 30.4375 days per month
|
||||
const daysPerMonthE6 int64 = 30436875 // 30.436875 days per month
|
||||
|
||||
const oneE4 int64 = 10000
|
||||
const oneE5 int64 = 100000
|
||||
const oneE6 int64 = 1000000
|
||||
const oneE7 int64 = 10000000
|
||||
|
||||
const hundredMs = 100 * time.Millisecond
|
||||
|
||||
// reminder: int64 overflow is after 9,223,372,036,854,775,807 (math.MaxInt64)
|
||||
|
||||
// Period holds a period of time and provides conversion to/from ISO-8601 representations.
|
||||
// Therefore there are six fields: years, months, days, hours, minutes, and seconds.
|
||||
//
|
||||
// In the ISO representation, decimal fractions are supported, although only the last non-zero
|
||||
// component is allowed to have a fraction according to the Standard. For example "P2.5Y"
|
||||
// is 2.5 years.
|
||||
//
|
||||
// However, in this implementation, the precision is limited to one decimal place only, by
|
||||
// means of integers with fixed point arithmetic. (This avoids using float32 in the struct,
|
||||
// so there are no problems testing equality using ==.)
|
||||
//
|
||||
// The implementation limits the range of possible values to ± 2^16 / 10 in each field.
|
||||
// Note in particular that the range of years is limited to approximately ± 3276.
|
||||
//
|
||||
// The concept of weeks exists in string representations of periods, but otherwise weeks
|
||||
// are unimportant. The period contains a number of days from which the number of weeks can
|
||||
// be calculated when needed.
|
||||
//
|
||||
// Note that although fractional weeks can be parsed, they will never be returned via String().
|
||||
// This is because the number of weeks is always inferred from the number of days.
|
||||
//
|
||||
type Period struct {
|
||||
years, months, days, hours, minutes, seconds int16
|
||||
}
|
||||
|
||||
// NewYMD creates a simple period without any fractional parts. The fields are initialised verbatim
|
||||
// without any normalisation; e.g. 12 months will not become 1 year. Use the Normalise method if you
|
||||
// need to.
|
||||
//
|
||||
// All the parameters must have the same sign (otherwise a panic occurs).
|
||||
func NewYMD(years, months, days int) Period {
|
||||
return New(years, months, days, 0, 0, 0)
|
||||
}
|
||||
|
||||
// NewHMS creates a simple period without any fractional parts. The fields are initialised verbatim
|
||||
// without any normalisation; e.g. 120 seconds will not become 2 minutes. Use the Normalise method
|
||||
// if you need to.
|
||||
//
|
||||
// All the parameters must have the same sign (otherwise a panic occurs).
|
||||
func NewHMS(hours, minutes, seconds int) Period {
|
||||
return New(0, 0, 0, hours, minutes, seconds)
|
||||
}
|
||||
|
||||
// New creates a simple period without any fractional parts. The fields are initialised verbatim
|
||||
// without any normalisation; e.g. 120 seconds will not become 2 minutes. Use the Normalise method
|
||||
// if you need to.
|
||||
//
|
||||
// All the parameters must have the same sign (otherwise a panic occurs).
|
||||
func New(years, months, days, hours, minutes, seconds int) Period {
|
||||
if (years >= 0 && months >= 0 && days >= 0 && hours >= 0 && minutes >= 0 && seconds >= 0) ||
|
||||
(years <= 0 && months <= 0 && days <= 0 && hours <= 0 && minutes <= 0 && seconds <= 0) {
|
||||
return Period{
|
||||
int16(years) * 10, int16(months) * 10, int16(days) * 10,
|
||||
int16(hours) * 10, int16(minutes) * 10, int16(seconds) * 10,
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("Periods must have homogeneous signs; got P%dY%dM%dDT%dH%dM%dS",
|
||||
years, months, days, hours, minutes, seconds))
|
||||
}
|
||||
|
||||
// TODO NewFloat
|
||||
|
||||
// NewOf converts a time duration to a Period, and also indicates whether the conversion is precise.
|
||||
// Any time duration that spans more than ± 3276 hours will be approximated by assuming that there
|
||||
// are 24 hours per day, 30.4375 per month and 365.2425 days per year.
|
||||
func NewOf(duration time.Duration) (p Period, precise bool) {
|
||||
var sign int16 = 1
|
||||
d := duration
|
||||
if duration < 0 {
|
||||
sign = -1
|
||||
d = -duration
|
||||
}
|
||||
|
||||
sign10 := sign * 10
|
||||
|
||||
totalHours := int64(d / time.Hour)
|
||||
|
||||
// check for 16-bit overflow - occurs near the 4.5 month mark
|
||||
if totalHours < 3277 {
|
||||
// simple HMS case
|
||||
minutes := d % time.Hour / time.Minute
|
||||
seconds := d % time.Minute / hundredMs
|
||||
return Period{0, 0, 0, sign10 * int16(totalHours), sign10 * int16(minutes), sign * int16(seconds)}, true
|
||||
}
|
||||
|
||||
totalDays := totalHours / 24 // ignoring daylight savings adjustments
|
||||
|
||||
if totalDays < 3277 {
|
||||
hours := totalHours - totalDays*24
|
||||
minutes := d % time.Hour / time.Minute
|
||||
seconds := d % time.Minute / hundredMs
|
||||
return Period{0, 0, sign10 * int16(totalDays), sign10 * int16(hours), sign10 * int16(minutes), sign * int16(seconds)}, false
|
||||
}
|
||||
|
||||
// TODO it is uncertain whether this is too imprecise and should be improved
|
||||
years := (oneE4 * totalDays) / daysPerYearE4
|
||||
months := ((oneE4 * totalDays) / daysPerMonthE4) - (12 * years)
|
||||
hours := totalHours - totalDays*24
|
||||
totalDays = ((totalDays * oneE4) - (daysPerMonthE4 * months) - (daysPerYearE4 * years)) / oneE4
|
||||
return Period{sign10 * int16(years), sign10 * int16(months), sign10 * int16(totalDays), sign10 * int16(hours), 0, 0}, false
|
||||
}
|
||||
|
||||
// Between converts the span between two times to a period. Based on the Gregorian conversion
|
||||
// algorithms of `time.Time`, the resultant period is precise.
|
||||
//
|
||||
// The result is not normalised; for time differences less than 3276 days, it will contain zero in the
|
||||
// years and months fields but the number of days may be up to 3275; this reduces errors arising from
|
||||
// the variable lengths of months. For larger time differences, greater than 3276 days, the months and
|
||||
// years fields are used as well.
|
||||
//
|
||||
// Remember that the resultant period does not retain any knowledge of the calendar, so any subsequent
|
||||
// computations applied to the period can only be precise if they concern either the date (year, month,
|
||||
// day) part, or the clock (hour, minute, second) part, but not both.
|
||||
func Between(t1, t2 time.Time) (p Period) {
|
||||
if t1.Location() != t2.Location() {
|
||||
t2 = t2.In(t1.Location())
|
||||
}
|
||||
|
||||
sign := 1
|
||||
if t2.Before(t1) {
|
||||
t1, t2, sign = t2, t1, -1
|
||||
}
|
||||
|
||||
year, month, day, hour, min, sec, hundredth := daysDiff(t1, t2)
|
||||
|
||||
if sign < 0 {
|
||||
p = New(-year, -month, -day, -hour, -min, -sec)
|
||||
p.seconds -= int16(hundredth)
|
||||
} else {
|
||||
p = New(year, month, day, hour, min, sec)
|
||||
p.seconds += int16(hundredth)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, hundredth int) {
|
||||
duration := t2.Sub(t1)
|
||||
|
||||
hh1, mm1, ss1 := t1.Clock()
|
||||
hh2, mm2, ss2 := t2.Clock()
|
||||
|
||||
day = int(duration / (24 * time.Hour))
|
||||
|
||||
hour = int(hh2 - hh1)
|
||||
min = int(mm2 - mm1)
|
||||
sec = int(ss2 - ss1)
|
||||
hundredth = (t2.Nanosecond() - t1.Nanosecond()) / 100000000
|
||||
|
||||
// Normalize negative values
|
||||
if sec < 0 {
|
||||
sec += 60
|
||||
min--
|
||||
}
|
||||
|
||||
if min < 0 {
|
||||
min += 60
|
||||
hour--
|
||||
}
|
||||
|
||||
if hour < 0 {
|
||||
hour += 24
|
||||
// no need to reduce day - it's calculated differently.
|
||||
}
|
||||
|
||||
// test 16bit storage limit (with 1 fixed decimal place)
|
||||
if day > 3276 {
|
||||
y1, m1, d1 := t1.Date()
|
||||
y2, m2, d2 := t2.Date()
|
||||
year = y2 - y1
|
||||
month = int(m2 - m1)
|
||||
day = d2 - d1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsZero returns true if applied to a zero-length period.
|
||||
func (period Period) IsZero() bool {
|
||||
return period == Period{}
|
||||
}
|
||||
|
||||
// IsPositive returns true if any field is greater than zero. By design, this also implies that
|
||||
// all the other fields are greater than or equal to zero.
|
||||
func (period Period) IsPositive() bool {
|
||||
return period.years > 0 || period.months > 0 || period.days > 0 ||
|
||||
period.hours > 0 || period.minutes > 0 || period.seconds > 0
|
||||
}
|
||||
|
||||
// IsNegative returns true if any field is negative. By design, this also implies that
|
||||
// all the other fields are negative or zero.
|
||||
func (period Period) IsNegative() bool {
|
||||
return period.years < 0 || period.months < 0 || period.days < 0 ||
|
||||
period.hours < 0 || period.minutes < 0 || period.seconds < 0
|
||||
}
|
||||
|
||||
// Sign returns +1 for positive periods and -1 for negative periods. If the period is zero, it returns zero.
|
||||
func (period Period) Sign() int {
|
||||
if period.IsZero() {
|
||||
return 0
|
||||
}
|
||||
if period.IsNegative() {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// OnlyYMD returns a new Period with only the year, month and day fields. The hour,
|
||||
// minute and second fields are zeroed.
|
||||
func (period Period) OnlyYMD() Period {
|
||||
return Period{period.years, period.months, period.days, 0, 0, 0}
|
||||
}
|
||||
|
||||
// OnlyHMS returns a new Period with only the hour, minute and second fields. The year,
|
||||
// month and day fields are zeroed.
|
||||
func (period Period) OnlyHMS() Period {
|
||||
return Period{0, 0, 0, period.hours, period.minutes, period.seconds}
|
||||
}
|
||||
|
||||
// Abs converts a negative period to a positive one.
|
||||
func (period Period) Abs() Period {
|
||||
return Period{absInt16(period.years), absInt16(period.months), absInt16(period.days),
|
||||
absInt16(period.hours), absInt16(period.minutes), absInt16(period.seconds)}
|
||||
}
|
||||
|
||||
func absInt16(v int16) int16 {
|
||||
if v < 0 {
|
||||
return -v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Negate changes the sign of the period.
|
||||
func (period Period) Negate() Period {
|
||||
return Period{-period.years, -period.months, -period.days, -period.hours, -period.minutes, -period.seconds}
|
||||
}
|
||||
|
||||
// Add adds two periods together. Use this method along with Negate in order to subtract periods.
|
||||
//
|
||||
// The result is not normalised and may overflow arithmetically (to make this unlikely, use Normalise on
|
||||
// the inputs before adding them).
|
||||
func (period Period) Add(that Period) Period {
|
||||
return Period{
|
||||
period.years + that.years,
|
||||
period.months + that.months,
|
||||
period.days + that.days,
|
||||
period.hours + that.hours,
|
||||
period.minutes + that.minutes,
|
||||
period.seconds + that.seconds,
|
||||
}
|
||||
}
|
||||
|
||||
// Scale a period by a multiplication factor. Obviously, this can both enlarge and shrink it,
|
||||
// and change the sign if negative. The result is normalised.
|
||||
//
|
||||
// Bear in mind that the internal representation is limited by fixed-point arithmetic with one
|
||||
// decimal place; each field is only int16.
|
||||
//
|
||||
// Known issue: scaling by a large reduction factor (i.e. much less than one) doesn't work properly.
|
||||
func (period Period) Scale(factor float32) Period {
|
||||
|
||||
if -0.5 < factor && factor < 0.5 {
|
||||
d, pr1 := period.Duration()
|
||||
mul := float64(d) * float64(factor)
|
||||
p2, pr2 := NewOf(time.Duration(mul))
|
||||
return p2.Normalise(pr1 && pr2)
|
||||
}
|
||||
|
||||
y := int64(float32(period.years) * factor)
|
||||
m := int64(float32(period.months) * factor)
|
||||
d := int64(float32(period.days) * factor)
|
||||
hh := int64(float32(period.hours) * factor)
|
||||
mm := int64(float32(period.minutes) * factor)
|
||||
ss := int64(float32(period.seconds) * factor)
|
||||
|
||||
return (&period64{y, m, d, hh, mm, ss, false}).normalise64(true).toPeriod()
|
||||
}
|
||||
|
||||
// Years gets the whole number of years in the period.
|
||||
// The result is the number of years and does not include any other field.
|
||||
func (period Period) Years() int {
|
||||
return int(period.YearsFloat())
|
||||
}
|
||||
|
||||
// YearsFloat gets the number of years in the period, including a fraction if any is present.
|
||||
// The result is the number of years and does not include any other field.
|
||||
func (period Period) YearsFloat() float32 {
|
||||
return float32(period.years) / 10
|
||||
}
|
||||
|
||||
// Months gets the whole number of months in the period.
|
||||
// The result is the number of months and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 12 months are added to
|
||||
// the number of years, so the number of months will be reduced correspondingly.
|
||||
func (period Period) Months() int {
|
||||
return int(period.MonthsFloat())
|
||||
}
|
||||
|
||||
// MonthsFloat gets the number of months in the period.
|
||||
// The result is the number of months and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 12 months are added to
|
||||
// the number of years, so the number of months will be reduced correspondingly.
|
||||
func (period Period) MonthsFloat() float32 {
|
||||
return float32(period.months) / 10
|
||||
}
|
||||
|
||||
// Days gets the whole number of days in the period. This includes the implied
|
||||
// number of weeks but does not include any other field.
|
||||
func (period Period) Days() int {
|
||||
return int(period.DaysFloat())
|
||||
}
|
||||
|
||||
// DaysFloat gets the number of days in the period. This includes the implied
|
||||
// number of weeks but does not include any other field.
|
||||
func (period Period) DaysFloat() float32 {
|
||||
return float32(period.days) / 10
|
||||
}
|
||||
|
||||
// Weeks calculates the number of whole weeks from the number of days. If the result
|
||||
// would contain a fraction, it is truncated.
|
||||
// The result is the number of weeks and does not include any other field.
|
||||
//
|
||||
// Note that weeks are synthetic: they are internally represented using days.
|
||||
// See ModuloDays(), which returns the number of days excluding whole weeks.
|
||||
func (period Period) Weeks() int {
|
||||
return int(period.days) / 70
|
||||
}
|
||||
|
||||
// WeeksFloat calculates the number of weeks from the number of days.
|
||||
// The result is the number of weeks and does not include any other field.
|
||||
func (period Period) WeeksFloat() float32 {
|
||||
return float32(period.days) / 70
|
||||
}
|
||||
|
||||
// ModuloDays calculates the whole number of days remaining after the whole number of weeks
|
||||
// has been excluded.
|
||||
func (period Period) ModuloDays() int {
|
||||
days := absInt16(period.days) % 70
|
||||
f := int(days / 10)
|
||||
if period.days < 0 {
|
||||
return -f
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Hours gets the whole number of hours in the period.
|
||||
// The result is the number of hours and does not include any other field.
|
||||
func (period Period) Hours() int {
|
||||
return int(period.HoursFloat())
|
||||
}
|
||||
|
||||
// HoursFloat gets the number of hours in the period.
|
||||
// The result is the number of hours and does not include any other field.
|
||||
func (period Period) HoursFloat() float32 {
|
||||
return float32(period.hours) / 10
|
||||
}
|
||||
|
||||
// Minutes gets the whole number of minutes in the period.
|
||||
// The result is the number of minutes and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 60 minutes are added to
|
||||
// the number of hours, so the number of minutes will be reduced correspondingly.
|
||||
func (period Period) Minutes() int {
|
||||
return int(period.MinutesFloat())
|
||||
}
|
||||
|
||||
// MinutesFloat gets the number of minutes in the period.
|
||||
// The result is the number of minutes and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 60 minutes are added to
|
||||
// the number of hours, so the number of minutes will be reduced correspondingly.
|
||||
func (period Period) MinutesFloat() float32 {
|
||||
return float32(period.minutes) / 10
|
||||
}
|
||||
|
||||
// Seconds gets the whole number of seconds in the period.
|
||||
// The result is the number of seconds and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 60 seconds are added to
|
||||
// the number of minutes, so the number of seconds will be reduced correspondingly.
|
||||
func (period Period) Seconds() int {
|
||||
return int(period.SecondsFloat())
|
||||
}
|
||||
|
||||
// SecondsFloat gets the number of seconds in the period.
|
||||
// The result is the number of seconds and does not include any other field.
|
||||
//
|
||||
// Note that after normalisation, whole multiple of 60 seconds are added to
|
||||
// the number of minutes, so the number of seconds will be reduced correspondingly.
|
||||
func (period Period) SecondsFloat() float32 {
|
||||
return float32(period.seconds) / 10
|
||||
}
|
||||
|
||||
// AddTo adds the period to a time, returning the result.
|
||||
// A flag is also returned that is true when the conversion was precise and false otherwise.
|
||||
//
|
||||
// When the period specifies hours, minutes and seconds only, the result is precise.
|
||||
// Also, when the period specifies whole years, months and days (i.e. without fractions), the
|
||||
// result is precise. However, when years, months or days contains fractions, the result
|
||||
// is only an approximation (it assumes that all days are 24 hours and every year is 365.2425 days).
|
||||
func (period Period) AddTo(t time.Time) (time.Time, bool) {
|
||||
wholeYears := (period.years % 10) == 0
|
||||
wholeMonths := (period.months % 10) == 0
|
||||
wholeDays := (period.days % 10) == 0
|
||||
|
||||
if wholeYears && wholeMonths && wholeDays {
|
||||
// in this case, time.AddDate provides an exact solution
|
||||
stE3 := totalSecondsE3(period)
|
||||
t1 := t.AddDate(int(period.years/10), int(period.months/10), int(period.days/10))
|
||||
return t1.Add(stE3 * time.Millisecond), true
|
||||
}
|
||||
|
||||
d, precise := period.Duration()
|
||||
return t.Add(d), precise
|
||||
}
|
||||
|
||||
// DurationApprox converts a period to the equivalent duration in nanoseconds.
|
||||
// When the period specifies hours, minutes and seconds only, the result is precise.
|
||||
// however, when the period specifies years, months and days, it is impossible to be precise
|
||||
// because the result may depend on knowing date and timezone information, so the duration
|
||||
// is estimated on the basis of a year being 365.2425 days and a month being
|
||||
// 1/12 of a that; days are all assumed to be 24 hours long.
|
||||
func (period Period) DurationApprox() time.Duration {
|
||||
d, _ := period.Duration()
|
||||
return d
|
||||
}
|
||||
|
||||
// Duration converts a period to the equivalent duration in nanoseconds.
|
||||
// A flag is also returned that is true when the conversion was precise and false otherwise.
|
||||
//
|
||||
// When the period specifies hours, minutes and seconds only, the result is precise.
|
||||
// however, when the period specifies years, months and days, it is impossible to be precise
|
||||
// because the result may depend on knowing date and timezone information, so the duration
|
||||
// is estimated on the basis of a year being 365.2425 days and a month being
|
||||
// 1/12 of a that; days are all assumed to be 24 hours long.
|
||||
func (period Period) Duration() (time.Duration, bool) {
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
tdE6 := time.Duration(totalDaysApproxE7(period) * 8640)
|
||||
stE3 := totalSecondsE3(period)
|
||||
return tdE6*time.Microsecond + stE3*time.Millisecond, tdE6 == 0
|
||||
}
|
||||
|
||||
func totalSecondsE3(period Period) time.Duration {
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
// and these are divided by 1E1
|
||||
hhE3 := time.Duration(period.hours) * 360000
|
||||
mmE3 := time.Duration(period.minutes) * 6000
|
||||
ssE3 := time.Duration(period.seconds) * 100
|
||||
return hhE3 + mmE3 + ssE3
|
||||
}
|
||||
|
||||
func totalDaysApproxE7(period Period) int64 {
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
ydE6 := int64(period.years) * (daysPerYearE4 * 100)
|
||||
mdE6 := int64(period.months) * daysPerMonthE6
|
||||
ddE6 := int64(period.days) * oneE6
|
||||
return ydE6 + mdE6 + ddE6
|
||||
}
|
||||
|
||||
// TotalDaysApprox gets the approximate total number of days in the period. The approximation assumes
|
||||
// a year is 365.2425 days and a month is 1/12 of that. Whole multiples of 24 hours are also included
|
||||
// in the calculation.
|
||||
func (period Period) TotalDaysApprox() int {
|
||||
pn := period.Normalise(false)
|
||||
tdE6 := totalDaysApproxE7(pn)
|
||||
hE6 := (int64(pn.hours) * oneE6) / 24
|
||||
return int((tdE6 + hE6) / oneE7)
|
||||
}
|
||||
|
||||
// TotalMonthsApprox gets the approximate total number of months in the period. The days component
|
||||
// is included by approximation, assuming a year is 365.2425 days and a month is 1/12 of that.
|
||||
// Whole multiples of 24 hours are also included in the calculation.
|
||||
func (period Period) TotalMonthsApprox() int {
|
||||
pn := period.Normalise(false)
|
||||
mE1 := int64(pn.years)*12 + int64(pn.months)
|
||||
hE1 := int64(pn.hours) / 24
|
||||
dE1 := ((int64(pn.days) + hE1) * oneE6) / daysPerMonthE6
|
||||
return int((mE1 + dE1) / 10)
|
||||
}
|
||||
|
||||
// Normalise attempts to simplify the fields. It operates in either precise or imprecise mode.
|
||||
//
|
||||
// Because the number of hours per day is imprecise (due to daylight savings etc), and because
|
||||
// the number of days per month is variable in the Gregorian calendar, there is a reluctance
|
||||
// to transfer time too or from the days element. To give control over this, there are two modes.
|
||||
//
|
||||
// In precise mode:
|
||||
// Multiples of 60 seconds become minutes.
|
||||
// Multiples of 60 minutes become hours.
|
||||
// Multiples of 12 months become years.
|
||||
//
|
||||
// Additionally, in imprecise mode:
|
||||
// Multiples of 24 hours become days.
|
||||
// Multiples of approx. 30.4 days become months.
|
||||
//
|
||||
// Note that leap seconds are disregarded: every minute is assumed to have 60 seconds.
|
||||
func (period Period) Normalise(precise bool) Period {
|
||||
const limit = 32670 - (32670 / 60)
|
||||
|
||||
// can we use a quicker algorithm for HHMMSS with int16 arithmetic?
|
||||
if period.years == 0 && period.months == 0 &&
|
||||
(!precise || period.days == 0) &&
|
||||
period.hours > -limit && period.hours < limit {
|
||||
|
||||
return period.normaliseHHMMSS(precise)
|
||||
}
|
||||
|
||||
// can we use a quicker algorithm for YYMM with int16 arithmetic?
|
||||
if (period.years != 0 || period.months != 0) && //period.months%10 == 0 &&
|
||||
period.days == 0 && period.hours == 0 && period.minutes == 0 && period.seconds == 0 {
|
||||
|
||||
return period.normaliseYYMM()
|
||||
}
|
||||
|
||||
// do things the no-nonsense way using int64 arithmetic
|
||||
return period.toPeriod64().normalise64(precise).toPeriod()
|
||||
}
|
||||
|
||||
func (period Period) normaliseHHMMSS(precise bool) Period {
|
||||
s := period.Sign()
|
||||
ap := period.Abs()
|
||||
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
ap.minutes += (ap.seconds / 600) * 10
|
||||
ap.seconds = ap.seconds % 600
|
||||
|
||||
ap.hours += (ap.minutes / 600) * 10
|
||||
ap.minutes = ap.minutes % 600
|
||||
|
||||
// up to 36 hours stays as hours
|
||||
if !precise && ap.hours > 360 {
|
||||
ap.days += (ap.hours / 240) * 10
|
||||
ap.hours = ap.hours % 240
|
||||
}
|
||||
|
||||
d10 := ap.days % 10
|
||||
if d10 != 0 && (ap.hours != 0 || ap.minutes != 0 || ap.seconds != 0) {
|
||||
ap.hours += d10 * 24
|
||||
ap.days -= d10
|
||||
}
|
||||
|
||||
hh10 := ap.hours % 10
|
||||
if hh10 != 0 {
|
||||
ap.minutes += hh10 * 60
|
||||
ap.hours -= hh10
|
||||
}
|
||||
|
||||
mm10 := ap.minutes % 10
|
||||
if mm10 != 0 {
|
||||
ap.seconds += mm10 * 60
|
||||
ap.minutes -= mm10
|
||||
}
|
||||
|
||||
if s < 0 {
|
||||
return ap.Negate()
|
||||
}
|
||||
return ap
|
||||
}
|
||||
|
||||
func (period Period) normaliseYYMM() Period {
|
||||
s := period.Sign()
|
||||
ap := period.Abs()
|
||||
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
if ap.months > 129 {
|
||||
ap.years += (ap.months / 120) * 10
|
||||
ap.months = ap.months % 120
|
||||
}
|
||||
|
||||
y10 := ap.years % 10
|
||||
if y10 != 0 && (ap.years < 10 || ap.months != 0) {
|
||||
ap.months += y10 * 12
|
||||
ap.years -= y10
|
||||
}
|
||||
|
||||
if s < 0 {
|
||||
return ap.Negate()
|
||||
}
|
||||
return ap
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// used for stages in arithmetic
|
||||
type period64 struct {
|
||||
years, months, days, hours, minutes, seconds int64
|
||||
neg bool
|
||||
}
|
||||
|
||||
func (period Period) toPeriod64() *period64 {
|
||||
return &period64{
|
||||
int64(period.years), int64(period.months), int64(period.days),
|
||||
int64(period.hours), int64(period.minutes), int64(period.seconds),
|
||||
false,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *period64) toPeriod() Period {
|
||||
if p.neg {
|
||||
return Period{
|
||||
int16(-p.years), int16(-p.months), int16(-p.days),
|
||||
int16(-p.hours), int16(-p.minutes), int16(-p.seconds),
|
||||
}
|
||||
}
|
||||
|
||||
return Period{
|
||||
int16(p.years), int16(p.months), int16(p.days),
|
||||
int16(p.hours), int16(p.minutes), int16(p.seconds),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *period64) normalise64(precise bool) *period64 {
|
||||
return p.abs().rippleUp(precise).moveFractionToRight()
|
||||
}
|
||||
|
||||
func (p *period64) abs() *period64 {
|
||||
|
||||
if !p.neg {
|
||||
if p.years < 0 {
|
||||
p.years = -p.years
|
||||
p.neg = true
|
||||
}
|
||||
|
||||
if p.months < 0 {
|
||||
p.months = -p.months
|
||||
p.neg = true
|
||||
}
|
||||
|
||||
if p.days < 0 {
|
||||
p.days = -p.days
|
||||
p.neg = true
|
||||
}
|
||||
|
||||
if p.hours < 0 {
|
||||
p.hours = -p.hours
|
||||
p.neg = true
|
||||
}
|
||||
|
||||
if p.minutes < 0 {
|
||||
p.minutes = -p.minutes
|
||||
p.neg = true
|
||||
}
|
||||
|
||||
if p.seconds < 0 {
|
||||
p.seconds = -p.seconds
|
||||
p.neg = true
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *period64) rippleUp(precise bool) *period64 {
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
|
||||
p.minutes = p.minutes + (p.seconds/600)*10
|
||||
p.seconds = p.seconds % 600
|
||||
|
||||
p.hours = p.hours + (p.minutes/600)*10
|
||||
p.minutes = p.minutes % 600
|
||||
|
||||
// 32670-(32670/60)-(32670/3600) = 32760 - 546 - 9.1 = 32204.9
|
||||
if !precise || p.hours > 32204 {
|
||||
p.days += (p.hours / 240) * 10
|
||||
p.hours = p.hours % 240
|
||||
}
|
||||
|
||||
if !precise || p.days > 32760 {
|
||||
dE6 := p.days * oneE6
|
||||
p.months += dE6 / daysPerMonthE6
|
||||
p.days = (dE6 % daysPerMonthE6) / oneE6
|
||||
}
|
||||
|
||||
p.years = p.years + (p.months/120)*10
|
||||
p.months = p.months % 120
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// moveFractionToRight applies the rule that only the smallest field is permitted to have a decimal fraction.
|
||||
func (p *period64) moveFractionToRight() *period64 {
|
||||
// remember that the fields are all fixed-point 1E1
|
||||
|
||||
y10 := p.years % 10
|
||||
if y10 != 0 && (p.months != 0 || p.days != 0 || p.hours != 0 || p.minutes != 0 || p.seconds != 0) {
|
||||
p.months += y10 * 12
|
||||
p.years = (p.years / 10) * 10
|
||||
}
|
||||
|
||||
m10 := p.months % 10
|
||||
if m10 != 0 && (p.days != 0 || p.hours != 0 || p.minutes != 0 || p.seconds != 0) {
|
||||
p.days += (m10 * daysPerMonthE6) / oneE6
|
||||
p.months = (p.months / 10) * 10
|
||||
}
|
||||
|
||||
d10 := p.days % 10
|
||||
if d10 != 0 && (p.hours != 0 || p.minutes != 0 || p.seconds != 0) {
|
||||
p.hours += d10 * 24
|
||||
p.days = (p.days / 10) * 10
|
||||
}
|
||||
|
||||
hh10 := p.hours % 10
|
||||
if hh10 != 0 && (p.minutes != 0 || p.seconds != 0) {
|
||||
p.minutes += hh10 * 60
|
||||
p.hours = (p.hours / 10) * 10
|
||||
}
|
||||
|
||||
mm10 := p.minutes % 10
|
||||
if mm10 != 0 && p.seconds != 0 {
|
||||
p.seconds += mm10 * 60
|
||||
p.minutes = (p.minutes / 10) * 10
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
26
vendor/github.com/rickb777/plural/.gitignore
generated
vendored
Normal file
26
vendor/github.com/rickb777/plural/.gitignore
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj/
|
||||
_test/
|
||||
vendor/
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
*.out
|
11
vendor/github.com/rickb777/plural/.travis.yml
generated
vendored
Normal file
11
vendor/github.com/rickb777/plural/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go get -t -v .
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
script:
|
||||
- ./build+test.sh
|
27
vendor/github.com/rickb777/plural/LICENSE
generated
vendored
Normal file
27
vendor/github.com/rickb777/plural/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2016, Rick Beton
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of plural nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
vendor/github.com/rickb777/plural/README.md
generated
vendored
Normal file
28
vendor/github.com/rickb777/plural/README.md
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# plural - Simple Go API for Pluralisation.
|
||||
|
||||
[](https://godoc.org/github.com/rickb777/plural)
|
||||
[](https://travis-ci.org/rickb777/plural)
|
||||
[](https://coveralls.io/github/rickb777/plural?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/rickb777/plural)
|
||||
[](https://github.com/rickb777/plural/issues)
|
||||
|
||||
Package plural provides simple support for localising plurals in a flexible range of different styles.
|
||||
|
||||
There are considerable differences around the world in the way plurals are handled. This is a simple
|
||||
but competent API for catering with these differences when presenting to people formatted text with numbers.
|
||||
|
||||
This package is able to format **countable things** and **continuous values**. It can handle integers
|
||||
and floating point numbers equally and this allows you to decide to what extent each is appropriate.
|
||||
|
||||
For example, `2 cars` might weigh `1.6 tonnes`; both categories are covered.
|
||||
|
||||
This API is deliberately simple; it doesn't address the full gamut of internationalisation. If that's
|
||||
what you need, you should consider products such as https://github.com/nicksnyder/go-i18n instead.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/rickb777/plural
|
||||
|
||||
## Status
|
||||
|
||||
This library has been in reliable production use for some time. Versioning follows the well-known semantic version pattern.
|
13
vendor/github.com/rickb777/plural/build+test.sh
generated
vendored
Normal file
13
vendor/github.com/rickb777/plural/build+test.sh
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash -e
|
||||
cd $(dirname $0)
|
||||
PATH=$HOME/gopath/bin:$GOPATH/bin:$PATH
|
||||
|
||||
if ! type -p goveralls; then
|
||||
echo go get github.com/mattn/goveralls
|
||||
go get github.com/mattn/goveralls
|
||||
fi
|
||||
|
||||
echo date...
|
||||
go test -v -covermode=count -coverprofile=date.out .
|
||||
go tool cover -func=date.out
|
||||
[ -z "$COVERALLS_TOKEN" ] || goveralls -coverprofile=date.out -service=travis-ci -repotoken $COVERALLS_TOKEN
|
20
vendor/github.com/rickb777/plural/doc.go
generated
vendored
Normal file
20
vendor/github.com/rickb777/plural/doc.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2016 Rick Beton. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package plural provides simple support for localising plurals in a flexible range of different styles.
|
||||
//
|
||||
// There are considerable differences around the world in the way plurals are handled. This is
|
||||
// a simple but competent API for catering with these differences when presenting to people formatted text with numbers.
|
||||
//
|
||||
// This package is able to format countable things and continuous values. It can handle integers
|
||||
// and floating point numbers equally and this allows you to decide to what extent each is appropriate.
|
||||
//
|
||||
// For example, "2 cars" might weigh "1.6 tonnes"; both categories are covered.
|
||||
//
|
||||
// This API is deliberately simple; it doesn't address the full gamut of internationalisation. If that's
|
||||
// what you need, you should consider products such as https://github.com/nicksnyder/go-i18n instead.
|
||||
//
|
||||
// Please see the examples and associated api documentation.
|
||||
//
|
||||
package plural
|
203
vendor/github.com/rickb777/plural/plural.go
generated
vendored
Normal file
203
vendor/github.com/rickb777/plural/plural.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package plural
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Case is the inner element of this API and describes one case. When the number to be described
|
||||
// matches the number here, the corresponding format string will be used. If the format string
|
||||
// includes '%', then fmt.Sprintf will be used. Otherwise the format string will be returned verbatim.
|
||||
type Case struct {
|
||||
Number int
|
||||
Format string
|
||||
}
|
||||
|
||||
// Plurals provides a list of plural cases in the order they will be searched.
|
||||
// For plurals of continuous ranges (e.g. weight), the cases must be in ascending number order.
|
||||
// For plurals of discrete ranges (i.e. integers), the cases can be in any order you require,
|
||||
// but will conventionally be in ascending number order.
|
||||
// If no match is found, the last case will be used.
|
||||
type Plurals []Case
|
||||
|
||||
// Format searches through the plural cases for the first match. If none is found, the last
|
||||
// case is used. The value passed in can be any number type, or pointer to a number type, except
|
||||
// complex numbers are not supported. The value will be converted to an int in order to
|
||||
// find the first case that matches.
|
||||
// The only possible error arises if value has a type that is not numeric.
|
||||
// It panics if 'plurals' is empty.
|
||||
func (plurals Plurals) Format(value interface{}) (string, error) {
|
||||
switch x := value.(type) {
|
||||
case int:
|
||||
return plurals.FormatInt(x), nil
|
||||
case int8:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case int16:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case int32:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case int64:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case uint8:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case uint16:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case uint32:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case uint64:
|
||||
return plurals.FormatInt(int(x)), nil
|
||||
case float32:
|
||||
return plurals.FormatFloat(x), nil
|
||||
case float64:
|
||||
return plurals.FormatFloat(float32(x)), nil
|
||||
|
||||
case *int:
|
||||
return plurals.FormatInt(*x), nil
|
||||
case *int8:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *int16:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *int32:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *int64:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *uint:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *uint8:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *uint16:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *uint32:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *uint64:
|
||||
return plurals.FormatInt(int(*x)), nil
|
||||
case *float32:
|
||||
return plurals.FormatFloat(*x), nil
|
||||
case *float64:
|
||||
return plurals.FormatFloat(float32(*x)), nil
|
||||
|
||||
case nil:
|
||||
return "", fmt.Errorf("Unexpected nil value for %s", plurals)
|
||||
default:
|
||||
return "", fmt.Errorf("Unexpected type %T for %v", x, value)
|
||||
}
|
||||
}
|
||||
|
||||
// FormatInt expresses an int in plural form. It panics if 'plurals' is empty.
|
||||
func (plurals Plurals) FormatInt(value int) string {
|
||||
for _, c := range plurals {
|
||||
if value == c.Number {
|
||||
return c.FormatInt(value)
|
||||
}
|
||||
}
|
||||
c := plurals[len(plurals)-1]
|
||||
return c.FormatInt(value)
|
||||
}
|
||||
|
||||
// FormatFloat expresses a float32 in plural form. It panics if 'plurals' is empty.
|
||||
func (plurals Plurals) FormatFloat(value float32) string {
|
||||
for _, c := range plurals {
|
||||
if value <= float32(c.Number) {
|
||||
return c.FormatFloat(value)
|
||||
}
|
||||
}
|
||||
c := plurals[len(plurals)-1]
|
||||
return c.FormatFloat(value)
|
||||
}
|
||||
|
||||
// FormatInt renders a specific case with a given value.
|
||||
func (c Case) FormatInt(value int) string {
|
||||
if strings.IndexByte(c.Format, '%') < 0 {
|
||||
return c.Format
|
||||
}
|
||||
return fmt.Sprintf(c.Format, value)
|
||||
}
|
||||
|
||||
// FormatFloat renders a specific case with a given value.
|
||||
func (c Case) FormatFloat(value float32) string {
|
||||
if strings.IndexByte(c.Format, '%') < 0 {
|
||||
return c.Format
|
||||
}
|
||||
return fmt.Sprintf(c.Format, value)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// String implements io.Stringer.
|
||||
func (plurals Plurals) String() string {
|
||||
ss := make([]string, 0, len(plurals))
|
||||
for _, c := range plurals {
|
||||
ss = append(ss, c.String())
|
||||
}
|
||||
return fmt.Sprintf("Plurals(%s)", strings.Join(ss, ", "))
|
||||
}
|
||||
|
||||
// String implements io.Stringer.
|
||||
func (c Case) String() string {
|
||||
return fmt.Sprintf("{%v -> %q}", c.Number, c.Format)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// ByOrdinal constructs a simple set of cases using small ordinals (0, 1, 2, 3 etc), which is a
|
||||
// common requirement. It is an alias for FromZero.
|
||||
func ByOrdinal(zeroth string, rest ...string) Plurals {
|
||||
return FromZero(zeroth, rest...)
|
||||
}
|
||||
|
||||
// FromZero constructs a simple set of cases using small ordinals (0, 1, 2, 3 etc), which is a
|
||||
// common requirement. It prevents creation of a Plurals list that is empty, which would be invalid.
|
||||
//
|
||||
// The 'zeroth' string becomes Case{0, first}. The rest are appended similarly. Notice that the
|
||||
// counting starts from zero.
|
||||
//
|
||||
// So
|
||||
//
|
||||
// FromZero("nothing", "%v thing", "%v things")
|
||||
//
|
||||
// is simply a shorthand for
|
||||
//
|
||||
// Plurals{Case{0, "nothing"}, Case{1, "%v thing"}, Case{2, "%v things"}}
|
||||
//
|
||||
// which would also be valid but a little more verbose.
|
||||
//
|
||||
// This helper function is less flexible than constructing Plurals directly, but covers many common
|
||||
// situations.
|
||||
func FromZero(zeroth string, rest ...string) Plurals {
|
||||
p := make(Plurals, 0, len(rest)+1)
|
||||
p = append(p, Case{0, zeroth})
|
||||
for i, c := range rest {
|
||||
p = append(p, Case{i+1, c})
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// FromOne constructs a simple set of cases using small positive numbers (1, 2, 3 etc), which is a
|
||||
// common requirement. It prevents creation of a Plurals list that is empty, which would be invalid.
|
||||
//
|
||||
// The 'first' string becomes Case{1, first}. The rest are appended similarly. Notice that the
|
||||
// counting starts from one.
|
||||
//
|
||||
// So
|
||||
//
|
||||
// FromOne("%v thing", "%v things")
|
||||
//
|
||||
// is simply a shorthand for
|
||||
//
|
||||
// Plurals{Case{1, "%v thing"}, Case{2, "%v things"}}
|
||||
//
|
||||
// which would also be valid but a little more verbose.
|
||||
//
|
||||
// Note the behaviour of formatting when the count is zero. As a consequence of Format evaluating
|
||||
// the cases in order, FromOne(...).FormatInt(0) will pick the last case you provide, not the first.
|
||||
//
|
||||
// This helper function is less flexible than constructing Plurals directly, but covers many common
|
||||
// situations.
|
||||
func FromOne(first string, rest ...string) Plurals {
|
||||
p := make(Plurals, 0, len(rest)+1)
|
||||
p = append(p, Case{1, first})
|
||||
for i, c := range rest {
|
||||
p = append(p, Case{i+2, c})
|
||||
}
|
||||
return p
|
||||
}
|
Reference in New Issue
Block a user