2020-11-08 21:49:44 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2020-11-10 17:17:11 +08:00
|
|
|
"fmt"
|
2020-11-08 21:49:44 +08:00
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-11-29 09:16:41 +08:00
|
|
|
// ErrComponentsMismatch is thrown when the URL has empty or missing components
|
|
|
|
var ErrComponentsMismatch = errors.New("missing or too many path components")
|
2020-11-10 17:17:11 +08:00
|
|
|
|
|
|
|
// ErrInvalidTime is thrown in a time.ParseError
|
|
|
|
var ErrInvalidTime = errors.New("invalid ISO 8601 time")
|
2020-11-08 21:49:44 +08:00
|
|
|
|
|
|
|
var timeRFC3339NoSec = "2006-01-02T15:04Z07:00"
|
|
|
|
var timeFormats = []string{time.RFC3339, timeRFC3339NoSec}
|
|
|
|
|
|
|
|
// Request is a parsed datetime URL
|
|
|
|
type Request struct {
|
|
|
|
Time time.Time
|
|
|
|
Zones []string
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseRequest parses an input URL into a Request
|
|
|
|
func ParseRequest(u *url.URL) (Request, error) {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
parts := strings.Split(u.Path, "/")[1:]
|
2020-11-29 09:16:41 +08:00
|
|
|
if len(parts) > 2 || len(parts) < 1 {
|
|
|
|
return Request{}, ErrComponentsMismatch
|
2020-11-08 21:49:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse time portion
|
|
|
|
var t time.Time
|
|
|
|
timeString := parts[0]
|
|
|
|
if len(timeString) == 0 {
|
2020-11-29 09:16:41 +08:00
|
|
|
return Request{}, ErrComponentsMismatch
|
2020-11-08 21:49:44 +08:00
|
|
|
}
|
2020-11-10 19:52:28 +08:00
|
|
|
if timeString == "now" {
|
|
|
|
t = time.Now()
|
|
|
|
} else {
|
|
|
|
for _, f := range timeFormats {
|
|
|
|
t, err = time.Parse(f, timeString)
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return Request{}, fmt.Errorf("%w: %v", ErrInvalidTime, err)
|
2020-11-08 21:49:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split zones
|
|
|
|
var z []string
|
2020-11-29 09:16:41 +08:00
|
|
|
zoneString := "local"
|
2020-11-08 21:49:44 +08:00
|
|
|
if len(parts) >= 2 {
|
|
|
|
zoneString = parts[1]
|
|
|
|
}
|
|
|
|
if len(zoneString) == 0 {
|
2020-11-29 09:16:41 +08:00
|
|
|
return Request{}, ErrComponentsMismatch
|
2020-11-08 21:49:44 +08:00
|
|
|
}
|
|
|
|
z = strings.Split(zoneString, ",")
|
|
|
|
|
|
|
|
return Request{
|
|
|
|
Time: t,
|
|
|
|
Zones: z,
|
|
|
|
}, nil
|
|
|
|
}
|