Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  1. Dates that represent an instant in time - timezone applies. In this document, these will be referred to as instant dates.
    1. An example here would be the submitted date field of a requisition. This is the specific point in time where the requisition was submitted for authorization/approval.
  2. Dates that represent an instant in time only after appropriate timezone is added - In this document, these will be referred to as business dates.
    1. An example here would be the start date of a programprocessing period. This is a date that represents when a program processing period was started. It only becomes an instant in time when an appropriate timezone is added (in this case, an implementation's default timezone).

...

Since we are currently using Postgres as our backend database, Postgres' timestamp with time zone data type should be used for instant dates, and text data type for business dates.

Java

...

Backend Code

Java 8's ZonedDateTime should be used when dealing with instant dates (and generally be in UTC), and LocalDate LocalDateTime should be used when dealing with business dates.

...

  • Dates should be serialized into a ISO-8601 formatted string. This is because when Jackson serializes date classes, it turns them into an array of values, which is not as useful or readable.
  • Instant dates should return a timestamp string with timezone UTC.
  • Business dates should return a timestamp string with an appropriate timezone. Rough steps to add the appropriate timezone (this is to avoid using a default timezone from LocalDateLocalDateTime):
    1. Make a "best guess" about the timezone to use.
      1. If the API call is respective to a user, use the timezone in the user's profile.
      2. If respective to a facility, use the facility's timezone (Note: this would be a new feature, as facility timezone profiles were not in v2).
      3. If neither, use an implementation default timezone (some configuration setting in the system).
    2. Create a new ZonedDateTime with the business date and the "best guess" timezone, and serialize that in the API response.

During deserialization (when dates are provided by a client to an API call):

  • Instant dates should be in timezone UTC, which would deserialize into a ZonedDateTime object. If it is not in UTC, it would be "translated" into UTC.
  • Business dates should not have timezone information, and would deserialize into a LocalDate LocalDateTime object.

Frontend Client

...

(i.e. AngularJS UI)

Clients using API calls to display timestamps to user

...

  • For instant dates, the client should send timestamps in UTC timezone.
  • For business dates, the client should send timestamps with no timezone information.

Example 1: Instant Date

The example used here is the submitted date of a requisition.

  • Persistent Storage - in the requisitions table, there would be a submitteddate column of type timestamp with time zone.
  • Java Backend Code - in the Requisition object, there would be a submittedDate field of class ZonedDateTime. This field would store a timestamp with UTC timezone. If somehow it was not in UTC timezone, it would be saved in UTC to the database (using the ZonedDateTimeAttributeConverter).
  • API Interface
    • Serialization: since it is already in UTC timezone, it would simply be converted into a String of ISO-8601 format, then returned in the response. (This conversion would probably be done in the DTO).
    • Deserialization: convert the String into a ZonedDateTime object. If it is not in UTC timezone, create a UTC version of it. This is what is assigned to submittedDate.
  • Frontend Client
    • When displaying to the user, change the UTC timestamp into "local" time.
    • When calling the APIs, make sure timestamp is in UTC timezone.

Example 2: Business Date

The example used here is the start date of a processing period.

  • Persistent Storage - in the processing_periods table, there would be a startdate column of type text.
  • Java Backend Code - in the ProcessingPeriod object, there would be a startDate field of class LocalDateTime. When persisting, startDate would have UTC added and be converted into a string (to match the text type). When retrieving, the a ZonedDateTime object would be created based on the string from the database, then converted into LocalDateTime, which is then used for startDate.
  • API Interface
    • Serialization: the "best guess" timezone would be determined first. In this case, it would be the implementation default time zone. (If the facility had a timezone profile, that would be used instead.) A new ZonedDateTime object would be created using startDate and the implementation default timezone. This would be converted into a String of ISO-8601 format, then returned in the response.
    • Deserialization: convert the String into a LocalDateTime object. This is what is assigned to startDate.
  • Frontend Client
    • When displaying to the user, use the timestamp as-is.
    • When calling the APIs, make sure timestamp does not have timezone information.

Appendix: Survey of Usage

...