Documentation ¶
Overview ¶
Package period provides functionality for periods of time using ISO-8601 conventions. This deals with years, months, weeks/days, hours, minutes and seconds.
*** Warning: this package is the subject of many issues, so a replacement is under development. Please see https://github.com/rickb777/period.
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.
Index ¶
- Constants
- Variables
- type Period
- func Between(t1, t2 time.Time) (p Period)
- func MustParse(value string, normalise ...bool) Period
- func New(years, months, days, hours, minutes, seconds int) Period
- func NewHMS(hours, minutes, seconds int) Period
- func NewOf(duration time.Duration) (p Period, precise bool)
- func NewYMD(years, months, days int) Period
- func Parse(period string, normalise ...bool) (Period, error)
- func ParseWithNormalise(period string, normalise bool) (Period, error)
- func (period Period) Abs() Period
- func (period Period) Add(that Period) Period
- func (period Period) AddTo(t time.Time) (time.Time, bool)
- func (period Period) Days() int
- func (period Period) DaysFloat() float32
- func (period Period) Duration() (time.Duration, bool)
- func (period Period) DurationApprox() time.Duration
- func (period Period) Format() string
- func (period Period) FormatWithPeriodNames(...) string
- func (period Period) FormatWithoutWeeks() string
- func (period Period) Hours() int
- func (period Period) HoursFloat() float32
- func (period Period) IsNegative() bool
- func (period Period) IsPositive() bool
- func (period Period) IsZero() bool
- func (period Period) MarshalBinary() ([]byte, error)
- func (period Period) MarshalText() ([]byte, error)
- func (period Period) Minutes() int
- func (period Period) MinutesFloat() float32
- func (period Period) ModuloDays() int
- func (period Period) Months() int
- func (period Period) MonthsFloat() float32
- func (period Period) Negate() Period
- func (period Period) Normalise(precise bool) Period
- func (period Period) OnlyHMS() Period
- func (period Period) OnlyYMD() Period
- func (period Period) Scale(factor float32) Period
- func (period Period) ScaleWithOverflowCheck(factor float32) (Period, error)
- func (period *Period) Scan(value interface{}) (err error)
- func (period Period) Seconds() int
- func (period Period) SecondsFloat() float32
- func (period *Period) Set(p string) error
- func (period Period) Sign() int
- func (period Period) Simplify(precise bool, th ...int) Period
- func (period Period) String() string
- func (period Period) TotalDaysApprox() int
- func (period Period) TotalMonthsApprox() int
- func (period Period) Type() string
- func (period *Period) UnmarshalBinary(data []byte) error
- func (period *Period) UnmarshalText(data []byte) (err error)
- func (period Period) Value() (driver.Value, error)
- func (period Period) Weeks() int
- func (period Period) WeeksFloat() float32
- func (period Period) Years() int
- func (period Period) YearsFloat() float32
Constants ¶
const ( Year ymdDesignator = 'Y' Month ymdDesignator = 'M' Week ymdDesignator = 'W' Day ymdDesignator = 'D' Hour hmsDesignator = 'H' Minute hmsDesignator = 'M' Second hmsDesignator = 'S' )
const ( Unready itemState = iota Armed Set )
Variables ¶
var PeriodDayNames = plural.FromZero("%v days", "%v day", "%v days")
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 PeriodHourNames = plural.FromZero("", "%v hour", "%v hours")
PeriodHourNames is as for PeriodDayNames but for hours.
var PeriodMinuteNames = plural.FromZero("", "%v minute", "%v minutes")
PeriodMinuteNames is as for PeriodDayNames but for minutes.
var PeriodMonthNames = plural.FromZero("", "%v month", "%v months")
PeriodMonthNames is as for PeriodDayNames but for months.
var PeriodSecondNames = plural.FromZero("", "%v second", "%v seconds")
PeriodSecondNames is as for PeriodDayNames but for seconds.
var PeriodWeekNames = plural.FromZero("", "%v week", "%v weeks")
PeriodWeekNames is as for PeriodDayNames but for weeks.
var PeriodYearNames = plural.FromZero("", "%v year", "%v years")
PeriodYearNames is as for PeriodDayNames but for years.
Functions ¶
This section is empty.
Types ¶
type Period ¶
type Period struct {
// contains filtered or unexported fields
}
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.
func Between ¶
Between converts the span between two times to a period. Based on the Gregorian conversion algorithms of `time.Time`, the resultant period is precise.
To improve precision, result is not always fully normalised; for time differences less than 3276 hours (about 4.5 months), it will contain zero in the years, months and days fields but the number of hours may be up to 3275; this reduces errors arising from the variable lengths of months. For larger time differences (greater than 3276 hours) the days, 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 MustParse ¶
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. By default, the value is normalised. Normalisation can be disabled using the optional flag.
func New ¶
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 NewHMS ¶
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). Because this implementation uses int16 internally, the paramters must be within the range ± 2^16 / 10.
func NewOf ¶
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, 365.2425 days per year (as per Gregorian calendar rules), and a month being 1/12 of that (approximately 30.4369 days).
The result is not always fully normalised; for time differences less than 3276 hours (about 4.5 months), it will contain zero in the years, months and days 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 hours, the days, months and years fields are used as well.
func NewYMD ¶
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). Because this implementation uses int16 internally, the paramters must be within the range ± 2^16 / 10.
func Parse ¶
Parse parses strings that specify periods using ISO-8601 rules.
In addition, a plus or minus sign can precede the period, e.g. "-P10D"
By default, 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.
Normalisation can be disabled using the optional flag.
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 ParseWithNormalise ¶ added in v1.13.0
ParseWithNormalise parses strings that specify periods using ISO-8601 rules with an option to specify whether to normalise parsed period components.
This method is deprecated and should not be used. It may be removed in a future version.
func (Period) Add ¶
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) AddTo ¶ added in v1.8.0
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, as per Gregorian calendar rules).
func (Period) Days ¶
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) 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) Duration ¶
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 as per Gregorian calendar rules) and a month being 1/12 of a that; days are all assumed to be 24 hours long.
func (Period) DurationApprox ¶ added in v1.4.0
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 (as per Gregorian calendar rules) and a month being 1/12 of a that; days are all assumed to be 24 hours long.
func (Period) Format ¶
Format converts the period to human-readable form using the default localisation. Multiples of 7 days are shown as weeks.
func (Period) FormatWithPeriodNames ¶
func (period Period) FormatWithPeriodNames(yearNames, monthNames, weekNames, dayNames, hourNames, minNames, secNames plural.Plurals) string
FormatWithPeriodNames converts the period to human-readable form in a localisable way.
func (Period) FormatWithoutWeeks ¶ added in v1.14.0
FormatWithoutWeeks converts the period to human-readable form using the default localisation. Multiples of 7 days are not shown as weeks.
func (Period) Hours ¶
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) 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) IsNegative ¶
IsNegative returns true if any field is negative. By design, this also implies that all the other fields are negative or zero.
func (Period) IsPositive ¶ added in v1.8.0
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) MarshalBinary ¶
MarshalBinary implements the encoding.BinaryMarshaler interface. This also provides support for gob encoding.
func (Period) MarshalText ¶
MarshalText implements the encoding.TextMarshaler interface for Periods. This also provides support for JSON encoding.
func (Period) Minutes ¶
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) 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) ModuloDays ¶
ModuloDays calculates the whole number of days remaining after the whole number of weeks has been excluded.
func (Period) Months ¶
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) 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) Normalise ¶
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 to or from the days element, or to transfer days to or from the months 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) OnlyHMS ¶
OnlyHMS returns a new Period with only the hour, minute and second fields. The year, month and day fields are zeroed.
func (Period) OnlyYMD ¶
OnlyYMD returns a new Period with only the year, month and day fields. The hour, minute and second fields are zeroed.
func (Period) Scale ¶
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, but integer overflows are silently ignored.
Bear in mind that the internal representation is limited by fixed-point arithmetic with two decimal places; 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) ScaleWithOverflowCheck ¶ added in v1.14.0
ScaleWithOverflowCheck a period by a multiplication factor. Obviously, this can both enlarge and shrink it, and change the sign if negative. The result is normalised. An error is returned if integer overflow happened.
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) Scan ¶ added in v1.15.0
Scan parses some value, which can be either string or []byte. It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner
func (Period) Seconds ¶
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) 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) Sign ¶
Sign returns +1 for positive periods and -1 for negative periods. If the period is zero, it returns zero.
func (Period) Simplify ¶ added in v1.14.0
Simplify applies some heuristic simplifications with the objective of reducing the number of non-zero fields and thus making the rendered form simpler. It should be applied to a normalised period, otherwise the results may be unpredictable.
Note that months and days are never combined, due to the variability of month lengths. Days and hours are only combined when imprecise behaviour is selected; this is due to daylight savings transitions, during which there are more than or fewer than 24 hours per day.
The following transformation rules are applied in order:
* P1YnM becomes 12+n months for 0 < n <= 6 * P1DTnH becomes 24+n hours for 0 < n <= 6 (unless precise is true) * PT1HnM becomes 60+n minutes for 0 < n <= 10 * PT1MnS becomes 60+n seconds for 0 < n <= 10
At each step, if a fraction exists and would affect the calculation, the transformations stop. Also, when not precise,
* for periods of at least ten years, month proper fractions are discarded * for periods of at least a year, day proper fractions are discarded * for periods of at least a month, hour proper fractions are discarded * for periods of at least a day, minute proper fractions are discarded * for periods of at least an hour, second proper fractions are discarded
The thresholds can be set using the varargs th parameter. By default, the thresholds a, b, c, d are 6 months, 6 hours, 10 minutes, 10 seconds respectively as listed in the rules above.
* No thresholds is equivalent to 6, 6, 10, 10. * A single threshold a is equivalent to a, a, a, a. * Two thresholds a, b are equivalent to a, a, b, b. * Three thresholds a, b, c are equivalent to a, b, c, c. * Four thresholds a, b, c, d are used as provided.
func (Period) TotalDaysApprox ¶
TotalDaysApprox gets the approximate total number of days in the period. The approximation assumes a year is 365.2425 days as per Gregorian calendar rules) and a month is 1/12 of that. Whole multiples of 24 hours are also included in the calculation.
func (Period) TotalMonthsApprox ¶
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 (as per Gregorian calendar rules) and a month is 1/12 of that. Whole multiples of 24 hours are also included in the calculation.
func (*Period) UnmarshalBinary ¶
UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. This also provides support for gob decoding.
func (*Period) UnmarshalText ¶
UnmarshalText implements the encoding.TextUnmarshaler interface for Periods. This also provides support for JSON decoding.
func (Period) Value ¶ added in v1.15.0
Value converts the period to a string. It implements driver.Valuer, https://golang.org/pkg/database/sql/driver/#Valuer
func (Period) Weeks ¶
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) WeeksFloat ¶ added in v1.4.0
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) Years ¶
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) 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.