Date/time localization

After I had posted a question about the inconsistent date formatting in the Product api response (i.e. some dates are returned in ISO-8601 time stamp format, and some are returned in MMM dd yyyy format) It occurred to me that I have no idea what time zone those non-ISO formats are in. Nor do I know what time zone the UI displays dates in. I also do not know on data entry sheets and file uploads what time zones are defaulted by the system.

Can someone explain if the API localizes the date somehow? What about the UI, does it localize the dates to the user’s browser location? to the location that the user is currently working with? to the parent organization’s time zone?

It occurred to me that I have no idea what time zone those non-ISO formats are in.

Datetimes are always stored in the database in UTC.

Nor do I know what time zone the UI displays dates in.

The dates in the UI are in the timezone displayed in the footer, which is either the user-specific timezone or the system-wide timezone which is set on the server (either the OS’s timezone or overridden via Tomcat/Java at runtime)

I also do not know on data entry sheets and file uploads what time zones are defaulted by the system.

Same as above.

A user can override the timezone by setting one in their user’s profile.

Can someone explain if the API localizes the date somehow?

I believe the same rules apply for the UI and API.

What about the UI, does it localize the dates to the user’s browser location? to the location that the user is currently working with? to the parent organization’s time zone?

See above.

I have doubts about your answer, at least for the API responses. The BootStrap.groovy that you pointed me to in a previous response shows that for many, many of the dates in the various objects, the .format() method is called passing only the the format string. According to the groovy documentation I have found, this means that such dates would be localized to the server’s timezone. To show in the correct timezone on a user-by-user basis such dates would have to be reparsed and then reformatted to the user’s local time zone.

Good point. I was thinking the mechanism we use to “format” the dates returned by the API would implicitly use the timezone associated with the current HTTP session. But thinking through that more, I’m realizing that might not be the case. Grails uses a mechanism to retrieve the timezone from a request (which includes looking at the session).

However, I don’t believe we followed this convention. Instead, we just plopped the timezone into our own session variable (or we pull it from the user in the session when needed).

I’ll have to do a little research but this might be as easy as using the standard session variable name and/or using a more standardized (Grails/Spring) way of resolving the timezone.

SessionLocaleResolver.TIME_ZONE_SESSION_ATTRIBUTE_NAME

With all of that said, it looks like there are differing opinions on what format / timezone to use. For example, according to the following StackOverflow article

… these are some recommended best practices

  • Law #1: Use ISO-8601 for your dates
  • Law #2: Accept any timezone
  • Law #3: Store it in UTC
  • Law #4: Return it in UTC
  • Law #5: Don’t use time if you don’t need it

Here’s a link to the “5 Laws” article.

https://apiux.com/2013/03/20/5-laws-api-dates-and-times/

Not sure if this is the gold standard, but it seems we are following Law #4.

Going forward, we could decide to

  • Continue following Law #4 which would create the scenario you describe about parsing / reformatting (pros: standard; cons: API client needs to parse the value and format it in the local timezone)
  • Use the user-defined timezone and fallback to the system timezone (pros: easier for API client; cons: could be confusing and might need to send the timezone separately so it’s clear what timezone is being used)
  • Make the date formatting / timezone configurable on a system-by-system or user-by-user basis (pros: more flexible; cons: possibly more confusing)

If you were to ask me, I would use ISO-8601 only in all API returns. And let the API client parse and format it with whatever localization it needs.

Yeah, that’s what I was hoping you’d say.

The one caveat is Law #5 which says “Don’t use time if you don’t need it”. This is very subjective, but I can see cases like “expiration date” where the timestamp does not need to be returned.

cc @Artur just wanted you to be aware of this conversation.

Interesting problem with expiration date. There is an ambiguity. Is the thing expired when the calendar rolls to that date (i.e. at 00:00:01 on the expiration date) or when the calendar rolls off that date (i.e. at 23:59:59)? At my company, we have opted to decide that expiration dates are enforced at the end of the expiration date.

As far as Law #5 goes. In as much as the OpenBoxes supports localization, it is incorrect to return bare dates. For example an update in made during normal business hours in Australia, is almost always a calendar day before an update made during the business hours in the US. Sticking to Law #5 makes sense for things like Birthdays, Holidays, Anniversaries etc., and possibly fore casting or prospective dates. For these things I would stick to LocalDate. My Christmas is December 25; it doesn’t matter where I am at.