Skip to content

Multi Time Zone Environment

jhou-pro edited this page May 15, 2024 · 24 revisions

Overview

When developing TG applications we [currently] use Date and Joda-Time DateTime for manipulating dates (e.g. to create now moment we may write new Date() or new DateTime() expression).

If we just need to persist date or to compare two dates it is perfectly okay to use java.util.Date class and its before/after methods for that. Things get more nuanced when we need to do some time-zone dependent manipulations:

  1. get day start or some concrete hour of the day (e.g. 8 PM)
  2. show human-readable (toString) date representation
  3. midnight moment before now
  4. 3 AM moment to perform some job

We need to always remember "In which time-zone?" question before making these manipulations. Currently, we create Joda-Time org.joda.time.DateTime time-zone-aware instance and then use its methods to perform such manipulations.

If all users are in the same time-zone as a server (as specified explicitly in -Duser.timezone) its okay to not pass actual time-zone everywhere (e.g. use new Date() and new DateTime(...) without time-zone, meaning it will be created in server time-zone). However, things get more messy if the user makes request in different time-zone. For example, their day start would not be the same as for the users in server time-zone.

It is important to run IDE tests, maven tests (...-[dao/web-server]/pom.xml ), PopulateDb, Server and Vulcanize (!) in the intended server time-zone.

Special Considerations

In a multi time-zone environment, where users may reside in time-zones different from the server one, it is important to create / manipulate dates using our IDates API methods:

  1. DateTime zoned(Date date)
  2. DateTime now()
  3. String toString(final Date[Time] date)

The needed time-zone may be retrieved from DateTimeZone timeZone() method. IUniversalConstants methods DateTime now() and DateTime today() are also suitable, as well as DateTime now() in CommonEntityDao/AbstractBefore[After]ChangeEventHandler.

Please note, that these considerations are applicable for both dependent and independent time-zone modes.

Migration to multi time-zone environment

  1. new Date() => now().toDate()
  2. new Date(System.currentTimeMillis()) => now().toDate()
    new Date(System.currentTimeMillis() + deltaMillis) => now().plus(deltaMillis).toDate()
  3. new DateTime() => now()
  4. new DateTime(date) => dates.zoned(date)
    new DateTime(date.getTime()) => dates.zoned(date)
  5. deprecated new DateMidnight(dateTime) => dateTime.withTimeAtStartOfDay()
  6. new DateTime(y, m, d, h, m) => new DateTime(y, m, d, h, m, dates.timeZone())
    new DateTime(y, m, d, h, m, s) => new DateTime(y, m, d, h, m, s, dates.timeZone())
    new DateTime(y, m, d, h, m, s, m) => new DateTime(y, m, d, h, m, s, m, dates.timeZone())
  7. DateTime.now() => our now()
  8. Local[Date]Time.toDateTime[Today]() => Local[Date]Time.toDateTime[Today](dates.timeZone())
  9. TODO continue about EntityUtils.toString, DateTimeUtil.to[DateOnly]String, SimpleDateFormat.format ...
    (see also Bijection between client- and sever-side date/time formats #1661)

Do not use:

  1. java.util.Calendar
  2. Date.toString()
  3. any deprecated Date method (new Date("..."), new Date(2024, 5, 1), Date.parse("...") etc.)
  4. any deprecated Joda-Time class (org.joda.time.DateMidnight)

Safe operations (if all arguments were constructed properly):

  1. DateTime.toDate()
  2. Date.before/after(Date other)
  3. Date.getTime()
  4. Date.equals(Date date)
  5. new Date(millis)
Clone this wiki locally