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  }