From 7eef0865df1482863f1347d1920e2a4e8dfdf32f Mon Sep 17 00:00:00 2001 From: Alexander Green Date: Thu, 24 Jul 2025 16:52:10 +0200 Subject: [PATCH 01/14] Added `/core/date-time` --- sections/designRules.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sections/designRules.md b/sections/designRules.md index 95403e7..7451938 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -125,6 +125,22 @@ A resource that corresponds to a single conceptual entity is referred to as a [= +
+

Use ISO 8601 for date and time formats

+
+
Statement
+
+

All date and time fields in requests and responses MUST be in ISO 8601 format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). The response MUST be in UTC. While the request can have a time offset, storing SHOULD be done in UTC.

+

If the time is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

+
+
Rationale
+
+

Implementing ISO 8601 in UTC removes ambiguity in date handling between systems and timezones.

+

Inserting a default or irrelevant time can lead to interpretation errors in international contexts. A publish date of 2025-07-24T00:00:00Z could for instance be rendered as July 23 in Ireland. A default time of 23:59 would in turn cause date confusion east of Greenwich.

+
+
+
+ ## HTTP methods Although the REST architectural style does not impose a specific protocol, REST APIs are typically implemented using HTTP [[rfc9110]]. From 8b98d6f88017f09040e0ec47d17af5e1603f6741 Mon Sep 17 00:00:00 2001 From: Alexander Green Date: Thu, 24 Jul 2025 16:57:50 +0200 Subject: [PATCH 02/14] markdownlint --- sections/designRules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index 7451938..375f984 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -131,7 +131,7 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
Statement

All date and time fields in requests and responses MUST be in ISO 8601 format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). The response MUST be in UTC. While the request can have a time offset, storing SHOULD be done in UTC.

-

If the time is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

+

If the time is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

Rationale
From c982b064d49f53c8bfc7d5c21ca9ab84b91c65d4 Mon Sep 17 00:00:00 2001 From: Alexander Green Date: Wed, 13 Aug 2025 16:02:02 +0200 Subject: [PATCH 03/14] Apply suggestions from code review Co-authored-by: Tim van der Lippe --- sections/designRules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index 375f984..c77f4f6 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -130,8 +130,8 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
Statement
-

All date and time fields in requests and responses MUST be in ISO 8601 format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). The response MUST be in UTC. While the request can have a time offset, storing SHOULD be done in UTC.

-

If the time is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

+

All date and time fields in requests and responses MUST be in ISO 8601 format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). Fields in responses MUST be in UTC. Fields in requests MUST allow any time offset, which servers SHOULD normalize to (and store in) UTC.

+

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

Rationale
From 00ae4402c9260d67ad09912671a76afd6f27f16e Mon Sep 17 00:00:00 2001 From: Alexander Green Date: Fri, 22 Aug 2025 11:36:12 +0200 Subject: [PATCH 04/14] Update sections/designRules.md Co-authored-by: Tim van der Lippe --- sections/designRules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index c77f4f6..f4d8ec1 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -130,7 +130,7 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
Statement
-

All date and time fields in requests and responses MUST be in ISO 8601 format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). Fields in responses MUST be in UTC. Fields in requests MUST allow any time offset, which servers SHOULD normalize to (and store in) UTC.

+

All date and time fields in requests and responses MUST follow [[RFC9557]] and thus be in [[ISO8601]] format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). Fields in responses containing timestamps MUST be in UTC (e.g. Z as offset). APIs MUST accept fields with timestamps with any time offset in requests and servers SHOULD normalize to (and store in) UTC.

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

Rationale
From 00d20c4c791a3655df297509123dbe56c9021126 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 11:20:38 +0200 Subject: [PATCH 05/14] Verwerk feedback op basis van werksessie --- sections/designRules.md | 67 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index f4d8ec1..c2acd82 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -125,18 +125,75 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
-
+## Date and time + +

Use ISO 8601 for date and time formats

Statement
-

All date and time fields in requests and responses MUST follow [[RFC9557]] and thus be in [[ISO8601]] format (e.g., YYYY-MM-DD for dates, YYYY-MM-DDTHH:mm:ssZ for timestamps). Fields in responses containing timestamps MUST be in UTC (e.g. Z as offset). APIs MUST accept fields with timestamps with any time offset in requests and servers SHOULD normalize to (and store in) UTC.

-

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted, stored, and returned.

+

All date, datetime and time fields in requests and responses MUST adhere to [[RFC9557]] and [[ISO8601]] format. Each field in the OpenAPI specification MUST set "type": "string" and set "format" to the OpenAPI format as listed in the following table: + + + + + + + + + + + + + + + + + + + + + + + + + +
Field typeISO8601 formatOpenAPI format
Datefull-date (YYYY-MM-DD)"format": "date"
Datetimedate-time (YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss±hh:mm)"format": "date-time"
Timetime (hh:mm:ss)"format": "time-local"
+

+
Rationale
+
+

Implementing RFC9557 and ISO 8601 in UTC removes ambiguity in date handling between systems and timezones.

+
+
+
+ +
+

Allow all timezones in requests and use UTC in responses

+
+
Statement
+
+

Fields in responses containing timestamps MUST be in UTC (e.g. Z as offset). APIs MUST accept fields with timestamps with any time offset in requests. +

+
Rationale
+
+

TODO +

+
+
+ +
+

Omit time portion for date fields

+
+
Statement
+
+

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted and returned.

Rationale
-

Implementing ISO 8601 in UTC removes ambiguity in date handling between systems and timezones.

-

Inserting a default or irrelevant time can lead to interpretation errors in international contexts. A publish date of 2025-07-24T00:00:00Z could for instance be rendered as July 23 in Ireland. A default time of 23:59 would in turn cause date confusion east of Greenwich.

+

Appending a default or irrelevant time portion to a date field can lead to interpretation errors. A publish date of 2025-07-24T00:00:00Z could for instance be rendered as July 23 in Ireland. A default time of 23:59 would in turn cause date confusion east of Greenwich. +

From 375c4d96564eb5982202fe1513602bdeb54806c1 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 11:42:11 +0200 Subject: [PATCH 06/14] Vul tekst in bij TODOs --- sections/designRules.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index c2acd82..ea73655 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -128,11 +128,11 @@ A resource that corresponds to a single conceptual entity is referred to as a [= ## Date and time
-

Use ISO 8601 for date and time formats

+

Use standard format for date, datetime and time

Statement
-

All date, datetime and time fields in requests and responses MUST adhere to [[RFC9557]] and [[ISO8601]] format. Each field in the OpenAPI specification MUST set "type": "string" and set "format" to the OpenAPI format as listed in the following table: +

All date, datetime and time fields in requests and responses MUST adhere to [[RFC9557]] and [[ISO8601]] format. Each field in the OpenAPI specification MUST set "type": "string" and set "format" to the OpenAPI format as listed in the following table: @@ -172,11 +172,11 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
Statement
-

Fields in responses containing timestamps MUST be in UTC (e.g. Z as offset). APIs MUST accept fields with timestamps with any time offset in requests. +

APIs MUST accept fields with timestamps with any timezone offset in requests. Fields in responses containing timestamps MUST be in UTC (e.g. Z as timezone offset).

Rationale
-

TODO +

Allowing clients to use any timezone offset in requests results in flexibility and less complexity for users. Using UTC in responses results in clarity and removes ambiguity.

@@ -191,13 +191,17 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
Rationale

Appending a default or irrelevant time portion to a date field can lead to interpretation errors. A publish date of 2025-07-24T00:00:00Z could for instance be rendered as July 23 in Ireland. A default time of 23:59 would in turn cause date confusion east of Greenwich. -

+Handling date and time is tricky and can lead to confusion among clients. The date-time rules remove ambiguity and provide clarity in the API contract between servers and clients. + + + ## HTTP methods Although the REST architectural style does not impose a specific protocol, REST APIs are typically implemented using HTTP [[rfc9110]]. From b61be80b05a0a65d0c1832c7cb12517157c46c36 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 11:48:59 +0200 Subject: [PATCH 07/14] Update de bewoording --- sections/designRules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index ea73655..35be616 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -198,7 +198,7 @@ A resource that corresponds to a single conceptual entity is referred to as a [= Handling date and time is tricky and can lead to confusion among clients. The date-time rules remove ambiguity and provide clarity in the API contract between servers and clients. From 89fc8bc05ec6e8076bd7843c534a14f094aeb1e4 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 11:58:50 +0200 Subject: [PATCH 08/14] Zet het voorbeeld voor de regels --- sections/designRules.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index 35be616..236b6ac 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -127,6 +127,13 @@ A resource that corresponds to a single conceptual entity is referred to as a [= ## Date and time +Handling date and time is tricky and can lead to confusion among clients. The date-time rules remove ambiguity and provide clarity in the API contract between servers and clients. + + +

Use standard format for date, datetime and time

@@ -195,13 +202,6 @@ A resource that corresponds to a single conceptual entity is referred to as a [=
-Handling date and time is tricky and can lead to confusion among clients. The date-time rules remove ambiguity and provide clarity in the API contract between servers and clients. - - - ## HTTP methods Although the REST architectural style does not impose a specific protocol, REST APIs are typically implemented using HTTP [[rfc9110]]. From daaefa1b222798638ae2a7a78f6435d524b72a88 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 12:11:31 +0200 Subject: [PATCH 09/14] Update bewoording --- sections/designRules.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index 236b6ac..ee3f3d0 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -175,11 +175,11 @@ Handling date and time is tricky and can lead to confusion among clients. The da
-

Allow all timezones in requests and use UTC in responses

+

Allow all timezone offsets in requests and use UTC in responses

Statement
-

APIs MUST accept fields with timestamps with any timezone offset in requests. Fields in responses containing timestamps MUST be in UTC (e.g. Z as timezone offset). +

APIs MUST accept any timezone offset in fields in requests containing a datetime. Fields in responses containing a datetime MUST be in UTC (e.g. Z as timezone offset).

Rationale
@@ -188,12 +188,12 @@ Handling date and time is tricky and can lead to confusion among clients. The da
-
+

Omit time portion for date fields

Statement
-

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) SHOULD be accepted and returned. +

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) MUST be accepted and returned.

Rationale
From aca3229c654b423fc36757dd6cb94cae7acceacc Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 23 Oct 2025 14:15:47 +0200 Subject: [PATCH 10/14] Update bewoording --- sections/designRules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index ee3f3d0..c812fe1 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -193,7 +193,7 @@ Handling date and time is tricky and can lead to confusion among clients. The da
Statement
-

If the time portion is not relevant, only the date portion (e.g., YYYY-MM-DD) MUST be accepted and returned. +

If the time portion is not relevant, date MUST be used instead of datetime.

Rationale
From b983c0e050518e26c68e10ca7eac4d55f1af47a4 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Wed, 29 Oct 2025 15:32:01 +0100 Subject: [PATCH 11/14] Update zin met time portion Op basis van review feedback. --- sections/designRules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index c812fe1..f4730e3 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -193,7 +193,7 @@ Handling date and time is tricky and can lead to confusion among clients. The da
Statement
-

If the time portion is not relevant, date MUST be used instead of datetime. +

If the time portion is not relevant, date format MUST be used instead of date-time format.

Rationale
From 17737cf07fd2f3d9aefc7ff2a85fa73e94ba845d Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 30 Oct 2025 11:53:52 +0100 Subject: [PATCH 12/14] Voeg noot toe over opslaan van originele timezone --- sections/designRules.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sections/designRules.md b/sections/designRules.md index f4730e3..6575224 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -169,7 +169,7 @@ Handling date and time is tricky and can lead to confusion among clients. The da
Rationale
-

Implementing RFC9557 and ISO 8601 in UTC removes ambiguity in date handling between systems and timezones.

+

Implementing RFC9557 and ISO 8601 removes ambiguity in date handling between systems and timezones.

@@ -184,6 +184,9 @@ Handling date and time is tricky and can lead to confusion among clients. The da
Rationale

Allowing clients to use any timezone offset in requests results in flexibility and less complexity for users. Using UTC in responses results in clarity and removes ambiguity. +

This specification does not state rules regarding storage in databases. + However, it is recommended to store the originally supplied timezone from the client request in the database, such that later the location of the client can be determined. + For example, an extra field in a response can contain the originally supplied timezone, if that's useful for the client.

From a186fe3c1cd47c572ed84a1cd61638a5e68c1ae0 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 30 Oct 2025 14:17:59 +0100 Subject: [PATCH 13/14] Update designRules.md --- sections/designRules.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sections/designRules.md b/sections/designRules.md index 6575224..40b04d3 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -185,8 +185,7 @@ Handling date and time is tricky and can lead to confusion among clients. The da

Allowing clients to use any timezone offset in requests results in flexibility and less complexity for users. Using UTC in responses results in clarity and removes ambiguity.

This specification does not state rules regarding storage in databases. - However, it is recommended to store the originally supplied timezone from the client request in the database, such that later the location of the client can be determined. - For example, an extra field in a response can contain the originally supplied timezone, if that's useful for the client. + However, if the original timezone of a given timestamp value is relevant for users (such as the timezone in which a value is registered), it is recommended to store and publish the timezone details (e.g. the zone offset) as a separate property.

From 8afad816529e2b9a266a6f4e7fc6f725b9ac1717 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Mon, 17 Nov 2025 14:37:59 +0100 Subject: [PATCH 14/14] Voeg linter regels toe voor datum en tijd --- linter/spectral.yml | 50 ++++ linter/testcases/cor-api/expected-output.txt | 51 ++-- .../testcases/date-time/expected-output.txt | 14 ++ linter/testcases/date-time/openapi.json | 238 ++++++++++++++++++ sections/designRules.md | 10 +- 5 files changed, 337 insertions(+), 26 deletions(-) create mode 100644 linter/testcases/date-time/expected-output.txt create mode 100644 linter/testcases/date-time/openapi.json diff --git a/linter/spectral.yml b/linter/spectral.yml index fae4e00..253c6f4 100644 --- a/linter/spectral.yml +++ b/linter/spectral.yml @@ -179,6 +179,56 @@ rules: field: "@key" message: Properties must be lowerCamelCase. + #/core/date-time/timezone + nlgov:date-time-ensure-timezone: + severity: error + given: $..properties[*].format + message: "Use date-time format which includes a timezone" + then: + function: pattern + functionOptions: + notMatch: "/^date-time-local$/" + + nlgov:time-without-timezone: + severity: error + given: $..properties[*].format + message: "Use time-local format without a timezone" + then: + function: pattern + functionOptions: + notMatch: "/^time$/" + + #/core/date-time/date-omit-time-portion + nlgov:specify-format-for-date-and-time: + severity: error + given: + - $..properties[date,datum] + - $..properties[?(@property && @property.match(/((\w+D)|(_[dD]))((ate)|(atum))/))] + message: "Any date field must set 'format' to 'date'" + then: + function: schema + functionOptions: + schema: + anyOf: + - required: ["format"] + - properties: + allOf: + type: array + items: + required: ["format"] + required: ["allOf"] + + nlgov:use-date-instead-of-datetime: + severity: error + given: + - $..properties[date,datum]..format + - $..properties[?(@property && @property.match(/((\w+D)|(_[dD]))((ate)|(atum))/))]..format + message: "Field represents a date and therefore must set 'format' to 'date'" + then: + function: pattern + functionOptions: + notMatch: "/^date-time$/" + nlgov:semver: severity: error message: "Version {{value}} is not in semver format." diff --git a/linter/testcases/cor-api/expected-output.txt b/linter/testcases/cor-api/expected-output.txt index 5c46649..6743309 100644 --- a/linter/testcases/cor-api/expected-output.txt +++ b/linter/testcases/cor-api/expected-output.txt @@ -1,28 +1,29 @@ /testcases/cor-api/openapi.json - 70:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./heartbeat.get.responses[429].content - 80:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./heartbeat.get.responses[503].content - 181:29 warning nlgov:paths-kebab-case /laatsteWijziging is not kebab-case. paths./laatsteWijziging - 211:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[400].content - 221:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[404].content - 231:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[405].content - 241:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[406].content - 251:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[429].content - 261:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[500].content - 271:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[503].content - 506:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[400].content - 516:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[404].content - 526:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[405].content - 536:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[406].content - 546:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[429].content - 556:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[500].content - 566:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[503].content - 684:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[400].content - 694:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[404].content - 704:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[405].content - 714:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[406].content - 724:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[429].content - 734:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[500].content - 744:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[503].content + 70:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./heartbeat.get.responses[429].content + 80:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./heartbeat.get.responses[503].content + 181:29 warning nlgov:paths-kebab-case /laatsteWijziging is not kebab-case. paths./laatsteWijziging + 211:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[400].content + 221:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[404].content + 231:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[405].content + 241:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[406].content + 251:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[429].content + 261:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[500].content + 271:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./laatsteWijziging.get.responses[503].content + 506:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[400].content + 516:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[404].content + 526:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[405].content + 536:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[406].content + 546:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[429].content + 556:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[500].content + 566:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties.get.responses[503].content + 684:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[400].content + 694:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[404].content + 704:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[405].content + 714:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[406].content + 724:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[429].content + 734:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[500].content + 744:35 warning nlgov:use-problem-schema The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457. paths./organisaties/{oin}.get.responses[503].content + 978:27 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' components.schemas.LocalDateTime.format -✖ 24 problems (0 errors, 24 warnings, 0 infos, 0 hints) +✖ 25 problems (1 error, 24 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/date-time/expected-output.txt b/linter/testcases/date-time/expected-output.txt new file mode 100644 index 0000000..6a3cdc8 --- /dev/null +++ b/linter/testcases/date-time/expected-output.txt @@ -0,0 +1,14 @@ + +/testcases/date-time/openapi.json + 94:55 error nlgov:date-time-ensure-timezone Use date-time format which includes a timezone paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.date-time-local.format + 98:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.date.format + 102:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.datum.format + 106:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.geboorteDatum.format + 110:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.birthDate.format + 114:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.expiration_date.format + 118:55 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.expiration_Date.format + 122:55 error nlgov:time-without-timezone Use time-local format without a timezone paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.timestamp.format + 124:61 error nlgov:specify-format-for-date-and-time Any date field must set 'format' to 'date' paths./resources-with-time-incorrect.get.responses[200].content.application/json.schema.properties.missingFormatDate + 218:27 error nlgov:use-date-instead-of-datetime Field represents a date and therefore must set 'format' to 'date' components.schemas.LocalDateTimeIncorrect.format + +✖ 10 problems (10 errors, 0 warnings, 0 infos, 0 hints) diff --git a/linter/testcases/date-time/openapi.json b/linter/testcases/date-time/openapi.json new file mode 100644 index 0000000..6a4349b --- /dev/null +++ b/linter/testcases/date-time/openapi.json @@ -0,0 +1,238 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Baseline", + "description": "Deze OpenAPI specification bevat het minimale om aan alle regels te voldoen.", + "contact": { + "name": "Beheerder", + "url": "https://www.example.com", + "email": "mail@example.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://example.com/api/v1" + } + ], + "security": [ + { + "default": [] + } + ], + "tags": [ + { + "name": "openapi" + }, + { + "name": "time" + } + ], + "paths": { + "/openapi.json": { + "get": { + "tags": [ + "openapi" + ], + "description": "OpenAPI document", + "operationId": "getOpenapiJSON", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + }, + "access-control-allow-origin": { + "description": "Alle origins mogen bij deze resource", + "schema": { + "type": "string" + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + }, + "/resources-with-time-incorrect": { + "get": { + "tags": [ + "time" + ], + "description": "Resources with time incorrect", + "operationId": "getResourcesIncorrect", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "date-time-local": { + "type": "string", + "format": "date-time-local" + }, + "date": { + "type": "string", + "format": "date-time" + }, + "datum": { + "type": "string", + "format": "date-time" + }, + "geboorteDatum": { + "type": "string", + "format": "date-time" + }, + "birthDate": { + "type": "string", + "format": "date-time" + }, + "expiration_date": { + "type": "string", + "format": "date-time" + }, + "expiration_Date": { + "type": "string", + "format": "date-time" + }, + "timestamp": { + "type": "string", + "format": "time" + }, + "missingFormatDate": { + "nullable": true + }, + "meerdereDatum": { + "type": "string", + "allOf": [ + { + "$ref": "#/components/schemas/LocalDateTimeIncorrect" + } + ] + } + } + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + }, + "/resources-with-time-correct": { + "get": { + "tags": [ + "time" + ], + "description": "Resources with time correct", + "operationId": "getResourcesCorrect", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De huidige versie van de applicatie", + "style": "simple", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date" + }, + "datum": { + "type": "string", + "format": "date" + }, + "geboorteDatum": { + "type": "string", + "format": "date" + }, + "birthDate": { + "type": "string", + "format": "date" + }, + "timestamp": { + "type": "string", + "format": "time-local" + }, + "meerdereDatum": { + "type": "string", + "allOf": [ + { + "$ref": "#/components/schemas/LocalDateTimeCorrect" + } + ] + } + } + } + } + } + } + }, + "security": [ + { + "default": [] + } + ] + } + } + }, + "components": { + "schemas": { + "LocalDateTimeIncorrect": { + "format": "date-time", + "type": "string" + }, + "LocalDateTimeCorrect": { + "format": "date", + "type": "string" + } + }, + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": {} + } + } + } + } + } +} \ No newline at end of file diff --git a/sections/designRules.md b/sections/designRules.md index 40b04d3..0059c7e 100644 --- a/sections/designRules.md +++ b/sections/designRules.md @@ -171,10 +171,14 @@ Handling date and time is tricky and can lead to confusion among clients. The da

Implementing RFC9557 and ISO 8601 removes ambiguity in date handling between systems and timezones.

+
How to test
+
+ Analyse all fields and if the field represents a date, date-time or time, ensure it has the correct format according to the table above. +
-
+

Allow all timezone offsets in requests and use UTC in responses

Statement
@@ -201,6 +205,10 @@ Handling date and time is tricky and can lead to confusion among clients. The da

Appending a default or irrelevant time portion to a date field can lead to interpretation errors. A publish date of 2025-07-24T00:00:00Z could for instance be rendered as July 23 in Ireland. A default time of 23:59 would in turn cause date confusion east of Greenwich.

+
How to test
+
+ Analyse all fields that set format to "date-time" and ensure that the fields do not represent solely a date. +