AIP-142

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.

Guidance

Fields representing time should use the common, generally used components (such as google.protobuf.Timestamp or google.type.Date) for representing time or duration types. These types are common components, and using them consistently allows infrastructure and tooling to provide a better experience when interacting with time values.

Timestamps

Fields that represent an absolute point in time (independent of any time zone or calendar) should use the google.protobuf.Timestamp type, (which uses UNIX timestamps under the hood and hold nanosecond precision).

These fields should have names ending in _time, such as create_time or update_time.

Many timestamp fields refer to an activity (for example, create_time refers to when the applicable resource was created). For these, the field should be named with the {imperative}_time form. For example, if a book is being published, the field storing the time when this happens would use the imperative form of the verb “to publish” (“publish”) resulting in a field called publish_time. Fields should not be named using the past tense (such as published_time, created_time or last_updated_time).

Durations

Fields that represent a span between two points in time (independent of any time zone or calendar) should use the google.protobuf.Duration type.

To illustrate the distinction between timestamps and durations, consider a flight record:

// A representation of a (very incomplete) flight log.
message FlightRecord {
  // The absolute point in time when the plane took off.
  google.protobuf.Timestamp takeoff_time = 1;

  // The length (duration) of the flight, from takeoff to landing.
  google.protobuf.Duration flight_duration = 2;
}

Note: Observant readers may notice that the timestamp and duration messages have the same structure (int64 seconds and int32 nanos). However, the distinction between these is important, because they have different semantic meaning. Additionally, tooling is able to base behavior off of which message is used. For example, a Python-based tool could convert timestamps to datetime objects and durations to timedelta objects.

Relative time segments

In some cases, it may be necessary to represent a time segment inside a stream. In these cases, the google.protobuf.Duration type should be used, and the field name should end with _offset. To ensure that the meaning is clear, the field must have a comment noting the point that the offset is relative to.

To illustrate this, consider a resource representing a segment of an audio stream:

message AudioSegment {
  // The duration relative to the start of the stream representing the
  // beginning of the segment.
  google.protobuf.Duration start_offset = 1;
  
  // The total length of the segment.
  google.protobuf.Duration segment_duration = 2;
}

Civil dates and times

Fields that represent a calendar date or wall-clock time should use the appropriate common components:

Fields representing civil dates should have names ending in _date, while fields representing civil times or datetimes should have names ending in _time.

Note: Both the Date and TimeOfDay components are timezone-naïve. Fields that require timezone-awareness should use DateTime (see below).

Civil timestamps

Fields that represent a civil timestamp (date and time, optionally with a time zone) should use the google.type.DateTime component, and the field name should end in _time.

Compatibility

Occasionally, APIs are unable to use the common structures for legacy or compatibility reasons. For example, an API may conform to a separate specification that mandates that timestamps be integers or ISO-8601 strings.

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

  • For 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, send_time_millis.
  • 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.