ISO 8601 duration and time stamps in SCORM 2004

Claude Ostyn, August 2006
Copyright © 2004, 2005, 2006 Claude Ostyn

Overview

This document demonstrates the use of the ISO 8601 duration and date-time (a.k.a. "time stamp") formats as used in SCORM 2004 and recommended by the IEEE 1484.11.1 standard. It includes dynamic, interactive examples to show how different values are represented. It also explains how to do time related calculations based on ISO 8601 durations or time stamps. Because the number of days in a month varies, this may lead to loss of precision when representing durations. Practical workarounds are demonstrated to avoid this problem. The script of this page also contains reusable ECMAScript (a.k.a. JavaScript) functions to convert to and from the ISO 8601 format.

Tested with IE6 and FireFox 1.5.x. This page may not render correctly with some other browsers.

The ISO 8601 format for duration

Enter a value in any of the boxes below and click the Convert button next to it to see the corresponding representations. The ISO string must match the form
        P[yY][mM][dD][T[hH][mM][s[.s]S]]
where anything between [] is optional, but there must be at least one field (Year, Month, Day, Hour, Minute or Second). You can also click a button to generate a random value.

The error detection in this demo is not complete, and some incorrect forms that are not detected may produce incorrect results.

Centiseconds are 1/100s of a second, which is the resolution required by the standard. If you attempt to enter finer values, they will be rounded to centiseconds. The conversion to ISO format is always canonical, e.g. days only have 24 hours, and zero values are not shown. If you enter a large number of seconds in ISO format, for example PT310S, and convert to seconds and then back, the second conversion will use the canonical format and thus you will end up with PT5M10S. If you enter a value of 0 for seconds or centiseconds, the ISO string representation used here will be PT0H0M0S as specified by the SCORM 2004 conformance requirements document. Although technically it seems that it could just be P, one designator and value must be present in addition to the designator P and so it should be at least PT0S (PT, zero, S). However, the SCORM 2004 1.3.1 conformance test suite was coded to require the PT0H0M0S format for the initial zero value of the total attempt time; using that format is therefore recommended where compatibility with early implementations of SCORM 2004 is required.

 

Centiseconds:  
Seconds:  
ISO:  
ISO precise:  

(The ISO precise format does not use Year or Month)

Old format

SCORM 1.2 used the HHHH:MM:SS[.SS] format, which was superseded by the format recommended in the IEEE draft standard used in SCORM 2004. Note that hour values above 9999 are lost in converting to SCORM 1.2 format.

SCORM 1.2:

Duration samples

Elapsed time samples:
SCORM2004 format (ISO): PT26.4S
SCORM 1.2 format: 0000:00:26.40

Duration arithmetic

Precision issues with long durations

If necessary, the number of days in a month can calculated by approximation, using the formula
1 month = ((365 * 4) + 1)/48 days
to calculate the average months per day in any 4 year period, because a precise calculation is impossible without knowing dates and times. As a result, there may be a loss of precision in reciprocal conversions when the duration exceeds 28 days, unless the precise ISO form that uses neither Year nor Month fields is used. For example, entering P35D and converting to centiseconds and back using a ISO canonical format with a Month field results in P1M4DT13H30M, which does not look like whole days. But if the conversion to centiseconds and back is done without using a precise ISO format Month fields, the result is exactly the same: P35D. It cannot be assumed that different implementers will use the same approximation formula if it is necessary to calculate Month or Year values represented in an ISO format string.

Because of the variable number of days in a month or a year, precise duration arithmetic is very complex when a duration is expressed using Month and/or Year fields. A precise time and date reference is required, and you must know when the duration occured relative to that time and date. This can be further complicated by having to take into account the time zone, daylight savings time, and so on. The W3C Recommendation for XML Schema includes a specification of how to do this kind of calculation to add durations to date-time values.

So, if you want to do precise duration arithmetic but avoid this kind of complexity, the ISO string should use neither Year nor Date fields. Instead, the duration should be expressed in days, hours, minutes and/or seconds because the relationship between those data elements is fixed. If the number of days is higher than 28, just use a large number of days; for example, P45D is a conformant ISO representation for a long duration. Or you could use some other pattern with one or more fields, such as a seconds field with a very large value.

Examples of duration arithmetic

The examples below convert the ISO values to centiseconds. The addition and substraction then convert the result back to ISO. Because the same approximation method is used to calculate days in a month, the result is predictable for very long durations even if the ISO string format is not the "precise" format that does not use Year or Month. You can verify this by looking at the centisecond values extracted from the ISO string values. However, if the ISO string contains a Year or Month field, the same operation might not produce the same result in another implementation because that other implementation may use another approximation method.

   Use precise ISO format Explain

Operation Value 1   Value 2   Result   Behind the scene (centiseconds)
Addition   +   =     Click a button above to generate some values
Subtraction   -   =      
Comparison   ?   ->      

The ISO 8601 format for time stamp

A time stamp is a data value representing a "point in time".

When time stamp values must be exchanged, a standard representation for the value must be used to allow interoperability. This representation must be totally predictable, and it must work in any time zone and regardless of whether daylight savings time is in effect. The ISO 8601 standard defines such a representation, and SCORM 2004 requires that time stamp data be passed as an ISO 8601 conformant string. Using the SCORM profile for the ISO 8601 standard, the string must match the form
        YYYY[-MM[-DD[Thh[:mm[:ss[.s]]][TZD]]]]
where anything between [] is optional. Notice how the character T is used as separator between year, month, day and the time of day.

Only the four-digit year is required. In practice, time stamps used in the SCORM communication data model will usually contain more detailed information, because it is unlikely that a time stamp will be generated for 0 hours 0 minute 0 second on the first of January of a particular year. However, you might find such an abbreviated time stamp in the metadata, for example to represent a publication year. The optional value represented by TZD in the pattern is a reference to Universal Coordinated Time (UTC). The TZD value designates the time zone assumed in the time stamp. This is expressed as a positive or negative time offset in hours and possibly minutes, or by the value Z which means "zero offset from UTC". See examples below. Such a reference to UTC is often necessary for interoperability; it is however allowed only if there is a time component in the string.

Note that there is a small issue with the SCORM 2004 conformance requirements document. The requirement states that the pattern is
        YYYY[-MM[-DD[Thh[:mm[:ss[.s]TZD]]]]]]]
While technically incorrect, this is required for conformance with the IEEE 1484.11.1 standard, which in turn inherited this from a typo from the IEEE 1484.12.1:2004 standard. This is a generally harmless error since it won't cause anyone to lose data. The ADL technical team is aware of this issue. Watch the ADL knowledge base and corrigenda for a future official correction.

There is no need to wait for a correction, though. The simplest way to deal with this is to include hundreds of seconds whenever you include a timezone designator. For example, something like
        2004-04-01T09:45:58.00Z
is valid today according to the SCORM test suite, and will still be valid the future if the error is ever corrected. In any case, fully specifying a time stamp with zero values for the various components is harmless.

The ECMAScript (JavaScript) interpreters in different browsers use a standard Date object to represent a time stamp value. This object is not a string, but it can be rendered as a string by the ECMAString toString() function. Unfortunately, different browsers use different display formats for the string rendering of a Date object. This is how the ECMAScript Date object in your browser represents the same point in time when asked to display it as a string, using two different methods:

Local time using method Date.toString( ): ?  
Universal time using method Date.toGMTString( ):  ?

Time stamp examples

Time stamp values are best generated by the computer:  .
You can also edit this ISO format time stamp or create a new one:  

There are different ways to represent the same "point in time", as shown in the following table:

UTC time (Coordinated Universal Time, a.k.a. "Zulu" time) Local time with offset from UTC time
Precision = 0.01 second 2005-02-16T19:45:11Z 2005-02-16T19:45:11Z
Precision = 1 second 2005-02-16T11:45:10.97-08 2005-02-16T11:45:11-08

Validating the script conversions

The script of this page generates the ISO strings in the table above. For verification, the script also translates the ISO strings back to a JavaScript Date object by calling methods of the Date object with the date and time values. Doing these reverse conversions with a variety of time stamp values is very helpful in verifying that the scripts that perform the conversions work correctly:

The strings below are generated by doing a reverse conversion from the ISO format back to a JavaScript Date object, and asking JavaScript to display the Date.

From the time offset format:  ?
From the "Zulu" format:  ?

Note that you might observe a discrepancy of up to one second between the ISO string and the string rendered by the Date object, due to loss of precision in the conversion. This is not an error.

Time stamp arithmetic

Calculating elapsed time since a specific time stamp

The easiest way to calculate an ISO 8601 duration as elapsed since a given time stamp in ECMAScript is probably to create two Date objects, one for the time stamp, and one for "now", and set the value of the first Date object to match the given time stamp. Then use the Date.getTime() function to extract a millisecond value from each and calculate the difference. This will automatically take into account time zones and daylight savings time changes that might have occurred between the two dates and times. You can then convert the result to an IS0 8601 duration string. Obviously, if the original time stamp does not include a TZD the result will be correct only if the original time stamp is relative to the same time zone. Note that ECMAScript Date objects cannot be used this way for dates earlier than January 1, 1970.

Calculating duration between two time stamps

The easiest way to calculate an ISO 8601 duration from two time stamps in ECMAScript is probably to create two Date objects, one for each time stamp, and set their values accordingly. Then use the Date.getTime() function to extract a millisecond value from each and calculate the difference. This will automatically take into account time zones and daylight savings time changes that might occur between the two dates and times. You can then convert the result to an IS0 8601 duration string. Obviously, if the time stamps do not include a TZD the result will be correct only if the time stamps are relative to the same time zone. Note that ECMAScript Date objects cannot be used this way for dates earlier than January 1, 1970.

Resources

There are many web pages devoted to time calculations. A particularly interesting one if you have a few hours to kill can be found at http://www.merlyn.demon.co.uk/js-dates.htm.


Demonstration script

The reusable functions used to perform the conversions demonstrated on this page are contained in the script below. For example, to make an ISO time stamp string as expected by SCORM for "now", in ECMAScript (a.k.a. JavaScript) you would use something like

var objDate = new Date();

to capture the point in time, then call

MakeISOtimeStamp(objDate)

to get a UTC timestamp (Zulu time), e.g.

or

MakeISOtimeStamp(objDate, true)

to get a time stamp with a UTC offset, e.g.

Download

Please read the no nonsense License and terms of use below before downloading or using this script. By downloading or using this software you signify your agreement with the license and terms of use.

Right-click here to download ostynscormtime.js.

The following alternative download link is provided because scripting is not available in your browser: ostynscormtime.js.

License and terms of use

Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike2.5 License.
USE AT YOUR OWN RISK
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.