github.com/solo-io/cue@v0.4.7/pkg/time/time.go (about) 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 } 192 return t.UTC().Format(time.RFC3339Nano), nil 193 } 194 195 // Unix returns the Time, in UTC, 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) 202 return t.UTC().Format(time.RFC3339Nano) 203 }