Skip to content

Time and duration

Many services need to represent the concepts surrounding time. Representing time can be challenging due to the intricacies of calendars and time zones, as well as the fact that common exchange formats (such as JSON) lack a native concept of time.

Fields representing time must use a string field with values conforming to RFC 3339, such as 2012-04-21T15:00:00Z.

Services must use appropriate OpenAPI format indicators for all date and time fields.

Fields that represent an absolute point in time must use a string field with RFC 3339 values. In OpenAPI, these fields must use type: string with format: date-time.

These values must include an explicit timezone offset (Z or ±hh:mm). Services should default to UTC (Z) for timestamps unless preserving the original offset is semantically meaningful for the business use case (such as scheduling or local audit trails). Timestamps must not include non-standard language-specific suffixes in the JSON string, such as the Java [America/New_York] suffix. If a specific IANA timezone ID is required, it must be provided in a separate field, such as timeZone.

These fields should have names ending in Time, such as createdTime or expireTime. For array fields, the names should end in Times.

To maintain consistency with metadata fields like createdBy and updatedBy, the fields createdTime, updatedTime, and deletedTime must use the past tense. For all other timestamps, the field may be named using either the root form of the verb (such as expireTime or publishTime) or the past tense (such as completedTime), depending on which best conveys the field’s intent.

Example:

Book:
type: object
properties:
createdTime:
type: string
format: date-time
readOnly: true
example: '2025-12-18T10:00:00Z'
publishTime:
type: string
format: date-time
description: 'The scheduled time for the book to become available.'
example: '2025-12-25T09:00:00-05:00'

Fields that represent a span between two points in time should be represented as explicit start and end timestamps, such as startTime and endTime.

If a single duration value better fits the use case, services should use an int field representing a numeric count of a specific unit. The unit of measurement must be explicitly included as a suffix in the field name, such as durationSeconds, retryIntervalMillis, or ttlSeconds.

Services should not use ISO 8601 duration strings (such as PT1H) unless required by an external specification or for compatibility with a specific library.

Example:

Session:
type: object
properties:
startTime:
type: string
format: date-time
endTime:
type: string
format: date-time
ttlSeconds:
type: integer
description: 'Remaining time before session expires.'
example: 3600

Services may support fractional seconds for both timestamps and durations, but should not support precision more granular than the nanosecond. Services may also limit the supported precision, and may truncate values received from the user to the supported precision.

Fields that represent a calendar date independent of a specific time (such as a birthday) should use the YYYY-MM-DD format. In OpenAPI, these fields must use type: string with format: date. These fields should have names ending in Date, such as birthDate.

Fields that represent a “wall-clock” time independent of a specific date (such as an opening hour) should use the hh:mm:ss format. To distinguish these from absolute timestamps, these fields should have names ending in TimeOfDay, such as openingTimeOfDay.

Example:

Store:
type: object
properties:
openingDate:
type: string
format: date
example: '2025-06-01'
openingTimeOfDay:
type: string
pattern: '^[0-9]{2}:[0-9]{2}:[0-9]{2}$'
example: '09:00:00'

A service that needs to document a recurring event should use cronspec if cronspec is able to support the service’s use case.

Occasionally, APIs are unable to use RFC 3339 strings for legacy or compatibility reasons. For example, an API may conform to a separate specification that mandates that timestamps be Unix timestamp integers.

In these situations, fields may use other types. If possible, the following naming conventions apply:

  • Unix timestamps should use a UnixTime suffix.
    • Multipliers of Unix time (such as milliseconds) should not be used; if they are unavoidable, the field name should use both UnixTime and the unit, such as unixTimeMillis.
  • For other integers, include the meaning (examples: time, duration, delay, latency) and the unit of measurement (valid values: seconds, millis, micros, nanos) as a final suffix. For example, sendTimeMillis.
  • For strings, include the meaning (examples: time, duration, delay, latency) but no unit suffix.

In all cases, clearly document the expected format, and the rationale for its use.

Why avoid ISO 8601 duration?

This is to maximize developer productivity and ensure cross-platform predictability. While ISO 8601 strings are syntactically standard, they lack native parsing support in many common environments; notably modern web browsers and standard Go or Python libraries. This often requires additional third-party dependencies to handle. Furthermore, units like “months” or “years” within these strings introduce calendar ambiguity that can lead to calculation errors across client-server boundaries. By prioritizing explicit startTime/endTime pairs or unit-suffixed integers (e.g., durationSeconds), the API provides immediate clarity and allows developers to perform mathematical operations using native numeric types without the overhead of complex string parsing.

2025-12-02: Initial creation, adapted from Google AIP-142 and aep.dev AEP-142.