Floating times

Intended audience: users, HTML coders, script developers (PHP, JSP, etc.), CSS coders, schema developers (DTDs, XML Schema, RelaxNG, etc.), XSLT developers, Web project managers, and anyone who is new to internationalization and needs guidance on topics to consider and ways to get into the material on the site. yyy adapt this to describe the intended reader of the article.

Question

What is a floating time and how do I handle floating times in my Web application?

Quick answer

A floating time or a floating date is a time value that isn't tied to a specific time zone. Applications that work with floating times need to avoid pitfalls that can arise from implicit conversion to incremental time values or the improper use of time zones when displaying or processing a floating time value.

Details

The Working with Timezones WG Note says:

Some observed time values are not related to a specific moment in incremental time. Instead, they need to be combined with local information to determine a range of acceptable incremental time values. We refer to these sorts of time values as "floating times" because they are not fixed to a specific incremental time value. Floating times are not attached and should never be attached to a particular time zone.

That is, a floating time usually refers to a range of possible time values that share a specific relationship to the defined moment in time that the floating value represents. Examples of floating times include concepts such as birth date, starting or ending dates for a worldwide event, holidays, or publication dates.

For example, consider the publication date of a document—let's say a specific issue of an online newspaper. On 30 April 2017 this newspaper published a Sunday edition. And indeed, the newspaper might have declared the date like this in HTML:

<p>Publication Date: <time datetime="2017-04-30">April 30, 2017</time></p>

This seems unambiguous. Yet for some reason when Martina, who is in Buenos Aires, Argentina, opens the Web site, she sees "Saturday edition" and "29 April 2017" as the date for her copy. Problems such as this can arise if Web developers or content authors do not treat the publication date as a floating time value. For example, the JavaScript Date object is a form of incremental time: it represents the number of milliseconds since an epoch date. In the case of JavaScript, the epoch data is the same as that used by Unix, the Java programming language, and many other systems: it's defined as midnight, January 1, 1970 in the UTC (Universal Coordinated Time) time zone. So for Martina's newspaper, the value in the HTML document might be converted in JavaScript to a Date object with the value: 1493510400000 (in milliseconds since the epoch).

var date = new Date(myPubDateElement.value);
var target = document.getElementById("date_target");
target.appendChild(document.createTextNode(date.toDateString()));

Suppose your element myPubDateElement contained the value above (2017-04-30). You'd expect the element date_target contain a string representing that date. However, if you live in a time zone west of UTC (such as Martina, in the America/Buenos_Aires time zone), you'll get a surprise. It says:

Sat Apr 29 21:00:00 ART 2017

The problem here is that many of the Date methods in JavaScript are sensitive to the local system's time zone and they try to present the value using local time zone rules. Because the time of day was not specified, the time is treated as midnight, so anyone displaying the underlying value in a time zone following UTC will naturally see the previous day. In the case of a system running in the America/Buenos_Aires time zone, which has an offset from UTC of either -3 hours or -2 hours (depending on whether or not daylight savings time is in effect) the value presented to the user from the JavaScript is incorrect because the the time portion of the publication date is zeroed out. Subtracting two or three hours from the Date object results in a presentation string that is on the previous day. That day might be in the wrong month or even the wrong year.

Because the local interpretation of a given date depends on the local time—that is, it depends on the local calendar, clock, and time zone rules—the range of incremental times that might be described as 2017-04-30 turns out to span as many as fifty hours. The earliest time that can be called "30 April 2017" starts in Kiribati in the South Pacific, some 14 hours before midnight on 30 April 2017 occurs in UTC. The last moment that can be called part of "30 April 2017" occurs just before midnight of "1 May 2017" on the island of Midway's time zone, some 11 hours after "30 April 2017" has ended in UTC (there is an even later zone, but it is uninhabited). Depending on the time zone used to create and then later to display an incremental time value, the same floating date value could appear to be as much as two days off.

That's because, while a floating time is not tied to a specific time zone, any incremental time values depend on time zone for their display and processing. Since data formats for time values in both server-side (such as Java or PHP) and client-side languages (such as JavaScript) are always incremental times, this can lead to problems such as Martina's mysterious newspaper publication date.

One way to work around this it to always use the UTC time zone for processing floating time values. Developers have to be careful to convert time values into incremental time objects using an offset of zero and segregate code that deals with floating times from more-normal time values such as time stamps.

Storing, Retrieving, and Aggregating Time Data

Another way that floating times are used is in the aggregation of data. For example, suppose you are building an application that keeps track of the number of downloads a user makes. You can record each download using a timestamp (an incremental time value). That might look like this:

{
    "user-id": "9333c644-487a-11e7-a919-92ebcb67fe33",
    "item": "http://www.example.com/downloadMe",
    "date": "2013-10-02T07:17:00Z",
    "user-timezone": "America/Los_Angeles"
},

When your application wants to aggregate statistics, the use of incremental times to represent the aggregated data could become a problem. Suppose you want to accumulate user statistics, such as total downloads, on a daily basis. The timestamp in the example above might fall on October 2, 2013 for that customer. In this case, if the time zone were America/Los_Angeles as shown in the record, it would not! Here's what the accumulated record might look like:

{
    "user-id": "9333c644-487a-11e7-a919-92ebcb67fe33",
    "aggregationDate": "2013-10-01",
    "numDownloaded": 10
},

In this case, you want to use local time rules, including the time zone, in order to compute which floating date the download should accumulate to. But you want to use floating time rules to read and write the accumulated data record. That way the statistics remain the same for a given date, even if the user's time zone has changed in the interim. For example, if the customer moves to the Europe/Paris time zone, the number of downloads on 2013-10-01 should remain the same, even though the accumulation rules might be different now than they were previously.