blob: d93ac5e9bad3de8c1364586e703d371ce7ba0fbc [file] [log] [blame]
Marcel van Lohuizen80906392019-08-06 13:04:16 +02001// 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.
16package time
17
18import (
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.
83const (
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
99const (
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
114const (
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.
128func Time(s string) (bool, error) {
129 return timeFormat(s, time.RFC3339Nano)
130}
131
132func 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.
145func 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.
187func Parse(layout, value string) (string, error) {
188 t, err := time.Parse(layout, value)
189 if err != nil {
190 return "", err
191 }
Marcel van Lohuizenca05b5f2019-08-07 00:47:33 +0200192 return t.UTC().Format(time.RFC3339Nano), nil
Marcel van Lohuizen80906392019-08-06 13:04:16 +0200193}
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).
200func Unix(sec int64, nsec int64) string {
201 t := time.Unix(sec, nsec)
Marcel van Lohuizenca05b5f2019-08-07 00:47:33 +0200202 return t.UTC().Format(time.RFC3339Nano)
Marcel van Lohuizen80906392019-08-06 13:04:16 +0200203}