Marcel van Lohuizen | 8090639 | 2019-08-06 13:04:16 +0200 | [diff] [blame] | 1 | // Copyright 2019 CUE Authors |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // Package time defines time-related types. |
| 16 | package time |
| 17 | |
| 18 | import ( |
| 19 | "fmt" |
| 20 | "time" |
| 21 | ) |
| 22 | |
| 23 | // These are predefined layouts for use in Time.Format and time.Parse. |
| 24 | // The reference time used in the layouts is the specific time: |
| 25 | // Mon Jan 2 15:04:05 MST 2006 |
| 26 | // which is Unix time 1136239445. Since MST is GMT-0700, |
| 27 | // the reference time can be thought of as |
| 28 | // 01/02 03:04:05PM '06 -0700 |
| 29 | // To define your own format, write down what the reference time would look |
| 30 | // like formatted your way; see the values of constants like ANSIC, |
| 31 | // StampMicro or Kitchen for examples. The model is to demonstrate what the |
| 32 | // reference time looks like so that the Format and Parse methods can apply |
| 33 | // the same transformation to a general time value. |
| 34 | // |
| 35 | // Some valid layouts are invalid time values for time.Parse, due to formats |
| 36 | // such as _ for space padding and Z for zone information. |
| 37 | // |
| 38 | // Within the format string, an underscore _ represents a space that may be |
| 39 | // replaced by a digit if the following number (a day) has two digits; for |
| 40 | // compatibility with fixed-width Unix time formats. |
| 41 | // |
| 42 | // A decimal point followed by one or more zeros represents a fractional |
| 43 | // second, printed to the given number of decimal places. A decimal point |
| 44 | // followed by one or more nines represents a fractional second, printed to |
| 45 | // the given number of decimal places, with trailing zeros removed. |
| 46 | // When parsing (only), the input may contain a fractional second |
| 47 | // field immediately after the seconds field, even if the layout does not |
| 48 | // signify its presence. In that case a decimal point followed by a maximal |
| 49 | // series of digits is parsed as a fractional second. |
| 50 | // |
| 51 | // Numeric time zone offsets format as follows: |
| 52 | // -0700 ±hhmm |
| 53 | // -07:00 ±hh:mm |
| 54 | // -07 ±hh |
| 55 | // Replacing the sign in the format with a Z triggers |
| 56 | // the ISO 8601 behavior of printing Z instead of an |
| 57 | // offset for the UTC zone. Thus: |
| 58 | // Z0700 Z or ±hhmm |
| 59 | // Z07:00 Z or ±hh:mm |
| 60 | // Z07 Z or ±hh |
| 61 | // |
| 62 | // The recognized day of week formats are "Mon" and "Monday". |
| 63 | // The recognized month formats are "Jan" and "January". |
| 64 | // |
| 65 | // Text in the format string that is not recognized as part of the reference |
| 66 | // time is echoed verbatim during Format and expected to appear verbatim |
| 67 | // in the input to Parse. |
| 68 | // |
| 69 | // The executable example for Time.Format demonstrates the working |
| 70 | // of the layout string in detail and is a good reference. |
| 71 | // |
| 72 | // Note that the RFC822, RFC850, and RFC1123 formats should be applied |
| 73 | // only to local times. Applying them to UTC times will use "UTC" as the |
| 74 | // time zone abbreviation, while strictly speaking those RFCs require the |
| 75 | // use of "GMT" in that case. |
| 76 | // In general RFC1123Z should be used instead of RFC1123 for servers |
| 77 | // that insist on that format, and RFC3339 should be preferred for new protocols. |
| 78 | // RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; |
| 79 | // when used with time.Parse they do not accept all the time formats |
| 80 | // permitted by the RFCs. |
| 81 | // The RFC3339Nano format removes trailing zeros from the seconds field |
| 82 | // and thus may not sort correctly once formatted. |
| 83 | const ( |
| 84 | ANSIC = "Mon Jan _2 15:04:05 2006" |
| 85 | UnixDate = "Mon Jan _2 15:04:05 MST 2006" |
| 86 | RubyDate = "Mon Jan 02 15:04:05 -0700 2006" |
| 87 | RFC822 = "02 Jan 06 15:04 MST" |
| 88 | RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone |
| 89 | RFC850 = "Monday, 02-Jan-06 15:04:05 MST" |
| 90 | RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" |
| 91 | RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone |
| 92 | RFC3339 = "2006-01-02T15:04:05Z07:00" |
| 93 | RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" |
| 94 | RFC3339Date = "2006-01-02" |
| 95 | Kitchen = "3:04PM" |
| 96 | Kitchen24 = "15:04" |
| 97 | ) |
| 98 | |
| 99 | const ( |
| 100 | January = 1 |
| 101 | February = 2 |
| 102 | March = 3 |
| 103 | April = 4 |
| 104 | May = 5 |
| 105 | June = 6 |
| 106 | July = 7 |
| 107 | August = 8 |
| 108 | September = 9 |
| 109 | October = 10 |
| 110 | November = 11 |
| 111 | December = 12 |
| 112 | ) |
| 113 | |
| 114 | const ( |
| 115 | Sunday = 0 |
| 116 | Monday = 1 |
| 117 | Tuesday = 2 |
| 118 | Wednesday = 3 |
| 119 | Thursday = 4 |
| 120 | Friday = 5 |
| 121 | Saturday = 6 |
| 122 | ) |
| 123 | |
| 124 | // Time validates a RFC3339 date-time. |
| 125 | // |
| 126 | // Caveat: this implementation uses the Go implementation, which does not |
| 127 | // accept leap seconds. |
| 128 | func Time(s string) (bool, error) { |
| 129 | return timeFormat(s, time.RFC3339Nano) |
| 130 | } |
| 131 | |
| 132 | func timeFormat(value, layout string) (bool, error) { |
| 133 | _, err := time.Parse(layout, value) |
| 134 | if err != nil { |
| 135 | // Use our own error, the time package's error as the Go error is too |
| 136 | // confusing within this context. |
| 137 | return false, fmt.Errorf("invalid time %q", value) |
| 138 | } |
| 139 | return true, nil |
| 140 | } |
| 141 | |
| 142 | // Format defines a type string that must adhere to a certain layout. |
| 143 | // |
| 144 | // See Parse for a description on layout strings. |
| 145 | func Format(value, layout string) (bool, error) { |
| 146 | return timeFormat(value, layout) |
| 147 | } |
| 148 | |
| 149 | // Parse parses a formatted string and returns the time value it represents. |
| 150 | // The layout defines the format by showing how the reference time, |
| 151 | // defined to be |
| 152 | // Mon Jan 2 15:04:05 -0700 MST 2006 |
| 153 | // would be interpreted if it were the value; it serves as an example of |
| 154 | // the input format. The same interpretation will then be made to the |
| 155 | // input string. |
| 156 | // |
| 157 | // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard |
| 158 | // and convenient representations of the reference time. For more information |
| 159 | // about the formats and the definition of the reference time, see the |
| 160 | // documentation for ANSIC and the other constants defined by this package. |
| 161 | // Also, the executable example for Time.Format demonstrates the working |
| 162 | // of the layout string in detail and is a good reference. |
| 163 | // |
| 164 | // Elements omitted from the value are assumed to be zero or, when |
| 165 | // zero is impossible, one, so parsing "3:04pm" returns the time |
| 166 | // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is |
| 167 | // 0, this time is before the zero Time). |
| 168 | // Years must be in the range 0000..9999. The day of the week is checked |
| 169 | // for syntax but it is otherwise ignored. |
| 170 | // |
| 171 | // In the absence of a time zone indicator, Parse returns a time in UTC. |
| 172 | // |
| 173 | // When parsing a time with a zone offset like -0700, if the offset corresponds |
| 174 | // to a time zone used by the current location (Local), then Parse uses that |
| 175 | // location and zone in the returned time. Otherwise it records the time as |
| 176 | // being in a fabricated location with time fixed at the given zone offset. |
| 177 | // |
| 178 | // When parsing a time with a zone abbreviation like MST, if the zone abbreviation |
| 179 | // has a defined offset in the current location, then that offset is used. |
| 180 | // The zone abbreviation "UTC" is recognized as UTC regardless of location. |
| 181 | // If the zone abbreviation is unknown, Parse records the time as being |
| 182 | // in a fabricated location with the given zone abbreviation and a zero offset. |
| 183 | // This choice means that such a time can be parsed and reformatted with the |
| 184 | // same layout losslessly, but the exact instant used in the representation will |
| 185 | // differ by the actual zone offset. To avoid such problems, prefer time layouts |
| 186 | // that use a numeric zone offset, or use ParseInLocation. |
| 187 | func Parse(layout, value string) (string, error) { |
| 188 | t, err := time.Parse(layout, value) |
| 189 | if err != nil { |
| 190 | return "", err |
| 191 | } |
Marcel van Lohuizen | ca05b5f | 2019-08-07 00:47:33 +0200 | [diff] [blame] | 192 | return t.UTC().Format(time.RFC3339Nano), nil |
Marcel van Lohuizen | 8090639 | 2019-08-06 13:04:16 +0200 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | // Unix returns the local Time corresponding to the given Unix time, |
| 196 | // sec seconds and nsec nanoseconds since January 1, 1970 UTC. |
| 197 | // It is valid to pass nsec outside the range [0, 999999999]. |
| 198 | // Not all sec values have a corresponding time value. One such |
| 199 | // value is 1<<63-1 (the largest int64 value). |
| 200 | func Unix(sec int64, nsec int64) string { |
| 201 | t := time.Unix(sec, nsec) |
Marcel van Lohuizen | ca05b5f | 2019-08-07 00:47:33 +0200 | [diff] [blame] | 202 | return t.UTC().Format(time.RFC3339Nano) |
Marcel van Lohuizen | 8090639 | 2019-08-06 13:04:16 +0200 | [diff] [blame] | 203 | } |