}
// Parse the nanoseconds.
- if strings.Trim(sn, "0123456789") != "" {
- return time.Time{}, ErrHeader
- }
- if len(sn) < maxNanoSecondDigits {
- sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
- } else {
- sn = sn[:maxNanoSecondDigits] // Right truncate
+ // Initialize an array with '0's to handle right padding automatically.
+ nanoDigits := [maxNanoSecondDigits]byte{'0', '0', '0', '0', '0', '0', '0', '0', '0'}
+ for i := range len(sn) {
+ switch c := sn[i]; {
+ case c < '0' || c > '9':
+ return time.Time{}, ErrHeader
+ case i < len(nanoDigits):
+ nanoDigits[i] = c
+ }
}
- nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
+ nsecs, _ := strconv.ParseInt(string(nanoDigits[:]), 10, 64) // Must succeed after validation
if len(ss) > 0 && ss[0] == '-' {
return time.Unix(secs, -1*nsecs), nil // Negative correction
}
}
}
}
+
+func BenchmarkParsePAXTIme(b *testing.B) {
+ tests := []struct {
+ name string
+ in string
+ want time.Time
+ ok bool
+ }{
+ {
+ name: "NoNanos",
+ in: "123456",
+ want: time.Unix(123456, 0),
+ ok: true,
+ },
+ {
+ name: "ExactNanos",
+ in: "1.123456789",
+ want: time.Unix(1, 123456789),
+ ok: true,
+ },
+ {
+ name: "WithNanoPadding",
+ in: "1.123",
+ want: time.Unix(1, 123000000),
+ ok: true,
+ },
+ {
+ name: "WithNanoTruncate",
+ in: "1.123456789123",
+ want: time.Unix(1, 123456789),
+ ok: true,
+ },
+ {
+ name: "TrailingError",
+ in: "1.123abc",
+ want: time.Time{},
+ ok: false,
+ },
+ {
+ name: "LeadingError",
+ in: "1.abc123",
+ want: time.Time{},
+ ok: false,
+ },
+ }
+ for _, tt := range tests {
+ b.Run(tt.name, func(b *testing.B) {
+ b.ReportAllocs()
+ for b.Loop() {
+ ts, err := parsePAXTime(tt.in)
+ if (err == nil) != tt.ok {
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.Fatal("expected error")
+ }
+ if !ts.Equal(tt.want) {
+ b.Fatalf("time mismatch: got %v, want %v", ts, tt.want)
+ }
+ }
+ })
+ }
+}