Repository: ogen-go/ogen
Pull request #15 (2021-10-16 09:08:07)

feat: date and time formats


Patch:
diff --git a/internal/gen/_template/header.tmpl b/internal/gen/_template/header.tmpl
index f3285cf2..c41d1e45 100644
--- a/internal/gen/_template/header.tmpl
+++ b/internal/gen/_template/header.tmpl
@@ -21,6 +21,7 @@ import (
 "github.com/go-chi/chi/v5"
 "github.com/google/uuid"
 "github.com/ogen-go/ogen/conv"
+"github.com/ogen-go/ogen/types"
 "github.com/ogen-go/ogen/uri"
 "github.com/ogen-go/ogen/encoding/json"
 )
@@ -43,6 +44,7 @@ var (
   _ = uuid.UUID{}
   _ = uri.PathEncoder{}
   _ = math.Mod
+  _ = types.Date{}
 )
 
 {{ end }}
diff --git a/internal/gen/schema_gen.go b/internal/gen/schema_gen.go
index 305fa06b..c2519055 100644
--- a/internal/gen/schema_gen.go
+++ b/internal/gen/schema_gen.go
@@ -210,8 +210,10 @@ func (g *schemaGen) parseSimple(typ, format string) (string, error) {
 		"string": {
 			"":          "string",
 			"byte":      "[]byte",
-			"date":      "time.Time",
 			"date-time": "time.Time",
+			"time":      "types.Time",
+			"date":      "types.Date",
+			"duration":  "types.Duration",
 			"password":  "string",
 			"uuid":      "uuid.UUID",
 			// TODO: support binary format
diff --git a/internal/sample_api/openapi_client_gen.go b/internal/sample_api/openapi_client_gen.go
index f93124f2..886d2d4d 100644
--- a/internal/sample_api/openapi_client_gen.go
+++ b/internal/sample_api/openapi_client_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 type HTTPClient interface {
diff --git a/internal/sample_api/openapi_handlers_gen.go b/internal/sample_api/openapi_handlers_gen.go
index 0b9ca708..d353b658 100644
--- a/internal/sample_api/openapi_handlers_gen.go
+++ b/internal/sample_api/openapi_handlers_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func NewFoobarGetHandler(s Server) func(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/sample_api/openapi_param_decoders_gen.go b/internal/sample_api/openapi_param_decoders_gen.go
index b9fda361..ce2d9ba6 100644
--- a/internal/sample_api/openapi_param_decoders_gen.go
+++ b/internal/sample_api/openapi_param_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func decodeFoobarGetParams(r *http.Request) (FoobarGetParams, error) {
diff --git a/internal/sample_api/openapi_params_gen.go b/internal/sample_api/openapi_params_gen.go
index 5ccd93b9..b671b8ef 100644
--- a/internal/sample_api/openapi_params_gen.go
+++ b/internal/sample_api/openapi_params_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 type FoobarGetParams struct {
diff --git a/internal/sample_api/openapi_request_decoders_gen.go b/internal/sample_api/openapi_request_decoders_gen.go
index d5910811..72fb6b55 100644
--- a/internal/sample_api/openapi_request_decoders_gen.go
+++ b/internal/sample_api/openapi_request_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func decodeFoobarPostRequest(r *http.Request) (_ *Pet, rerr error) {
diff --git a/internal/sample_api/openapi_request_encoders_gen.go b/internal/sample_api/openapi_request_encoders_gen.go
index ac7eaa61..2dc6bfe3 100644
--- a/internal/sample_api/openapi_request_encoders_gen.go
+++ b/internal/sample_api/openapi_request_encoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func encodeFoobarPostRequest(req *Pet) ([]byte, string, error) {
diff --git a/internal/sample_api/openapi_response_decoders_gen.go b/internal/sample_api/openapi_response_decoders_gen.go
index 647df74c..dfe240c7 100644
--- a/internal/sample_api/openapi_response_decoders_gen.go
+++ b/internal/sample_api/openapi_response_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func decodeFoobarGetResponse(resp *http.Response) (_ FoobarGetResponse, rerr error) {
diff --git a/internal/sample_api/openapi_response_encoders_gen.go b/internal/sample_api/openapi_response_encoders_gen.go
index 74f511a3..cada60c0 100644
--- a/internal/sample_api/openapi_response_encoders_gen.go
+++ b/internal/sample_api/openapi_response_encoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func encodeFoobarGetResponse(response FoobarGetResponse, w http.ResponseWriter) error {
diff --git a/internal/sample_api/openapi_router_gen.go b/internal/sample_api/openapi_router_gen.go
index 631b5035..1c2cf9b3 100644
--- a/internal/sample_api/openapi_router_gen.go
+++ b/internal/sample_api/openapi_router_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func Register(r chi.Router, s Server) {
diff --git a/internal/sample_api/openapi_schemas_gen.go b/internal/sample_api/openapi_schemas_gen.go
index 97c54926..d7acf188 100644
--- a/internal/sample_api/openapi_schemas_gen.go
+++ b/internal/sample_api/openapi_schemas_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 type Error struct {
@@ -65,15 +67,19 @@ func (*NotFound) foobarPostResponse() {}
 
 // Pet describes #/components/schemas/Pet.
 type Pet struct {
-	Birthday     time.Time   `json:"birthday"`
-	Friends      *[]Pet      `json:"friends"`
-	ID           int64       `json:"id"`
-	Name         string      `json:"name"`
-	Tag          *uuid.UUID  `json:"tag"`
-	TestArray1   *[][]string `json:"testArray1"`
-	TestFloat1   *float64    `json:"testFloat1"`
-	TestInteger1 *int        `json:"testInteger1"`
-	Type         *PetType    `json:"type"`
+	Birthday     types.Date      `json:"birthday"`
+	Friends      *[]Pet          `json:"friends"`
+	ID           int64           `json:"id"`
+	Name         string          `json:"name"`
+	Tag          *uuid.UUID      `json:"tag"`
+	TestArray1   *[][]string     `json:"testArray1"`
+	TestDate     *types.Date     `json:"testDate"`
+	TestDateTime *time.Time      `json:"testDateTime"`
+	TestDuration *types.Duration `json:"testDuration"`
+	TestFloat1   *float64        `json:"testFloat1"`
+	TestInteger1 *int            `json:"testInteger1"`
+	TestTime     *types.Time     `json:"testTime"`
+	Type         *PetType        `json:"type"`
 }
 
 func (*Pet) foobarGetResponse()  {}
diff --git a/internal/sample_api/openapi_server_gen.go b/internal/sample_api/openapi_server_gen.go
index aa77b204..57a7de9f 100644
--- a/internal/sample_api/openapi_server_gen.go
+++ b/internal/sample_api/openapi_server_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 // Server handles operations described by OpenAPI v3 specification.
diff --git a/internal/sample_api/openapi_validators_gen.go b/internal/sample_api/openapi_validators_gen.go
index d4687209..209b32a9 100644
--- a/internal/sample_api/openapi_validators_gen.go
+++ b/internal/sample_api/openapi_validators_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func (s *Pet) validate() error {
diff --git a/internal/techempower/openapi_client_gen.go b/internal/techempower/openapi_client_gen.go
index 580def53..413d496b 100644
--- a/internal/techempower/openapi_client_gen.go
+++ b/internal/techempower/openapi_client_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 type HTTPClient interface {
diff --git a/internal/techempower/openapi_handlers_gen.go b/internal/techempower/openapi_handlers_gen.go
index 8712b70a..42a22193 100644
--- a/internal/techempower/openapi_handlers_gen.go
+++ b/internal/techempower/openapi_handlers_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func NewCachingHandler(s Server) func(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/techempower/openapi_param_decoders_gen.go b/internal/techempower/openapi_param_decoders_gen.go
index f38165dd..865a194c 100644
--- a/internal/techempower/openapi_param_decoders_gen.go
+++ b/internal/techempower/openapi_param_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func decodeCachingParams(r *http.Request) (CachingParams, error) {
diff --git a/internal/techempower/openapi_params_gen.go b/internal/techempower/openapi_params_gen.go
index 277a529d..f373688e 100644
--- a/internal/techempower/openapi_params_gen.go
+++ b/internal/techempower/openapi_params_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 type CachingParams struct {
diff --git a/internal/techempower/openapi_request_decoders_gen.go b/internal/techempower/openapi_request_decoders_gen.go
index 119ce259..2e9998af 100644
--- a/internal/techempower/openapi_request_decoders_gen.go
+++ b/internal/techempower/openapi_request_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,4 +41,5 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
diff --git a/internal/techempower/openapi_request_encoders_gen.go b/internal/techempower/openapi_request_encoders_gen.go
index 119ce259..2e9998af 100644
--- a/internal/techempower/openapi_request_encoders_gen.go
+++ b/internal/techempower/openapi_request_encoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,4 +41,5 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
diff --git a/internal/techempower/openapi_response_decoders_gen.go b/internal/techempower/openapi_response_decoders_gen.go
index 9aad4c3b..df02d079 100644
--- a/internal/techempower/openapi_response_decoders_gen.go
+++ b/internal/techempower/openapi_response_decoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func decodeCachingResponse(resp *http.Response) (_ []WorldObject, rerr error) {
diff --git a/internal/techempower/openapi_response_encoders_gen.go b/internal/techempower/openapi_response_encoders_gen.go
index f3ede463..e632b1bf 100644
--- a/internal/techempower/openapi_response_encoders_gen.go
+++ b/internal/techempower/openapi_response_encoders_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func encodeCachingResponse(response []WorldObject, w http.ResponseWriter) error {
diff --git a/internal/techempower/openapi_router_gen.go b/internal/techempower/openapi_router_gen.go
index 6433b1ac..b73e871b 100644
--- a/internal/techempower/openapi_router_gen.go
+++ b/internal/techempower/openapi_router_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 func Register(r chi.Router, s Server) {
diff --git a/internal/techempower/openapi_schemas_gen.go b/internal/techempower/openapi_schemas_gen.go
index c309ba82..2c5b502b 100644
--- a/internal/techempower/openapi_schemas_gen.go
+++ b/internal/techempower/openapi_schemas_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 // HelloWorld describes #/components/schemas/HelloWorld.
diff --git a/internal/techempower/openapi_server_gen.go b/internal/techempower/openapi_server_gen.go
index 6edba218..8793ad5d 100644
--- a/internal/techempower/openapi_server_gen.go
+++ b/internal/techempower/openapi_server_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,6 +41,7 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
 
 // Server handles operations described by OpenAPI v3 specification.
diff --git a/internal/techempower/openapi_validators_gen.go b/internal/techempower/openapi_validators_gen.go
index 119ce259..2e9998af 100644
--- a/internal/techempower/openapi_validators_gen.go
+++ b/internal/techempower/openapi_validators_gen.go
@@ -19,6 +19,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/ogen-go/ogen/conv"
 	"github.com/ogen-go/ogen/encoding/json"
+	"github.com/ogen-go/ogen/types"
 	"github.com/ogen-go/ogen/uri"
 )
 
@@ -40,4 +41,5 @@ var (
 	_ = uuid.UUID{}
 	_ = uri.PathEncoder{}
 	_ = math.Mod
+	_ = types.Date{}
 )
diff --git a/types/time.go b/types/time.go
new file mode 100644
index 00000000..d6644d93
--- /dev/null
+++ b/types/time.go
@@ -0,0 +1,86 @@
+package types
+
+import (
+	"encoding/json"
+	"time"
+)
+
+const (
+	dateLayout = "2006-01-02"
+	timeLayout = "15:04:05"
+)
+
+type Date struct {
+	time.Time
+}
+
+func (d Date) MarshalJSON() ([]byte, error) {
+	return json.Marshal(d.Format(dateLayout))
+}
+
+func (d *Date) UnmarshalJSON(b []byte) error {
+	var v string
+
+	if err := json.Unmarshal(b, &v); err != nil {
+		return err
+	}
+
+	t, err := time.Parse(dateLayout, v)
+	if err != nil {
+		return err
+	}
+
+	d.Time = t
+
+	return nil
+}
+
+type Time struct {
+	time.Time
+}
+
+func (t Time) MarshalJSON() ([]byte, error) {
+	return json.Marshal(t.Format(timeLayout))
+}
+
+func (t *Time) UnmarshalJSON(b []byte) error {
+	var v string
+
+	if err := json.Unmarshal(b, &v); err != nil {
+		return err
+	}
+
+	dt, err := time.Parse(timeLayout, v)
+	if err != nil {
+		return err
+	}
+
+	t.Time = dt
+
+	return nil
+}
+
+type Duration struct {
+	time.Duration
+}
+
+func (d Duration) MarshalJSON() ([]byte, error) {
+	return json.Marshal(d.String())
+}
+
+func (d *Duration) UnmarshalJSON(b []byte) error {
+	var v string
+
+	if err := json.Unmarshal(b, &v); err != nil {
+		return err
+	}
+
+	dt, err := time.ParseDuration(v)
+	if err != nil {
+		return err
+	}
+
+	d.Duration = dt
+
+	return nil
+}


Test patch:
diff --git a/_testdata/sample_1.json b/_testdata/sample_1.json
index d0e305b4..d06ad81e 100644
--- a/_testdata/sample_1.json
+++ b/_testdata/sample_1.json
@@ -276,6 +276,22 @@
                 "maxLength": 255
               }
             }
+          },
+          "testDate": {
+            "type": "string",
+            "format": "date"
+          },
+          "testDuration": {
+            "type": "string",
+            "format": "duration"
+          },
+          "testTime": {
+            "type": "string",
+            "format": "time"
+          },
+          "testDateTime": {
+            "type": "string",
+            "format": "date-time"
           }
         },
         "required": [
diff --git a/types/time_test.go b/types/time_test.go
new file mode 100644
index 00000000..361a2331
--- /dev/null
+++ b/types/time_test.go
@@ -0,0 +1,43 @@
+package types
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestTime(t *testing.T) {
+	var v Time
+	s := `"20:30:15"`
+
+	require.NoError(t, v.UnmarshalJSON([]byte(s)))
+
+	b, err := v.MarshalJSON()
+	require.NoError(t, err)
+
+	require.Equal(t, s, string(b))
+}
+
+func TestDate(t *testing.T) {
+	var v Date
+	s := `"2021-10-10"`
+
+	require.NoError(t, v.UnmarshalJSON([]byte(s)))
+
+	b, err := v.MarshalJSON()
+	require.NoError(t, err)
+
+	require.Equal(t, s, string(b))
+}
+
+func TestDuration(t *testing.T) {
+	var v Duration
+	s := `"100h0m0s"`
+
+	require.NoError(t, v.UnmarshalJSON([]byte(s)))
+
+	b, err := v.MarshalJSON()
+	require.NoError(t, err)
+
+	require.Equal(t, s, string(b))
+}