// Copyright 2022 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package timeimport// RFC 3339 is the most commonly used format.//// It is implicitly used by the Time.(Marshal|Unmarshal)(Text|JSON) methods.// Also, according to analysis on https://go.dev/issue/52746,// RFC 3339 accounts for 57% of all explicitly specified time formats,// with the second most popular format only being used 8% of the time.// The overwhelming use of RFC 3339 compared to all other formats justifies// the addition of logic to optimize formatting and parsing.func ( Time) ( []byte, bool) []byte { , , := .locabs()// Format date. , , , := absDate(, true) = appendInt(, , 4) = append(, '-') = appendInt(, int(), 2) = append(, '-') = appendInt(, , 2) = append(, 'T')// Format time. , , := absClock() = appendInt(, , 2) = append(, ':') = appendInt(, , 2) = append(, ':') = appendInt(, , 2)if { := stdFracSecond(stdFracSecond9, 9, '.') = appendNano(, .Nanosecond(), ) }if == 0 {returnappend(, 'Z') }// Format zone. := / 60// convert to minutesif < 0 { = append(, '-') = - } else { = append(, '+') } = appendInt(, /60, 2) = append(, ':') = appendInt(, %60, 2)return}func ( Time) ( []byte) ([]byte, error) { := len() = .appendFormatRFC3339(, true)// Not all valid Go timestamps can be serialized as valid RFC 3339. // Explicitly check for these edge cases. // See https://go.dev/issue/4556 and https://go.dev/issue/54580. := func( []byte) byte { return10*([0]-'0') + ([1] - '0') }switch {case [+len("9999")] != '-': // year must be exactly 4 digits widereturn , errors.New("year outside of range [0,9999]")case [len()-1] != 'Z': := [len()-len("Z07:00")]if ('0' <= && <= '9') || ([len()-len("07:00"):]) >= 24 {return , errors.New("timezone hour outside of range [0,23]") } }return , nil}func parseRFC3339[ []byte | string]( , *Location) (Time, bool) {// parseUint parses s as an unsigned decimal integer and // verifies that it is within some range. // If it is invalid or out-of-range, // it sets ok to false and returns the min value. := true := func( , , int) ( int) {for , := range []byte() {if < '0' || '9' < { = falsereturn } = *10 + int() - '0' }if < || < { = falsereturn }return }// Parse the date and time.iflen() < len("2006-01-02T15:04:05") {returnTime{}, false } := ([0:4], 0, 9999) // e.g., 2006 := ([5:7], 1, 12) // e.g., 01 := ([8:10], 1, daysIn(Month(), )) // e.g., 02 := ([11:13], 0, 23) // e.g., 15 := ([14:16], 0, 59) // e.g., 04 := ([17:19], 0, 59) // e.g., 05if ! || !([4] == '-' && [7] == '-' && [10] == 'T' && [13] == ':' && [16] == ':') {returnTime{}, false } = [19:]// Parse the fractional second.varintiflen() >= 2 && [0] == '.' && isDigit(, 1) { := 2for ; < len() && isDigit(, ); ++ { } , _, _ = parseNanoseconds(, ) = [:] }// Parse the time zone. := Date(, Month(), , , , , , UTC)iflen() != 1 || [0] != 'Z' {iflen() != len("-07:00") {returnTime{}, false } := ([1:3], 0, 23) // e.g., 07 := ([4:6], 0, 59) // e.g., 00if ! || !(([0] == '-' || [0] == '+') && [3] == ':') {returnTime{}, false } := (*60 + ) * 60if [0] == '-' { *= -1 } .addSec(-int64())// Use local zone with the given offset if possible.if , , , , := .lookup(.unixSec()); == { .setLoc() } else { .setLoc(FixedZone("", )) } }return , true}func parseStrictRFC3339( []byte) (Time, error) { , := parseRFC3339(, Local)if ! { , := Parse(RFC3339, string())if != nil {returnTime{}, }// The parse template syntax cannot correctly validate RFC 3339. // Explicitly check for cases that Parse is unable to validate for. // See https://go.dev/issue/54580. := func( []byte) byte { return10*([0]-'0') + ([1] - '0') }switch {// TODO(https://go.dev/issue/54580): Strict parsing is disabled for now. // Enable this again with a GODEBUG opt-out.casetrue:return , nilcase [len("2006-01-02T")+1] == ':': // hour must be two digitsreturnTime{}, &ParseError{RFC3339, string(), "15", string([len("2006-01-02T"):][:1]), ""}case [len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a periodreturnTime{}, &ParseError{RFC3339, string(), ".", ",", ""}case [len()-1] != 'Z':switch {case ([len()-len("07:00"):]) >= 24: // timezone hour must be in rangereturnTime{}, &ParseError{RFC3339, string(), "Z07:00", string([len()-len("Z07:00"):]), ": timezone hour out of range"}case ([len()-len("00"):]) >= 60: // timezone minute must be in rangereturnTime{}, &ParseError{RFC3339, string(), "Z07:00", string([len()-len("Z07:00"):]), ": timezone minute out of range"} }default: // unknown error; should not occurreturnTime{}, &ParseError{RFC3339, string(), RFC3339, string(), ""} } }return , nil}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.