this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

syntax: always do full datetime parse

+26 -9
+19 -7
atproto/syntax/datetime.go
··· 17 17 // Represents the a Datetime in string format, as would pass Lexicon syntax validation: the intersection of RFC-3339 and ISO-8601 syntax. 18 18 // 19 19 // Always use [ParseDatetime] instead of wrapping strings directly, especially when working with network input. 20 + // 21 + // Syntax is specified at: https://atproto.com/specs/lexicon#datetime 20 22 type Datetime string 21 23 22 24 func ParseDatetime(raw string) (Datetime, error) { ··· 29 31 } 30 32 if strings.HasSuffix(raw, "-00:00") { 31 33 return "", fmt.Errorf("Datetime can't use '-00:00' for UTC timezone, must use '+00:00', per ISO-8601") 34 + } 35 + // ensure that the datetime actually parses using golang time lib 36 + _, err := time.Parse(time.RFC3339Nano, raw) 37 + if err != nil { 38 + return "", err 32 39 } 33 40 return Datetime(raw), nil 34 41 } 35 42 36 - // Parses a string to a golang time.Time in a single step. 43 + // Validates and converts a string to a golang [time.Time] in a single step. 37 44 func ParseDatetimeTime(raw string) (time.Time, error) { 38 - var zero time.Time 39 45 d, err := ParseDatetime(raw) 40 46 if err != nil { 47 + var zero time.Time 41 48 return zero, err 42 49 } 43 - return d.Time() 50 + return d.Time(), nil 44 51 } 45 52 46 - // Parses the Datetime string in to a golang time.Time. 53 + // Parses the Datetime string in to a golang [time.Time]. 47 54 // 48 - // There are a small number of strings which will pass initial syntax validation but fail when actually parsing, so this function can return an error. Use [ParseDatetimeTime] to fully parse in a single function call. 49 - func (d Datetime) Time() (time.Time, error) { 50 - return time.Parse(time.RFC3339Nano, d.String()) 55 + // This method assumes that [ParseDatetime] was used to create the Datetime, which already verified parsing, and thus that [time.Parse] will always succeed. In the event of an error, zero/nil will be returned. 56 + func (d Datetime) Time() time.Time { 57 + var zero time.Time 58 + ret, err := time.Parse(time.RFC3339Nano, d.String()) 59 + if err != nil { 60 + return zero 61 + } 62 + return ret 51 63 } 52 64 53 65 // Creates a new valid Datetime string matching the current time, in prefered syntax.
+7 -2
atproto/syntax/datetime_test.go
··· 60 60 if len(line) == 0 || line[0] == '#' { 61 61 continue 62 62 } 63 - _, err := ParseDatetimeTime(line) 63 + _, err := ParseDatetime(line) 64 + if err == nil { 65 + fmt.Println("BAD: " + line) 66 + } 67 + assert.Error(err) 68 + _, err = ParseDatetimeTime(line) 64 69 if err == nil { 65 70 fmt.Println("BAD: " + line) 66 71 } ··· 69 74 assert.NoError(scanner.Err()) 70 75 } 71 76 72 - func TestInteropDatetimeNow(t *testing.T) { 77 + func TestDatetimeNow(t *testing.T) { 73 78 assert := assert.New(t) 74 79 75 80 dt := DatetimeNow()