In this document:
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.
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.
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:
| Elapsed time samples: | |
| SCORM2004 format (ISO): | PT26.4S |
| SCORM 1.2 format: | 0000:00:26.40 |
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.
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 | ? | -> |
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 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 |
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.
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.
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.
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.
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.
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.
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.