File size: 1,721 Bytes
fea99b3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | package datetime
import (
"errors"
"strings"
"time"
)
// Parse parses a RFC3339, ISO8601, or RFC9557 formatted string into a DateTime.
func Parse(value string) (DateTime, error) {
if value == "" {
return DateTime{}, NewDateTimeParseError(value)
}
// Check if the value has a timezone suffix
i := strings.LastIndexByte(value, '[')
if i == -1 || !strings.HasSuffix(value, "]") {
// No timezone suffix, try standard layouts
layouts := []string{
time.RFC3339,
time.RFC3339Nano,
ISO8601Layout,
ISO8601MilliLayout,
ISO8601MicroLayout,
ISO8601NanoLayout,
ISO8601ZuluLayout,
ISO8601ZuluMilliLayout,
ISO8601ZuluMicroLayout,
ISO8601ZuluNanoLayout,
}
for _, layout := range layouts {
if t, err := time.Parse(layout, value); err == nil {
return DateTime{t}, nil
}
}
return DateTime{}, NewDateTimeParseError(value)
}
// Extract timestamp and timezone
timestamp := value[:i]
timezone := value[i+1 : len(value)-1]
// Validate timezone bracket format
if timezone == "" {
return DateTime{}, NewInvalidTimezoneError(timezone, errors.New("timezone identifier is empty"))
}
// Load the timezone location
loc, err := time.LoadLocation(timezone)
if err != nil {
return DateTime{}, NewInvalidTimezoneError(timezone, err)
}
// Try parsing with RFC9557-compatible layouts
layouts := []string{
time.RFC3339,
time.RFC3339Nano,
ISO8601ZuluLayout,
ISO8601ZuluMilliLayout,
ISO8601ZuluMicroLayout,
ISO8601ZuluNanoLayout,
}
for _, layout := range layouts {
if t, err := time.Parse(layout, timestamp); err == nil {
// Convert to the specified timezone
return DateTime{t.In(loc)}, nil
}
}
return DateTime{}, NewDateTimeParseError(value)
}
|