github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/api/types/time/timestamp.go (about) 1 package time 2 3 import ( 4 "fmt" 5 "math" 6 "strconv" 7 "strings" 8 "time" 9 ) 10 11 // These are additional predefined layouts for use in Time.Format and Time.Parse 12 // with --since and --until parameters for `docker logs` and `docker events` 13 const ( 14 rFC3339Local = "2006-01-02T15:04:05" // RFC3339 with local timezone 15 rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone 16 dateWithZone = "2006-01-02Z07:00" // RFC3339 with time at 00:00:00 17 dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00 18 ) 19 20 // GetTimestamp tries to parse given string as golang duration, 21 // then RFC3339 time and finally as a Unix timestamp. If 22 // any of these were successful, it returns a Unix timestamp 23 // as string otherwise returns the given value back. 24 // In case of duration input, the returned timestamp is computed 25 // as the given reference time minus the amount of the duration. 26 func GetTimestamp(value string, reference time.Time) (string, error) { 27 if d, err := time.ParseDuration(value); value != "0" && err == nil { 28 return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil 29 } 30 31 var format string 32 var parseInLocation bool 33 34 // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation 35 parseInLocation = !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) 36 37 if strings.Contains(value, ".") { 38 if parseInLocation { 39 format = rFC3339NanoLocal 40 } else { 41 format = time.RFC3339Nano 42 } 43 } else if strings.Contains(value, "T") { 44 // we want the number of colons in the T portion of the timestamp 45 tcolons := strings.Count(value, ":") 46 // if parseInLocation is off and we have a +/- zone offset (not Z) then 47 // there will be an extra colon in the input for the tz offset subtract that 48 // colon from the tcolons count 49 if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 { 50 tcolons-- 51 } 52 if parseInLocation { 53 switch tcolons { 54 case 0: 55 format = "2006-01-02T15" 56 case 1: 57 format = "2006-01-02T15:04" 58 default: 59 format = rFC3339Local 60 } 61 } else { 62 switch tcolons { 63 case 0: 64 format = "2006-01-02T15Z07:00" 65 case 1: 66 format = "2006-01-02T15:04Z07:00" 67 default: 68 format = time.RFC3339 69 } 70 } 71 } else if parseInLocation { 72 format = dateLocal 73 } else { 74 format = dateWithZone 75 } 76 77 var t time.Time 78 var err error 79 80 if parseInLocation { 81 t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone())) 82 } else { 83 t, err = time.Parse(format, value) 84 } 85 86 if err != nil { 87 // if there is a `-` then its an RFC3339 like timestamp otherwise assume unixtimestamp 88 if strings.Contains(value, "-") { 89 return "", err // was probably an RFC3339 like timestamp but the parser failed with an error 90 } 91 return value, nil // unixtimestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server) 92 } 93 94 return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil 95 } 96 97 // ParseTimestamps returns seconds and nanoseconds from a timestamp that has the 98 // format "%d.%09d", time.Unix(), int64(time.Nanosecond())) 99 // if the incoming nanosecond portion is longer or shorter than 9 digits it is 100 // converted to nanoseconds. The expectation is that the seconds and 101 // seconds will be used to create a time variable. For example: 102 // seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0) 103 // if err == nil since := time.Unix(seconds, nanoseconds) 104 // returns seconds as def(aultSeconds) if value == "" 105 func ParseTimestamps(value string, def int64) (int64, int64, error) { 106 if value == "" { 107 return def, 0, nil 108 } 109 sa := strings.SplitN(value, ".", 2) 110 s, err := strconv.ParseInt(sa[0], 10, 64) 111 if err != nil { 112 return s, 0, err 113 } 114 if len(sa) != 2 { 115 return s, 0, nil 116 } 117 n, err := strconv.ParseInt(sa[1], 10, 64) 118 if err != nil { 119 return s, n, err 120 } 121 // should already be in nanoseconds but just in case convert n to nanoseonds 122 n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1])))) 123 return s, n, nil 124 }