diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libgo/go/time/format.go | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libgo/go/time/format.go')
-rw-r--r-- | libgo/go/time/format.go | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go new file mode 100644 index 000000000..7b5a8f3b6 --- /dev/null +++ b/libgo/go/time/format.go @@ -0,0 +1,618 @@ +package time + +import ( + "bytes" + "os" + "strconv" +) + +const ( + numeric = iota + alphabetic + separator + plus + minus +) + +// These are predefined layouts for use in Time.Format. +// The standard time used in the layouts is: +// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700) +// which is Unix time 1136243045. +// (Think of it as 01/02 03:04:05PM '06 -0700.) +// To define your own format, write down what the standard +// time would look like formatted your way. +// +// Within the format string, an underscore _ represents a space that may be +// replaced by a digit if the following number (a day) has two digits; for +// compatibility with fixed-width Unix time formats. +// +// Numeric time zone offsets format as follows: +// -0700 ±hhmm +// -07:00 ±hh:mm +// Replacing the sign in the format with a Z triggers +// the ISO 8601 behavior of printing Z instead of an +// offset for the UTC zone. Thus: +// Z0700 Z or ±hhmm +// Z07:00 Z or ±hh:mm +const ( + ANSIC = "Mon Jan _2 15:04:05 2006" + UnixDate = "Mon Jan _2 15:04:05 MST 2006" + RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + RFC822 = "02 Jan 06 1504 MST" + // RFC822 with Zulu time. + RFC822Z = "02 Jan 06 1504 -0700" + RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" + RFC3339 = "2006-01-02T15:04:05Z07:00" + Kitchen = "3:04PM" +) + +const ( + stdLongMonth = "January" + stdMonth = "Jan" + stdNumMonth = "1" + stdZeroMonth = "01" + stdLongWeekDay = "Monday" + stdWeekDay = "Mon" + stdDay = "2" + stdUnderDay = "_2" + stdZeroDay = "02" + stdHour = "15" + stdHour12 = "3" + stdZeroHour12 = "03" + stdMinute = "4" + stdZeroMinute = "04" + stdSecond = "5" + stdZeroSecond = "05" + stdLongYear = "2006" + stdYear = "06" + stdPM = "PM" + stdpm = "pm" + stdTZ = "MST" + stdISO8601TZ = "Z0700" // prints Z for UTC + stdISO8601ColonTZ = "Z07:00" // prints Z for UTC + stdNumTZ = "-0700" // always numeric + stdNumShortTZ = "-07" // always numeric + stdNumColonTZ = "-07:00" // always numeric +) + +// nextStdChunk finds the first occurrence of a std string in +// layout and returns the text before, the std string, and the text after. +func nextStdChunk(layout string) (prefix, std, suffix string) { + for i := 0; i < len(layout); i++ { + switch layout[i] { + case 'J': // January, Jan + if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth { + return layout[0:i], stdLongMonth, layout[i+7:] + } + if len(layout) >= i+3 && layout[i:i+3] == stdMonth { + return layout[0:i], stdMonth, layout[i+3:] + } + + case 'M': // Monday, Mon, MST + if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay { + return layout[0:i], stdLongWeekDay, layout[i+6:] + } + if len(layout) >= i+3 { + if layout[i:i+3] == stdWeekDay { + return layout[0:i], stdWeekDay, layout[i+3:] + } + if layout[i:i+3] == stdTZ { + return layout[0:i], stdTZ, layout[i+3:] + } + } + + case '0': // 01, 02, 03, 04, 05, 06 + if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { + return layout[0:i], layout[i : i+2], layout[i+2:] + } + + case '1': // 15, 1 + if len(layout) >= i+2 && layout[i+1] == '5' { + return layout[0:i], stdHour, layout[i+2:] + } + return layout[0:i], stdNumMonth, layout[i+1:] + + case '2': // 2006, 2 + if len(layout) >= i+4 && layout[i:i+4] == stdLongYear { + return layout[0:i], stdLongYear, layout[i+4:] + } + return layout[0:i], stdDay, layout[i+1:] + + case '_': // _2 + if len(layout) >= i+2 && layout[i+1] == '2' { + return layout[0:i], stdUnderDay, layout[i+2:] + } + + case '3', '4', '5': // 3, 4, 5 + return layout[0:i], layout[i : i+1], layout[i+1:] + + case 'P': // PM + if len(layout) >= i+2 && layout[i+1] == 'M' { + return layout[0:i], layout[i : i+2], layout[i+2:] + } + + case 'p': // pm + if len(layout) >= i+2 && layout[i+1] == 'm' { + return layout[0:i], layout[i : i+2], layout[i+2:] + } + + case '-': // -0700, -07:00, -07 + if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ { + return layout[0:i], layout[i : i+5], layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ { + return layout[0:i], layout[i : i+6], layout[i+6:] + } + if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ { + return layout[0:i], layout[i : i+3], layout[i+3:] + } + case 'Z': // Z0700, Z07:00 + if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ { + return layout[0:i], layout[i : i+5], layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ { + return layout[0:i], layout[i : i+6], layout[i+6:] + } + } + } + return layout, "", "" +} + +var longDayNames = []string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +} + +var shortDayNames = []string{ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +} + +var shortMonthNames = []string{ + "---", + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +} + +var longMonthNames = []string{ + "---", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +} + +func lookup(tab []string, val string) (int, string, os.Error) { + for i, v := range tab { + if len(val) >= len(v) && val[0:len(v)] == v { + return i, val[len(v):], nil + } + } + return -1, val, errBad +} + +func pad(i int, padding string) string { + s := strconv.Itoa(i) + if i < 10 { + s = padding + s + } + return s +} + +func zeroPad(i int) string { return pad(i, "0") } + +// Format returns a textual representation of the time value formatted +// according to layout. The layout defines the format by showing the +// representation of a standard time, which is then used to describe +// the time to be formatted. Predefined layouts ANSIC, UnixDate, +// RFC3339 and others describe standard representations. For more +// information about the formats, see the documentation for ANSIC. +func (t *Time) Format(layout string) string { + b := new(bytes.Buffer) + // Each iteration generates one std value. + for { + prefix, std, suffix := nextStdChunk(layout) + b.WriteString(prefix) + if std == "" { + break + } + var p string + switch std { + case stdYear: + p = strconv.Itoa64(t.Year % 100) + case stdLongYear: + p = strconv.Itoa64(t.Year) + case stdMonth: + p = shortMonthNames[t.Month] + case stdLongMonth: + p = longMonthNames[t.Month] + case stdNumMonth: + p = strconv.Itoa(t.Month) + case stdZeroMonth: + p = zeroPad(t.Month) + case stdWeekDay: + p = shortDayNames[t.Weekday] + case stdLongWeekDay: + p = longDayNames[t.Weekday] + case stdDay: + p = strconv.Itoa(t.Day) + case stdUnderDay: + p = pad(t.Day, " ") + case stdZeroDay: + p = zeroPad(t.Day) + case stdHour: + p = zeroPad(t.Hour) + case stdHour12: + p = strconv.Itoa(t.Hour % 12) + case stdZeroHour12: + p = zeroPad(t.Hour % 12) + case stdMinute: + p = strconv.Itoa(t.Minute) + case stdZeroMinute: + p = zeroPad(t.Minute) + case stdSecond: + p = strconv.Itoa(t.Second) + case stdZeroSecond: + p = zeroPad(t.Second) + case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ: + // Ugly special case. We cheat and take the "Z" variants + // to mean "the time zone as formatted for ISO 8601". + if t.ZoneOffset == 0 && std[0] == 'Z' { + p = "Z" + break + } + zone := t.ZoneOffset / 60 // convert to minutes + if zone < 0 { + p = "-" + zone = -zone + } else { + p = "+" + } + p += zeroPad(zone / 60) + if std == stdISO8601ColonTZ || std == stdNumColonTZ { + p += ":" + } + p += zeroPad(zone % 60) + case stdPM: + if t.Hour >= 12 { + p = "PM" + } else { + p = "AM" + } + case stdpm: + if t.Hour >= 12 { + p = "pm" + } else { + p = "am" + } + case stdTZ: + if t.Zone != "" { + p = t.Zone + } else { + // No time zone known for this time, but we must print one. + // Use the -0700 format. + zone := t.ZoneOffset / 60 // convert to minutes + if zone < 0 { + p = "-" + zone = -zone + } else { + p = "+" + } + p += zeroPad(zone / 60) + p += zeroPad(zone % 60) + } + } + b.WriteString(p) + layout = suffix + } + return b.String() +} + +// String returns a Unix-style representation of the time value. +func (t *Time) String() string { + if t == nil { + return "<nil>" + } + return t.Format(UnixDate) +} + +var errBad = os.ErrorString("bad") // just a marker; not returned to user + +// ParseError describes a problem parsing a time string. +type ParseError struct { + Layout string + Value string + LayoutElem string + ValueElem string + Message string +} + +// String is the string representation of a ParseError. +func (e *ParseError) String() string { + if e.Message == "" { + return "parsing time " + + strconv.Quote(e.Value) + " as " + + strconv.Quote(e.Layout) + ": cannot parse " + + strconv.Quote(e.ValueElem) + " as " + + strconv.Quote(e.LayoutElem) + } + return "parsing time " + + strconv.Quote(e.Value) + e.Message +} + +// getnum parses s[0:1] or s[0:2] (fixed forces the latter) +// as a decimal integer and returns the integer and the +// remainder of the string. +func getnum(s string, fixed bool) (int, string, os.Error) { + if len(s) == 0 || s[0] < '0' || s[0] > '9' { + return 0, s, errBad + } + if len(s) == 1 || s[1] < '0' || s[1] > '9' { + if fixed { + return 0, s, errBad + } + return int(s[0] - '0'), s[1:], nil + } + return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil +} + +func cutspace(s string) string { + for len(s) > 0 && s[0] == ' ' { + s = s[1:] + } + return s +} + +// skip removes the given prefix from value, +// treating runs of space characters as equivalent. +func skip(value, prefix string) (string, os.Error) { + for len(prefix) > 0 { + if prefix[0] == ' ' { + if len(value) > 0 && value[0] != ' ' { + return "", errBad + } + prefix = cutspace(prefix) + value = cutspace(value) + continue + } + if len(value) == 0 || value[0] != prefix[0] { + return "", errBad + } + prefix = prefix[1:] + value = value[1:] + } + return value, nil +} + +// Parse parses a formatted string and returns the time value it represents. +// The layout defines the format by showing the representation of a standard +// time, which is then used to describe the string to be parsed. Predefined +// layouts ANSIC, UnixDate, RFC3339 and others describe standard +// representations.For more information about the formats, see the +// documentation for ANSIC. +// +// Only those elements present in the value will be set in the returned time +// structure. Also, if the input string represents an inconsistent time +// (such as having the wrong day of the week), the returned value will also +// be inconsistent. In any case, the elements of the returned time will be +// sane: hours in 0..23, minutes in 0..59, day of month in 0..31, etc. +// Years must be in the range 0000..9999. +func Parse(alayout, avalue string) (*Time, os.Error) { + var t Time + rangeErrString := "" // set if a value is out of range + pmSet := false // do we need to add 12 to the hour? + layout, value := alayout, avalue + // Each iteration processes one std value. + for { + var err os.Error + prefix, std, suffix := nextStdChunk(layout) + value, err = skip(value, prefix) + if err != nil { + return nil, &ParseError{alayout, avalue, prefix, value, ""} + } + if len(std) == 0 { + if len(value) != 0 { + return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value} + } + break + } + layout = suffix + var p string + switch std { + case stdYear: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + t.Year, err = strconv.Atoi64(p) + if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones + t.Year += 1900 + } else { + t.Year += 2000 + } + case stdLongYear: + if len(value) < 4 || value[0] < '0' || value[0] > '9' { + err = errBad + break + } + p, value = value[0:4], value[4:] + t.Year, err = strconv.Atoi64(p) + case stdMonth: + t.Month, value, err = lookup(shortMonthNames, value) + case stdLongMonth: + t.Month, value, err = lookup(longMonthNames, value) + case stdNumMonth, stdZeroMonth: + t.Month, value, err = getnum(value, std == stdZeroMonth) + if t.Month <= 0 || 12 < t.Month { + rangeErrString = "month" + } + case stdWeekDay: + t.Weekday, value, err = lookup(shortDayNames, value) + case stdLongWeekDay: + t.Weekday, value, err = lookup(longDayNames, value) + case stdDay, stdUnderDay, stdZeroDay: + if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + t.Day, value, err = getnum(value, std == stdZeroDay) + if t.Day < 0 || 31 < t.Day { + // TODO: be more thorough in date check? + rangeErrString = "day" + } + case stdHour: + t.Hour, value, err = getnum(value, false) + if t.Hour < 0 || 24 <= t.Hour { + rangeErrString = "hour" + } + case stdHour12, stdZeroHour12: + t.Hour, value, err = getnum(value, std == stdZeroHour12) + if t.Hour < 0 || 12 < t.Hour { + rangeErrString = "hour" + } + case stdMinute, stdZeroMinute: + t.Minute, value, err = getnum(value, std == stdZeroMinute) + if t.Minute < 0 || 60 <= t.Minute { + rangeErrString = "minute" + } + case stdSecond, stdZeroSecond: + t.Second, value, err = getnum(value, std == stdZeroSecond) + if t.Second < 0 || 60 <= t.Second { + rangeErrString = "second" + } + case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ: + if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' { + value = value[1:] + t.Zone = "UTC" + break + } + var sign, hh, mm string + if std == stdISO8601ColonTZ || std == stdNumColonTZ { + if len(value) < 6 { + err = errBad + break + } + if value[3] != ':' { + err = errBad + break + } + sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:] + } else if std == stdNumShortTZ { + if len(value) < 3 { + err = errBad + break + } + sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:] + } else { + if len(value) < 5 { + err = errBad + break + } + sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:] + } + var hr, min int + hr, err = strconv.Atoi(hh) + if err == nil { + min, err = strconv.Atoi(mm) + } + t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds + switch sign[0] { + case '+': + case '-': + t.ZoneOffset = -t.ZoneOffset + default: + err = errBad + } + case stdPM: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + if p == "PM" { + pmSet = true + } else if p != "AM" { + err = errBad + } + case stdpm: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + if p == "pm" { + pmSet = true + } else if p != "am" { + err = errBad + } + case stdTZ: + // Does it look like a time zone? + if len(value) >= 3 && value[0:3] == "UTC" { + t.Zone, value = value[0:3], value[3:] + break + } + + if len(value) >= 3 && value[2] == 'T' { + p, value = value[0:3], value[3:] + } else if len(value) >= 4 && value[3] == 'T' { + p, value = value[0:4], value[4:] + } else { + err = errBad + break + } + for i := 0; i < len(p); i++ { + if p[i] < 'A' || 'Z' < p[i] { + err = errBad + } + } + if err != nil { + break + } + // It's a valid format. + t.Zone = p + // Can we find its offset? + if offset, found := lookupByName(p); found { + t.ZoneOffset = offset + } + } + if rangeErrString != "" { + return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"} + } + if err != nil { + return nil, &ParseError{alayout, avalue, std, value, ""} + } + } + if pmSet && t.Hour < 12 { + t.Hour += 12 + } + return &t, nil +} |