PhoenixmlDb
Dates and Times
PhoeniXML DB uses UTC; the date-time forms it accepts, API key expiry, value indexes on dates, and embedded hosts
#Dates and Times
PhoeniXML DB uses UTC. A date-time without a timezone is UTC wherever the engine stores, indexes or
compares it. A value written with a timezone (Z, +02:00) keeps its instant; write an offset to
mean another zone. There is no time-zone setting.
|
gRPC server, EPS REST server |
Embedded engine |
|
|---|---|---|
|
Typed dateTime metadata, value-index keys, JSON index keys |
UTC |
UTC |
|
API key |
UTC |
not applicable |
|
Comparison in a query or stylesheet ( |
UTC |
UTC |
In both servers and in the embedded engine implicit-timezone() is PT0S, and
xs:dateTime('1996-12-12T13:13:00') < xs:dateTime('1996-12-12T13:13:00-02:00') is true, whatever
the time zone of the machine or of the host process. The engine gives UTC to every query engine and
XSLT transformer it makes (DocumentDatabase.ImplicitTimezone). A stylesheet's static expressions
(use-when, static parameters and variables) are in UTC too.
A server process runs in UTC: it sets the TZ environment variable of its own process to UTC at
startup. Console log timestamps, when turned on without UseUtcTimestamp, are UTC. A configuration key
PhoenixmlDb:Query:ImplicitTimezone is ignored; the server starts and lists it in the
effective-configuration event (3001).
#What is read as a date-time
Typed dateTime metadata, dateTime value-index keys and API key Expires accept these forms and
nothing else:
|
Form |
Example |
Read as |
|---|---|---|
|
|
|
that day at 00:00:00 UTC |
|
|
|
UTC when no timezone is written |
|
the same with a space in place of |
|
the same |
|
RFC 1123 |
|
that instant |
The year has four digits (0001 to 9999). Seconds are required. A fraction has any number of digits and is kept to 100 nanoseconds. Leading and trailing white space is ignored.
Refused, among others: a time with no date (12:00:00), a date with no year (1/15,
January 15), a year and month (2024-01), a two-digit year (1/15/24), 01/15/2024,
2024/01/15, 2024-1-5, 2024-01-15T12:00 (no seconds), 2024-01-15T12:00:00+0100,
2024-01-15T12:00:00+01, a lower-case t or z, 2024-01-15Z, and seconds since 1970.
A refused text:
-
as typed dateTime metadata: the request is refused with the metadata validation error;
-
in a document, at a path with a dateTime value index: the document is stored and that value has no index key;
-
as an API key
Expires: startup stops, naming the entry.
An xs:date in typed metadata or at a path with a date value index is yyyy-MM-dd (white space
around it ignored); any other text is refused as metadata and has no index key. An xs:date or
xs:time value that carries a timezone is refused as typed metadata and has no index key.
#API key expiry
PhoenixmlDb:Auth:ApiKeys:<n>:Expires (gRPC server) and Auth:ApiKey:Clients:<n>:Expires (EPS REST
server):
-
Text in one of the forms above. Without a timezone it is UTC:
2027-01-31is 2027-01-31T00:00:00Z. -
Absent: the key does not expire.
-
Empty, blank or not in one of the forms: startup stops with a message naming the entry. In the EPS REST server such an entry is also never valid when a request presents its key.
-
In the options classes
ApiKeyOptions.Expires(gRPC server) andApiKeyClientConfig.Expires(EPS) the property isstring?.
#Startup log
|
Event |
Level |
Text |
|---|---|---|
|
3010 |
Information |
|
|
3011 |
Warning |
Windows only, when the machine's time zone is not UTC (below): |
For each API key with an expiry still ahead, one Information line gives the instant in UTC, the entry
and its Id, for example
PhoenixmlDb:Auth:ApiKeys:0 (Id 'svc') expires at 2026-12-31T00:00:00.0000000+00:00. (gRPC server) or
Auth:ApiKey:Clients:0 (Id 'svc') expires at 2026-12-31T00:00:00.0000000+00:00. (EPS). A key already
expired has a warning with expired at and the instant in UTC. The effective-configuration event
(3001) shows Expires as configured.
#Value indexes on dates and times
A value index of type xs:dateTime, xs:date or xs:time answers one comparison: equality between
the attribute and a string literal that is a value of the index's type, for example
/order[@at = '2024-01-15T12:00:00']. That comparison is of text: it returns the rows whose attribute
has exactly that text.
Every other comparison on those index types is answered by a scan, with the same result as on a container that has no index:
-
a comparison with a typed value:
@at = xs:dateTime('…'),<,>=; -
a comparison with a variable, of any type:
let $x := … return /order[@at = $x], an external$v; -
a range with a string:
@at >= '2024-01-15T12:00:00Z'; -
a string literal that is not a value of the index's type:
@day = '2024-01-15Z'.
For every index type, a string literal that is not a value of the index's type is answered by a scan.
An external variable that holds a CLR DateTimeOffset is compared as text by the XQuery library.
The index writer reads numbers and dates with the invariant culture. A value index must be rebuilt when it was built on a machine whose time zone was not UTC (date-time values without a timezone), or on a machine whose regional settings were not English/invariant (numbers and dates). Nothing detects such an index. The rebuild operations:
|
Host |
Operation |
|---|---|
|
EPS REST server |
|
|
gRPC server |
|
|
Embedded |
|
Typed dateTime metadata is stored as an instant. A value stored earlier keeps its instant; a rebuild does not change it.
#Embedded engine in a host that is not in UTC
The embedded engine does not change the time zone of its host process. Its queries are in UTC all
the same. With rows a 2024-01-15T12:00:00 and b 2024-01-15T12:00:00Z, in a host in
America/New_York or Pacific/Kiritimati:
|
Answer |
|
|---|---|
|
|
a, b |
|
|
a, b |
|
metadata query for |
a, b |
|
|
|
|
|
by instant, no timezone read as UTC |
A query gives the same answer in such a host as in a UTC process, whether it is evaluated once per document or once over the container (Documents & Storage).
An application that runs its own XsltTransformer with the database's stylesheet policy sets
ImplicitTimezone itself, to DocumentDatabase.ImplicitTimezone. Without it the library takes the
zone of the host.
#Windows
On Windows a process cannot set its own time zone. A server on a Windows machine whose time zone is
UTC logs event 3010. On a machine in another zone it logs warning 3011 and starts. Queries and
stylesheets are in UTC there as elsewhere: the engine gives each query engine and transformer UTC as
its implicit timezone, whatever the zone of the process. What is stored, indexed and read from
configuration is UTC on Windows as elsewhere. Times the process takes from the local clock, such as
console log timestamps without UseUtcTimestamp, are in the machine's zone. Set the machine's time
zone to UTC.
See also: Metadata · Indexing · Server Mode · Logging and Telemetry