ConceptsDates and time zones
Dates and time zones
Date and date-time fields, the space REST writes between date and time, and the Timezone header that returns date-times in your own zone.
Answer
Date fields are YYYY-MM-DD. Date-times come back in UTC with an offset, with a space between date and time in REST and a T in GraphQL. Send a Timezone header, such as Europe/Bratislava, to get them in that zone. Values you send without an offset are read as UTC, whatever the header says.
Two kinds of field hold time. Date fields hold a day; date-time fields hold an instant, which the API writes in UTC unless you ask for your own time zone.
Date and date-time fields
| Kind | Example field | REST | GraphQL |
|---|---|---|---|
| Date | closing_ (shown in the app as Closing date) |
2026-12-15 |
2026-12-15 |
| Date-time | created, modified |
2026-10-15 09:00:00. |
2026-10-15T09:00:00. |
- REST writes a space between the date and the time; GraphQL writes a
T. A parser that insists on RFC 3339'sTfails on REST values: replace the space withTbefore you parse. - Date-times carry microseconds and an offset,
+00:00unless you send aTimezoneheader. - A date field has no time and no zone; the
Timezoneheader does not change it.
Read date-times in your time zone
Send a Timezone header and every date-time in the response comes back in that zone, with its
offset. The sample reads one opportunity twice, without the header and with
Timezone: Europe/Bratislava:
COEVERA_BASE="https://{region}.api.coevera.com/api/v100/rest/spaces/{space_id}"
# No Timezone header: created and modified come back in UTC.
curl -sS --fail-with-body -G "$COEVERA_BASE/entities/Opportunities" \
-d "filter[closing_date]=2026-12-15" \
-d load-only=name,closing_date,created,modified \
-d first=1 \
-u "$COEVERA_API_KEY:$COEVERA_API_SECRET"
echo
# The same request with a Timezone header: the same instants, in that zone's offset.
curl -sS --fail-with-body -G "$COEVERA_BASE/entities/Opportunities" \
-H "Timezone: Europe/Bratislava" \
-d "filter[closing_date]=2026-12-15" \
-d load-only=name,closing_date,created,modified \
-d first=1 \
-u "$COEVERA_API_KEY:$COEVERA_API_SECRET"
echoimport { Buffer } from "node:buffer";
import { env } from "node:process";
const base = `https://{region}.api.coevera.com/api/v100/rest/spaces/{space_id}`;
const auth = Buffer.from(`${env.COEVERA_API_KEY}:${env.COEVERA_API_SECRET}`).toString("base64");
// The opportunity that closes on 2026-12-15, with its date and its two date-times.
const query = "filter[closing_date]=2026-12-15&load-only=name,closing_date,created,modified&first=1";
async function opportunities(headers: Record<string, string>) {
const res = await fetch(`${base}/entities/Opportunities?${query}`, {
headers: { Authorization: `Basic ${auth}`, ...headers },
});
const body = await res.json();
if (!res.ok) throw new Error(`HTTP ${res.status} ${body.name}: ${body.message}`);
return body.data;
}
// No Timezone header: created and modified come back in UTC.
console.log("UTC:", JSON.stringify(await opportunities({}), null, 2));
// The same request with a Timezone header: the same instants, in that zone's offset.
console.log("Europe/Bratislava:", JSON.stringify(await opportunities({ Timezone: "Europe/Bratislava" }), null, 2));import json
import os
import sys
import requests
BASE = "https://{region}.api.coevera.com/api/v100/rest/spaces/{space_id}"
session = requests.Session()
session.auth = (os.environ["COEVERA_API_KEY"], os.environ["COEVERA_API_SECRET"])
# The opportunity that closes on 2026-12-15, with its date and its two date-times.
QUERY = "filter[closing_date]=2026-12-15&load-only=name,closing_date,created,modified&first=1"
def opportunities(headers):
response = session.get(f"{BASE}/entities/Opportunities?{QUERY}", headers=headers, timeout=30)
body = response.json()
if not response.ok:
sys.exit(f"HTTP {response.status_code} {body.get('name')}: {body.get('message')}")
return body["data"]
# No Timezone header: created and modified come back in UTC.
print("UTC:", json.dumps(opportunities({}), indent=2))
# The same request with a Timezone header: the same instants, in that zone's offset.
print("Europe/Bratislava:", json.dumps(opportunities({"Timezone": "Europe/Bratislava"}), indent=2))COEVERA_GRAPHQL="https://{region}.api.coevera.com/api/v100/app/space/{space_id}/graphql/public"
# The opportunity, with its date and its two date-times.
QUERY='{"query": "{ entities { opportunity { getByCriteria(first: 1, filter: { name: { icontains: [\"data platform rollout\"] } }) { edges { node { name closingDate created modified } } } } } }"}'
# No Timezone header: created and modified come back in UTC.
curl -sS --fail-with-body "$COEVERA_GRAPHQL" \
-u "$COEVERA_API_KEY:$COEVERA_API_SECRET" \
-H "Content-Type: application/json" \
-d "$QUERY"
echo
# The same request with a Timezone header: the same instants, in that zone's offset.
curl -sS --fail-with-body "$COEVERA_GRAPHQL" \
-u "$COEVERA_API_KEY:$COEVERA_API_SECRET" \
-H "Content-Type: application/json" \
-H "Timezone: Europe/Bratislava" \
-d "$QUERY"
echoimport { Buffer } from "node:buffer";
import { env } from "node:process";
const endpoint = `https://{region}.api.coevera.com/api/v100/app/space/{space_id}/graphql/public`;
const auth = Buffer.from(`${env.COEVERA_API_KEY}:${env.COEVERA_API_SECRET}`).toString("base64");
// The opportunity, with its date and its two date-times.
const OPPORTUNITY = `{
entities {
opportunity {
getByCriteria(first: 1, filter: { name: { icontains: ["data platform rollout"] } }) {
edges { node { name closingDate created modified } }
}
}
}
}`;
async function opportunities(headers: Record<string, string>) {
const res = await fetch(endpoint, {
method: "POST",
headers: { Authorization: `Basic ${auth}`, "Content-Type": "application/json", ...headers },
body: JSON.stringify({ query: OPPORTUNITY }),
});
const body = await res.json();
// GraphQL reports errors in the body, often with HTTP 200: check both.
if (!res.ok || body.errors) throw new Error(`HTTP ${res.status}: ${JSON.stringify(body.errors ?? body)}`);
return body.data.entities.opportunity.getByCriteria.edges;
}
// No Timezone header: created and modified come back in UTC.
console.log("UTC:", JSON.stringify(await opportunities({}), null, 2));
// The same request with a Timezone header: the same instants, in that zone's offset.
console.log("Europe/Bratislava:", JSON.stringify(await opportunities({ Timezone: "Europe/Bratislava" }), null, 2));import json
import os
import sys
import requests
ENDPOINT = (
"https://{region}.api.coevera.com/api/v100/app/space/"
"{space_id}/graphql/public"
)
AUTH = (os.environ["COEVERA_API_KEY"], os.environ["COEVERA_API_SECRET"])
# The opportunity, with its date and its two date-times.
OPPORTUNITY = """
{
entities {
opportunity {
getByCriteria(first: 1, filter: { name: { icontains: ["data platform rollout"] } }) {
edges { node { name closingDate created modified } }
}
}
}
}
"""
def opportunities(headers):
response = requests.post(ENDPOINT, json={"query": OPPORTUNITY}, auth=AUTH, headers=headers, timeout=30)
body = response.json()
# GraphQL reports errors in the body, often with HTTP 200: check both.
if not response.ok or body.get("errors"):
sys.exit(f"HTTP {response.status_code}: {json.dumps(body.get('errors', body))}")
return body["data"]["entities"]["opportunity"]["getByCriteria"]["edges"]
# No Timezone header: created and modified come back in UTC.
print("UTC:", json.dumps(opportunities({}), indent=2))
# The same request with a Timezone header: the same instants, in that zone's offset.
print("Europe/Bratislava:", json.dumps(opportunities({"Timezone": "Europe/Bratislava"}), indent=2))Without the header, created is in UTC:
{
"success": true,
"total": 1,
"page_info": {
"start_cursor": "WyIwMDAwMDAwMC0wMDAwLTQwMDAtYTAwMC0wMDAwMDAwMDAwMDEiXQ==",
"end_cursor": "WyIwMDAwMDAwMC0wMDAwLTQwMDAtYTAwMC0wMDAwMDAwMDAwMDEiXQ==",
"has_previous_page": false,
"has_next_page": false
},
"data": [
{
"modified": "2026-10-15 09:41:21.513848+00:00",
"created": "2026-10-15 09:00:00.000000+00:00",
"closing_date": "2026-12-15",
"name": "Northwind data platform rollout"
}
]
}{
"data": {
"entities": {
"opportunity": {
"getByCriteria": {
"edges": [
{
"node": {
"name": "Northwind data platform rollout",
"closingDate": "2026-12-15",
"created": "2026-10-15T09:00:00.000000+00:00",
"modified": "2026-10-15T09:41:21.513848+00:00"
}
}
]
}
}
}
}
}With it, the same instant comes back at +02:00, the offset Bratislava had on the day of the
recording; closing_date is unchanged:
{
"success": true,
"total": 1,
"page_info": {
"start_cursor": "WyIwMDAwMDAwMC0wMDAwLTQwMDAtYTAwMC0wMDAwMDAwMDAwMDEiXQ==",
"end_cursor": "WyIwMDAwMDAwMC0wMDAwLTQwMDAtYTAwMC0wMDAwMDAwMDAwMDEiXQ==",
"has_previous_page": false,
"has_next_page": false
},
"data": [
{
"modified": "2026-10-15 11:41:21.513848+02:00",
"created": "2026-10-15 11:00:00.000000+02:00",
"closing_date": "2026-12-15",
"name": "Northwind data platform rollout"
}
]
}{
"data": {
"entities": {
"opportunity": {
"getByCriteria": {
"edges": [
{
"node": {
"name": "Northwind data platform rollout",
"closingDate": "2026-12-15",
"created": "2026-10-15T11:00:00.000000+02:00",
"modified": "2026-10-15T11:41:21.513848+02:00"
}
}
]
}
}
}
}
}The header takes these forms:
| Form | Example | Offset on 2026-10-15 |
|---|---|---|
| IANA zone name | Europe/, America/ |
+02:00, -04:00: daylight saving applies |
| Windows zone name | Central Europe Standard Time |
+02:00 |
UTC or GMT with an offset |
UTC+2, UTC-03:30, GMT-5 |
+02:00, -03:30, -05:00 |
| Minutes east of UTC | 60 |
+01:00 |
UTC |
UTC |
+00:00 |
A one-word abbreviation such as CET, or a name the API does not know, is ignored without an
error: the response stays in UTC. GraphQL honours the header too.
Send date-times
- A date-time you send without an offset is read as UTC, even when you send a
Timezoneheader.filter[created]=2026-10-15 05:06:36withTimezone: Europe/Bratislavameans05:06:36in UTC, not in Bratislava. Send an offset,2026-10-15T07:06:36+02:00, or convert to UTC first. - Filters accept a space or a
Tbetween date and time, and a date alone on a date-time field:filter[created]=2026-10-15&filter-op[created]=gte. - Filter a date field with
YYYY-MM-DD:filter[closing_date]=2026-12-15. GraphQL has no filter onclosingDate. createdandmodifiedcan be set on create, for example when you import records with their original dates; the values you send are stored. A value more than one day after the time of the request, on a create or an update, is ignored: the write succeeds and the field is set as if you had not sent it. To store such a value, addvalidation-levelbit 8 (validation).
Limits
| Limit | Details |
|---|---|
| Zone abbreviations | CET, EST and other one-word names are ignored; use an IANA name |
| Input without an offset | Read as UTC, whatever the Timezone header says |
| Separator | REST writes a space, GraphQL a T |
| Date fields | No zone; the header does not apply |
created, modified in the future |
More than one day ahead is ignored on write, unless validation-level has bit 8 |