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  }