Documentation ¶
Overview ¶
Package fuzzytime helps with the parsing and representation of dates and times.
Fuzzytime defines types (Date, Time, DateTime) which have optional fields. So you can represent a date with a year and month, but no day.
A quick parsing example:
package main import ( "fmt" "github.com/bcampbell/fuzzytime" ) func main() { inputs := []string{ "Wed Apr 16 17:32:51 NZST 2014", "2010-02-01T13:14:43Z", // an iso 8601 form "no date or time info here", "Published on March 10th, 1999 by Brian Credability", "2:51pm", "April 2004", } for _, s := range inputs { dt, _, _ := fuzzytime.Extract(s) fmt.Println(dt.ISOFormat()) } }
This should output:
2014-04-16T17:32:51+12:00 2010-02-01T13:14:43Z 1999-03-10 T14:51 2004-04
Timezones, once resolved, are stored as an offset from UTC (in seconds).
Sometimes dates and times are ambiguous and can't be parsed without extra information (eg "dd/mm/yy" vs "mm/dd/yy"). The default behaviour when such a data is encountered is for Extract() function to just return an error. This can be overriden by using a Context struct, which provides functions to perform the decisions required in otherwise-ambiguous cases.
Index ¶
- Variables
- func DefaultTZResolver(preferredLocales string) func(name string) (int, error)
- func ExtendYear(year int) int
- func Extract(s string) (DateTime, []Span, error)
- func ExtractDate(s string) (Date, Span, error)
- func ExtractTime(s string) (Time, Span, error)
- func OffsetToTZ(secs int) string
- func TZToOffset(s string) (int, error)
- type Context
- type Date
- func (d *Date) Conflicts(other *Date) bool
- func (d *Date) Day() int
- func (d *Date) Empty() bool
- func (d *Date) Equals(other *Date) bool
- func (d *Date) HasDay() bool
- func (d *Date) HasMonth() bool
- func (d *Date) HasYear() bool
- func (d *Date) ISOFormat() string
- func (d *Date) Merge(other *Date)
- func (d *Date) Month() int
- func (d *Date) SetDay(day int)
- func (d *Date) SetMonth(month int)
- func (d *Date) SetYear(year int)
- func (d *Date) String() string
- func (d *Date) Year() int
- type DateTime
- type Span
- type TZInfo
- type Time
- func (t *Time) Conflicts(other *Time) bool
- func (t *Time) Empty() bool
- func (t *Time) Equals(other *Time) bool
- func (t *Time) Fractional() int
- func (t *Time) HasFractional() bool
- func (t *Time) HasHour() bool
- func (t *Time) HasMinute() bool
- func (t *Time) HasSecond() bool
- func (t *Time) HasTZOffset() bool
- func (t *Time) Hour() int
- func (t *Time) ISOFormat() string
- func (t *Time) Minute() int
- func (t *Time) Second() int
- func (t *Time) SetFractional(fractional int)
- func (t *Time) SetHour(hour int)
- func (t *Time) SetMinute(minute int)
- func (t *Time) SetSecond(second int)
- func (t *Time) SetTZOffset(tzOffset int)
- func (t *Time) String() string
- func (t *Time) TZOffset() int
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultContext = Context{ DateResolver: func(a, b, c int) (Date, error) { return Date{}, errors.New("ambiguous date") }, TZResolver: DefaultTZResolver(""), }
DefaultContext is a predefined context which bails out if timezones or dates are ambiguous. It makes no attempt to resolve them.
var USContext = Context{ DateResolver: MDYResolver, TZResolver: DefaultTZResolver("US"), }
USContext is a prefefined Context which opts for US timezones and mm/dd/yy dates
var WesternContext = Context{ DateResolver: DMYResolver, TZResolver: DefaultTZResolver("GB,US"), }
WesternContext is a predefined Context which opts for UK and US timezones and dd/mm/yy dates
Functions ¶
func DefaultTZResolver ¶
DefaultTZResolver returns a TZResolver function which uses a list of country codes in preferredLocales to resolve ambigous timezones. For example, if you were expecting Bangladeshi times, then:
DefaultTZResolver("BD")
would treat "BST" as Bangladesh Standard Time rather than British Summer Time
func ExtendYear ¶
ExtendYear extends 2-digit years into 4 digits. the rules used: 00-69 => 2000-2069 70-99 => 1970-1999
func Extract ¶
Extract tries to parse a Date and Time from a string. If none found, the returned DateTime will be empty Equivalent to DefaultContext.Extract()
Example ¶
inputs := []string{ "Wed Apr 16 17:32:51 NZST 2014", "2010-02-01T13:14:43Z", // an iso 8601 form "no date or time info here", "Published on March 10th, 1999 by Brian Credability", "2:51pm", } for _, inp := range inputs { dt, spans, err := Extract(inp) if err != nil { panic(fmt.Errorf("Extract(%s) error: %s", inp, err)) } fmt.Println(dt.ISOFormat(), spans) }
Output: 2014-04-16T17:32:51+12:00 [{0 29}] 2010-02-01T13:14:43Z [{0 20}] [] 1999-03-10 [{13 29}] T14:51 [{0 6}]
func ExtractDate ¶
ExtractDate tries to parse a Date from a string. Equivalent to DefaultContext.ExtractDate() Returns the parsed date information and a span showing which portion of the text matched, or an error.
func ExtractTime ¶
ExtractTime tries to parse a Time from a string. Equivalent to DefaultContext.ExtractTime() Returns the parsed time information and a span showing which portion of the text matched, or an error.
func OffsetToTZ ¶
OffsetToTZ converts an offset in seconds from UTC into an ISO8601-style offset (like "+HH:MM")
func TZToOffset ¶
TZToOffset parses an ISO8601 timezone offset ("Z", "[+-]HH" "[+-]HH[:]?MM" etc...) and returns the offset from UTC in seconds
Types ¶
type Context ¶
type Context struct { // DateResolver is called when ambigous dates are encountered eg (10/11/12) // It should return a date, if one can be decided. Returning an error // indicates the resolver can't decide. DateResolver func(a, b, c int) (Date, error) // TZResolver returns the offset in seconds from UTC of the named zone (eg "EST"). // if the resolver can't decide which timezone it is, it will return an error. TZResolver func(name string) (int, error) }
Context provides helper functions to resolve ambiguous dates and timezones. For example, "CST" can mean China Standard Time, Central Standard Time in or Central Standard Time in Australia. Or, the date "5/2/10". It could Feburary 5th, 2010 or May 2nd 2010. Or even Feb 10th 2005, depending on country. Even "05/02/2010" is ambiguous. If you know something about the types of times and dates you're likely to encounter, you can provide a Context struct to guide the parsing.
Example ¶
inputs := []string{ "01/02/03", "12/23/99", "10:25CST", } // USA context: fmt.Println("in USA:") for _, inp := range inputs { dt, _, _ := USContext.Extract(inp) fmt.Println(dt.ISOFormat()) } // custom context for Australia: aussie := Context{ DateResolver: DMYResolver, TZResolver: DefaultTZResolver("AU"), } fmt.Println("in Australia:") for _, inp := range inputs { dt, _, _ := aussie.Extract(inp) fmt.Println(dt.ISOFormat()) }
Output: in USA: 2003-01-02 1999-12-23 T10:25-06:00 in Australia: 2003-02-01 T10:25+09:30
func (*Context) Extract ¶
Extract tries to parse a Date and Time from a string It also returns a sorted list of spans specifing which bits of the string were used. If none found (or if there is an error), the returned DateTime will be empty.
func (*Context) ExtractDate ¶
ExtractDate tries to parse a date from a string. It returns a Date and Span indicating which part of string matched. If an error occurs, an empty Date will be returned.
func (*Context) ExtractTime ¶
ExtractTime tries to parse a time from a string. It returns a Time and a Span indicating which part of string matched. Time and Span may be empty, indicating no time was found. An error will be returned if a time is found but cannot be correctly parsed. If error is not nil time the returned time and span will both be empty
type Date ¶
type Date struct {
// contains filtered or unexported fields
}
A Date represents a year/month/day set where any of the three may be unset. default initialisation (ie Date{}) is a valid but empty Date.
func DMYResolver ¶
DMYResolver is a helper function for Contexts which treats ambiguous dates as DD/MM/YY
func MDYResolver ¶
MDYResolver is a helper function for Contexts which treats ambiguous dates as MM/DD/YY
func (*Date) Conflicts ¶
Conflicts returns true if date d conflicts with the other date. Missing fields are not considered so, for example "2013-01-05" doesn't conflict with "2013-01"
func (*Date) Equals ¶
Equals returns true if dates match. Fields present in one date but not the other are considered mismatches.
func (*Date) ISOFormat ¶
ISOFormat returns "YYYY-MM-DD", "YYYY-MM" or "YYYY" depending on which fields are available (or "" if year is missing).
func (*Date) Merge ¶
Merge copies all fields set in other into d. any fields unset in other are left unchanged in d.
type DateTime ¶
DateTime represents a set of fields for date and time, any of which may be unset. The default initialisation is a valid empty datetime with no fields set.
func (*DateTime) Conflicts ¶
Conflicts returns true if the two datetimes conflict. Note that this is not the same as the two being equal - one datetime can be more precise than the other. They are only in conflict if they have different values set for the same field. eg "2012-01-01T03:34:10" doesn't conflict with "03:34"
func (*DateTime) HasFullDate ¶
HasFullDate returns true if Year, Month and Day are all set
type Span ¶
Span represents the range [Begin,End), used to indicate the part of a string from which time or date information was parsed.
type TZInfo ¶
type TZInfo struct { // Name of the timezone eg "BST", "UTC", "NZDT" Name string // Offset from UTC, in ISO8601 form [+-]<HH>[:<MM>] Offset string // Locale contains comma-separated country identifiers // to help resolve ambiguities Locale string }
TZInfo holds info about a timezone offset
func FindTimeZone ¶
FindTimeZone returns timezones with the matching name (eg "BST") Some timezone names are ambiguous (eg "BST"), so all the matching ones will be returned. It's up to the caller to disambiguate them. To aid in this, ambiguous timezones include a list of country locale codes ("US", "AU" etc) in where they are used.
type Time ¶
type Time struct {
// contains filtered or unexported fields
}
Time represents a set of time fields, any of which may be unset. The default initialisation (ie Time{}) produces a Time with all fields unset.
func (*Time) Conflicts ¶
Conflicts returns true if time t conflicts with the other time. Missing fields are not considered so, for example "10:59:01" doesn't conflict with "10:59"
func (*Time) Equals ¶
Equals returns true if the two times have the same fields set and match exactly. Fields present in one time but not the other are considered mismatches.
func (*Time) Fractional ¶
Fractional returns the second (result undefined if field unset)
func (*Time) HasFractional ¶
HasFractional returns true if fraction second is set
func (*Time) HasTZOffset ¶
HasTZOffset returns true if the timezone offset field is set
func (*Time) SetFractional ¶
SetFractional sets the Fractional Second field (0-999)
func (*Time) SetTZOffset ¶
SetTZOffset sets the timezone offset from UTC, in seconds