github.com/aavshr/aws-sdk-go@v1.41.3/private/protocol/timestamp.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "strconv" 8 "time" 9 10 "github.com/aavshr/aws-sdk-go/internal/sdkmath" 11 ) 12 13 // Names of time formats supported by the SDK 14 const ( 15 RFC822TimeFormatName = "rfc822" 16 ISO8601TimeFormatName = "iso8601" 17 UnixTimeFormatName = "unixTimestamp" 18 ) 19 20 // Time formats supported by the SDK 21 // Output time is intended to not contain decimals 22 const ( 23 // RFC 7231#section-7.1.1.1 timetamp format. e.g Tue, 29 Apr 2014 18:30:38 GMT 24 RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT" 25 rfc822TimeFormatSingleDigitDay = "Mon, _2 Jan 2006 15:04:05 GMT" 26 rfc822TimeFormatSingleDigitDayTwoDigitYear = "Mon, _2 Jan 06 15:04:05 GMT" 27 28 // This format is used for output time without seconds precision 29 RFC822OutputTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" 30 31 // RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z 32 ISO8601TimeFormat = "2006-01-02T15:04:05.999999999Z" 33 iso8601TimeFormatNoZ = "2006-01-02T15:04:05.999999999" 34 35 // This format is used for output time with fractional second precision up to milliseconds 36 ISO8601OutputTimeFormat = "2006-01-02T15:04:05.999999999Z" 37 ) 38 39 // IsKnownTimestampFormat returns if the timestamp format name 40 // is know to the SDK's protocols. 41 func IsKnownTimestampFormat(name string) bool { 42 switch name { 43 case RFC822TimeFormatName: 44 fallthrough 45 case ISO8601TimeFormatName: 46 fallthrough 47 case UnixTimeFormatName: 48 return true 49 default: 50 return false 51 } 52 } 53 54 // FormatTime returns a string value of the time. 55 func FormatTime(name string, t time.Time) string { 56 t = t.UTC().Truncate(time.Millisecond) 57 58 switch name { 59 case RFC822TimeFormatName: 60 return t.Format(RFC822OutputTimeFormat) 61 case ISO8601TimeFormatName: 62 return t.Format(ISO8601OutputTimeFormat) 63 case UnixTimeFormatName: 64 ms := t.UnixNano() / int64(time.Millisecond) 65 return strconv.FormatFloat(float64(ms)/1e3, 'f', -1, 64) 66 default: 67 panic("unknown timestamp format name, " + name) 68 } 69 } 70 71 // ParseTime attempts to parse the time given the format. Returns 72 // the time if it was able to be parsed, and fails otherwise. 73 func ParseTime(formatName, value string) (time.Time, error) { 74 switch formatName { 75 case RFC822TimeFormatName: // Smithy HTTPDate format 76 return tryParse(value, 77 RFC822TimeFormat, 78 rfc822TimeFormatSingleDigitDay, 79 rfc822TimeFormatSingleDigitDayTwoDigitYear, 80 time.RFC850, 81 time.ANSIC, 82 ) 83 case ISO8601TimeFormatName: // Smithy DateTime format 84 return tryParse(value, 85 ISO8601TimeFormat, 86 iso8601TimeFormatNoZ, 87 time.RFC3339Nano, 88 time.RFC3339, 89 ) 90 case UnixTimeFormatName: 91 v, err := strconv.ParseFloat(value, 64) 92 _, dec := math.Modf(v) 93 dec = sdkmath.Round(dec*1e3) / 1e3 //Rounds 0.1229999 to 0.123 94 if err != nil { 95 return time.Time{}, err 96 } 97 return time.Unix(int64(v), int64(dec*(1e9))), nil 98 default: 99 panic("unknown timestamp format name, " + formatName) 100 } 101 } 102 103 func tryParse(v string, formats ...string) (time.Time, error) { 104 var errs parseErrors 105 for _, f := range formats { 106 t, err := time.Parse(f, v) 107 if err != nil { 108 errs = append(errs, parseError{ 109 Format: f, 110 Err: err, 111 }) 112 continue 113 } 114 return t, nil 115 } 116 117 return time.Time{}, fmt.Errorf("unable to parse time string, %v", errs) 118 } 119 120 type parseErrors []parseError 121 122 func (es parseErrors) Error() string { 123 var s bytes.Buffer 124 for _, e := range es { 125 fmt.Fprintf(&s, "\n * %q: %v", e.Format, e.Err) 126 } 127 128 return "parse errors:" + s.String() 129 } 130 131 type parseError struct { 132 Format string 133 Err error 134 }