<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  <title>It’s About Time</title>
  <style type="text/css">
body {
  padding: 2em 1em 2em 70px;
  margin: 0;
  font-family: sans-serif;
  color: black;
  background: white;
  background-position: top left;
  background-attachment: fixed;
  background-repeat: no-repeat;
}
:link { color: #00C; background: transparent }
:visited { color: #609; background: transparent }
a:active { color: #C00; background: transparent }

a:link img, a:visited img { border-style: none } /* no border on img links */

a img { color: white; }        /* trick to hide the border in Netscape 4 */
@media all {                   /* hide the next rule from Netscape 4 */
  a img { color: inherit; }    /* undo the color change above */
}

th, td { /* ns 4 */
  font-family: sans-serif;
}

h1, h2, h3, h4, h5, h6 { text-align: left }
/* background should be transparent, but WebTV has a bug */
h1, h2, h3, h4 { color: #005A9C; }
h1 { background: white }
h2 { background: white; }
h3 { background: white; }
h1 { font: 170% sans-serif }
h2 { font: 140% sans-serif }
h3 { font: italic 120% sans-serif }
h4 { font: bold 100% sans-serif }
h5 { font: italic 100% sans-serif }
h6 { font: small-caps 100% sans-serif }

.hide { display: none }

div.head { margin-bottom: 1em }
div.head h1 { margin-top: 2em; clear: both }
div.head table { margin-left: 2em; margin-top: 2em }

p.copyright { font-size: small }
p.copyright small { font-size: small }

@media screen {  /* hide from IE3 */
a[href]:hover { background: #ffa }
}

pre { margin-left: 2em }

dt, dd { margin-top: 0; margin-bottom: 0 } /* opera 3.50 */
dt { font-weight: bold }

pre, code { font-family: monospace; } /* navigator 4 requires this */

ul.toc {
  list-style: disc;     /* Mac NS has problem with 'none' */
  list-style: none;
}
  
code           { font-family: monospace; }

div.constraint,
div.issue,
div.note,
div.notice     { margin-left: 2em; }

li p           { margin-top: 0.3em;
                 margin-bottom: 0.3em; }

div.exampleInner pre { margin-left: 1em;
                       margin-top: 0em; 
                       margin-bottom: 0em
                     }
div.exampleOuter {border: 4px double gray;
                  margin: 0em; 
                  padding: 0em
                  }
div.exampleInner { background-color: #d5dee3;
                   border-top-width: 4px;
                   border-top-style: double;
                   border-top-color: #d3d3d3;
                   border-bottom-width: 4px;
                   border-bottom-style: double;
                   border-bottom-color: #d3d3d3;
                   padding: 4px; margin: 0em }
div.exampleWrapper { margin: 4px }
div.exampleHeader { font-weight: bold;
                    margin: 4px}
table { width: 100% }
pre {
      background: cyan;
      width: 80%;
      margin-top: 3pt;
      margin-bottom: 3pt;
      border: 1pt solid blue;
    }
p.quote { 
          font: normal 9pt san-serif;
          background: silver;
          width: 80%;
          border: 1pt solid blue;
          margin-top: 3pt;
          margin-bottom: 3pt;
         }
  </style>
</head>
<body> <h1>It’s About Time</h1><p>Author: Addison Phillips</p><p>Last Update: 2005-10-06</p>
<h1>Note:</h1>
<p>Readers of this document might wish to look at this W3C Note on the same topic: <a href="http://www.w3.org/International/core/2005/09/timezone.html">timezone faq</a></p>
<h2>Software Development and Testing Issues Related to Time</h2><p>Proper handling of dates, times, and time zones present many problems for developers and quality assurance teams. Much of this stems from a lack of education about the data types and algorithms involved. Time information is critical to most computer systems, but unlike numeric or textual data types, dates and times have a complex conceptual framework that developers must understand in order to avoid traps and pitfalls.</p><p>In addition, dates and times form the basis for many kinds of  "unique IDs", as well as relating information about frequency and recurrence. </p><h2>A Brief History of Time</h2><p>Computer systems tell time differently than people do. So it is helpful to understand how time works within computers as well as in the real world in order to get a handle on the things that can go wrong.</p><h3>Observed Time</h3><p>Humans tell time using something called "observed time". Time, as we experience it, is related to an apparently orderly progression of observed events: sunrise, sunset, longest and shortest day of the year, sun's position against the background stars. These are "observed events" are, of course, caused by the Earth's rotation on its axis; the Earth's orbit around the sun; and so forth. For convenience we divide these events up into arbritrary units that make time more measurable: hours in a day, for example, or weeks in a month. In some cases the original observational ties have been weakened or removed over time (in the Gregorian calendar the months are not tied to the lunar cycle). In some calendars the observational aspects of time remain more pronounced. For example, the Koran specifies exactly how to tell day from night (defining a "day") and solar-lunar calendars (such as the traditional Chinese calendar) define months in terms of the lunar cycle.</p><h3>From Observed to Deterministic Time</h3><p>Observational time has certain disadvantages for the modern world. Observed events are not always predictable or convenient to use. The advent of mechanical timekeeping has allowed a different kind of time to flourish: what I'll call "deterministic" time based on fixed units. In some cases deterministic time is merely a prediction of when an event might be observed.</p><p>Time zones are a good example of the advantages of deterministic time. Their origins are useful to contemplate, since they exactly mirror common bugs introduced by careless software developers when working with time.</p><p>Before time zones, local time was derived observationally. The observational definition of a day was often based on local noon, which is defined as the moment that the sun is highest in the sky. This is an event that, weather permitting, can be observed anywhere on Earth excepting certain polar regions using simple navigational techniques.</p><p>Traveling fairly short distances across the Earth's surface results in changes in when this time occurs. Eratosthenes of Alexandria (circa 225 BCE) worked out the size of the Earth by having someone step off the distance from Alexandria to the equator and measuring the difference in Sun angle at noon on the equinox, for example. Similar changes in the distance you travel to the east or west will change the time at which you observe local noon.</p><p>Prior to the late 1800s, most places set their local time well <em>locally</em>, as on a town clock, using these techniques. </p><p>With the advent of railroads, it became possible to travel quickly between places with distinct local times. Railroad operators faced fierce competition, so operating trains on a fixed, tight schedule is most economical. But you only have to travel about 17 miles at the equator (and less distance the further north or south you travel!) to alter the observed local time by a minute. The importance of maintaining a schedule is that people in the various locations served by the railroad know when the train will arrive (and depart) based on local time. You can make up for deviations by spending a lot of time waiting in each station, but this reduces the throughput for your railroad.</p><p>Observational error, local customs, and other issues combined with a plethora of "local times" made accurate scheduling nearly impossible. </p><p>The railroads solved this problem by adopting fixed time zones one hour wide. The time in the middle of the time zone is used throughout, so the most observational deviation you would get is about half an hour (and most people experience a smaller deviation). Railroad companies in the United States instituted standard time zones starting in 1883. This changed the definition of time from observed to deterministic time and allowed them to print schedules that did not rely on local observation. It also allowed them to communicate the status of a particular train (early or late) throughout their networks.</p><p>More recently, the concept of "Daylight Savings Time" (DST) or "Summer Time" (if you're European) was adopted as a way of making people more productive in times of war. There are lots of interesting variations and problems related to DST, including the fact that it varies from country to country (not to mention locality-to-locality) and often has "special one-off" changes to accommodate special events (like hosting the Olympics and the like).</p><p>For lots of time related links, see: <a href="http://www.daily-tangents.com/TimeZone/">Daily Tangents</a>.</p><p>Amusingly, problems with local time persist into modern times. For example: <a href="http://www.city.saskatoon.sk.ca/org/clerks_office/archives/history/resources_history_of_time_system.pdf">Saskatchewan time history</a>.</p><p>You can read a lot more information about daylight savings time here: <a href="http://www.timeanddate.com/time/aboutdst.html">http://www.timeanddate.com/time/aboutdst.html</a>.</p><h3>Computer Time</h3><p>In most modern operating systems and programming languages, time is based on a integer value: the number of events (frequently milliseconds) since an "epochal event": a fixed moment in time whose value is "0". The integer type used for storage and the epochal event vary and each system has its own idiosyncrasies, but the concept is very nearly universal. </p><p>Java's <code>java.util.Date</code> object is a good example of this. It is a wrapper around a <code>long</code> value: the number of milliseconds since midnight, January 1, 1970, in Universal Coordinated Time (or <em>UTC</em>). Times before that are negative numbers. Times after that are positive numbers.</p><p>At any moment in time, it is the same time, in UTC, all over the Earth. UTC does not have daylight savings and doesn't vary from place to place. Hence it is "Universal" and "Coordinated".</p><p>Java <code>Date</code> objects really only approximate UTC. They are actually built on "system time", which assumes a fixed number of seconds in each day. UTC requires the occasional leap second and other hiccough to deal with minor variations in the real world. Nonetheless, we can generally ignore the difference.</p><p>So a Java <code>Date</code> represents a specific, universal moment in time. When you apply a time zone to a <code>Date</code>, you will see a different time depending on which time zone you are currently using.</p><p>Let's illustrate this more clearly. Consider this Java code:</p><pre>d1 = new java.util.Date(); 
long f = d1.getTime(); 
System.out.println(f);</pre><p>At the time I'm writing this, the value of <em>f</em> is <code>1034197545321L</code>. If I print the date out in my time zone (Pacific Time), I get this:</p><pre>Wed Oct 09 14:08:01 PDT 2002</pre><p>If I print the same <code>Date</code> object out in Japan Standard Time, I get this string instead:</p><pre>Thu Oct 10 06:08:01 JST 2002</pre><p>This is the same <code>Date</code> object, but a different string—on a different day even! Of course, as I write this, it really <em>is</em> six o'clock in the morning in Japan.</p><p>There are quite a few different conventions for binary datetime, depending on different platforms and protocols. Some of these have drawbacks inherent in their design. For example, people using Unix time (seconds since January 1, 1970) think that they are safe until near the year 2038. But cases can and do arise where arithmetic manipulations causes serious problems. Consider the computation of the average of two datetimes, for example: if one calculates them with <code>averageTime = (time1 + time2)/2</code>, there will be overflow even with dates around the present. Moreover, even if these problems don't occur, there is the issue of conversion back and forth between different systems.</p><table border="1" cellpadding="4" cellspacing="0" bgcolor="66ccff">
    <caption>
      Table 1: Binary Time Scales
    </caption>
    <tbody><tr>
      <th align="left">Source</th>
      <th align="left">Datatype</th>

      <th align="left">Unit</th>
      <th align="left">Epoch</th>
    </tr>
    <tr>
      <td>JAVA_TIME</td>
      <td>int64</td>
      <td>milliseconds</td>

      <td>Jan 1, 1970</td>
    </tr>
    <tr>
      <td>UNIX_TIME</td>
      <td>int32 or int64</td>
      <td>seconds</td>
      <td>Jan 1, 1970</td>

    </tr>
    <tr>
      <td>ICU4C</td>
      <td>double64</td>
      <td>milliseconds</td>
      <td>Jan 1, 1970</td>
    </tr>

    <tr>
      <td>WINDOWS_FILE_TIME</td>
      <td>int64</td>
      <td>ticks (100 nanoseconds)</td>
      <td>Jan 1, 1601</td>
    </tr>
    <tr>

      <td>WINDOWS_DATE_TIME</td>
      <td>int64</td>
      <td>ticks (100 nanoseconds)</td>
      <td>Jan 1, 0001</td>
    </tr>
    <tr>
      <td>MAC_OLD_TIME</td>

      <td>int32</td>
      <td>seconds</td>
      <td>Jan 1, 1904</td>
    </tr>
    <tr>
      <td>MAC_TIME</td>
      <td>double</td>

      <td>seconds</td>
      <td>Jan 1, 2001</td>
    </tr>
    <tr>
      <td>EXCEL_TIME</td>
      <td>?</td>
      <td>days</td>

      <td>Dec 31, 1899</td>
    </tr>
    <tr>
      <td>DB2_TIME</td>
      <td>?</td>
      <td>days</td>
      <td>Dec 31, 1899</td>
    </tr>

  </tbody></table><p>You can read more about data types used for time here: <a href="http://oss.software.ibm.com/cvs/icu/~checkout~/icuhtml/design/formatting/universal_time_scale.html">Universal Time Scale (ibm.com)</a> (you'll notice I borrowed the above table and example from Mark Davis's article). As a refresher, you should probably refer to the information about Y2K. Here is a list of various important dates (some still in the future): <a href="http://www.uic.edu/depts/accc/software/isodates/dates.html">Dates with Special Importance in Computing (uic.edu)</a></p><h3>Representing Date and Time as a String</h3><p>Of course, a date value like <code>0xF0CAFA3169L</code> is really not abundantly helpful for end users. Users expect to see something more familiar, like "Oct 9, 2002, 2:08 P.M. PST". There is also the question of how to represent time when serialized as a string. These are separate questions. Let's start with the latter.</p><h4>Serializing Dates as Strings</h4><p>A common example of serializing a date or time as a string is in an XML or EDI flat file. In a text file, a value like the hex string above conveys little or no information to users trying to debug the file and it makes it difficult to validate the results of processing the file. This calls for a standardized way to represent time values as strings. </p><p>The most prevalent current standard (and the one used by XML Schema, please note) is ISO 8601.</p><p>ISO 8601 provides an amazing array of ways to represent dates, times, and intervals. However, the most common are the date, time, and datetime strings:</p><table summary="Examples of the common ISO 8601 date and time formats." border="1" cellpadding="1" cellspacing="1" bgcolor="66ccff"><caption>Common ISO 8601 formats</caption><thead><tr><th>Format Name</th><th>Java Pattern</th><th>Example</th><th>Comment</th></tr></thead><tbody><tr><td>Date</td><td>yyyy-MM-dd</td><td>2004-11-05</td><td>Year first format is always unambiguous.</td></tr><tr><td>Time</td><td>HH:mm:ssZ</td><td>14:25:37+01:00</td><td>Timezone is a UTC offset, which is inexact.</td></tr><tr><td>Datetime</td><td>yyyy-MM-dd'T'HH:mm:ssZ</td><td>2004-11-05T14:25:37+01:00</td><td>Note the letter "T" separates the date and time.</td></tr></tbody></table><p>You can read more about ISO 8601 here: <a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">ISO 8601 Summary</a></p><p>ISO 8601 also provides support for "intervals", which includes recurring periods of time, such as "every 10 minutes" or "in five weeks". A deeply technical discussion of how these are screwy can be found here: <a href="http://www.macchiato.com/unicode/timeIntervals.htm">Time Intervals (macchiato.com)</a> and a more coherent discussion of ISO 8601 (it's Powerpoint, though) can be found here: <a href="http://www.xencraft.com/resources/ISO8601_IUC21_200204.ppt">Understanding ISO 8601 date elements and interchange formats (xencraft.com)</a>.</p><p>The important point to remember about ISO 8601 format is that it is locale-neutral. Although its string representation relies on the Gregorian calendar, it doesn't use any specific language keywords and the numbers used have an explicit mapping back to deterministic time values such as <code>java.util.Date</code>. This means that an ISO 8601 date or time can be expressed using a local, non-Gregorian calendar.</p><p>There are some bad examples of time strings in standards as well. For example, the XML Schema date/time types that start with the letter "g" (for Gregorian) are dependent on the Gregorian calendar and have idiosyncrasies related to conversion in certain places. Here, for example, is the note from <a href="http://www.w3.org/TR/xmlschema-2/#gMonth">XML Schema Part 2: Datatypes</a>:</p><pre>Note:  Because months in one calendar only rarely correspond to months in 
other calendars, values of this type do not, in general, have any straightforward 
or intuitive representation in terms of most other calendars. This type should 
therefore be used with caution in contexts where conversion to other calendars 
is desired.</pre><h4>Presenting Dates as Strings</h4><p>The other way that dates and strings interrelate is the presentation of dates as strings in the user interface, what some people call "wall time" (because that's what your clock and calendar on the wall would show). The Java <code>Date</code> object does feature a <code>toString()</code> method that produces an English-like string. In fact, you've already seen examples of this string in this document:</p><pre>Wed Oct 09 14:08:01 PDT 2002</pre><p>This string is modeled after the one produced by Unix systems running in the C or POSIX locale—the default locale for Unix systems. Although the presentation and abbreviations used are familiar enough to U.S. English readers, you might notice that the format is a bit odd, what with the 24-hour clock and the year coming after the time and time zone.</p><p>Formats like this are predictable, but they aren't suitable for human display. When testing software running in an English locale configuration, be aware that dates that look like the above are bugs: they'll stay in English when the locale changes later!</p><p>The correct way to get generic date, time, and datetime strings from Java is to use the <code>DateFormat</code> class. The <code>DateFormat</code> class provides 24 different date/time patterns for each locale. That's four date patterns (SHORT, MEDIUM, LONG, and FULL), plus four time patterns (ditto), plus sixteen combinations of the two for date-and-time strings.</p><p>Each locale and format combination is unique. One of the problems that developers face is that the keywords are descriptive and do not accurately predict the form that a particular locale's date or time format will take. </p><p>Here are a large number of examples of the date formats found in Java, selected for the wide range of variation within a language and between one another:</p><table width="100%" bgcolor="#66CCFF" border="1" cellpadding="1" cellspacing="1"><thead><tr><td></td><td>SHORT</td><td>MEDIUM</td><td>LONG</td><td>FULL</td><td>Comment</td></tr></thead><tbody><tr><td>Korean</td><td>04. 3. 2.</td><td>2004. 3. 2.</td><td>2004년 3월 2일 (화)</td><td>2004년 3월 2일 화요일</td><td>spaces, Hangul</td></tr><tr><td>Thai</td><td>2/3/2004</td><td>2 มี.ค. 2004</td><td>2 มีนาคม 2004</td><td>วันอังคารที่ 2 มีนาคม ค.ศ. 2004</td><td></td></tr><tr><td>Thai (Thailand)</td><td>2/3/2547</td><td>2 มี.ค. 2547</td><td>2 มีนาคม 2547</td><td>วันอังคารที่ 2 มีนาคม พ.ศ. 2547</td><td>Year change</td></tr><tr><td>Thai (Thailand,TH)</td><td>๒/๓/๒๕๔๗</td><td>๒ มี.ค. ๒๕๔๗</td><td>๒ มีนาคม ๒๕๔๗</td><td>วันอังคารที่ ๒ มีนาคม พ.ศ. ๒๕๔๗</td><td>Year change and numeric shaping!</td></tr><tr><td>Chinese (China)</td><td>04-3-2</td><td>2004-3-2</td><td>2004年3月2日</td><td>2004年3月2日 星期二</td><td></td></tr><tr><td>Byelorussian</td><td>2.3.04</td><td>2.3.2004</td><td>аўторак, 2, сакавіка 2004</td><td>аўторак, 2, сакавіка 2004</td><td>No Capitalization.</td></tr><tr><td>Catalan (Spain)</td><td>02/03/04</td><td>02/03/2004</td><td>2 / març / 2004</td><td>dimarts, 2 / març / 2004</td><td>Separator</td></tr><tr><td>Czech</td><td>2.3.04</td><td>2.3.2004</td><td>2. březen 2004</td><td>Úterý, 2. březen 2004</td><td>#. for ordinal (1st, 2nd, 3rd) style number</td></tr><tr><td>Danish (Denmark)</td><td>02-03-04</td><td>02-03-2004</td><td>2. marts 2004</td><td>2. marts 2004</td><td></td></tr><tr><td>German (Switzerland)</td><td>02.03.04</td><td>02.03.2004</td><td>2. März 2004</td><td>Dienstag, 2. März 2004</td><td></td></tr><tr><td>Spanish</td><td>2/03/04</td><td>02-mar-2004</td><td>2 de marzo de 2004</td><td>martes 2 de marzo de 2004</td><td>Separators change!</td></tr><tr><td>Spanish (Argentina)</td><td>02/03/04</td><td>02/03/2004</td><td>2 de marzo de 2004</td><td>martes 2 de marzo de 2004</td><td>Different from base language.</td></tr><tr><td>French (France)</td><td>02/03/04</td><td>2 mars 2004</td><td>2 mars 2004</td><td>mardi 2 mars 2004</td><td></td></tr><tr><td>Lithuanian</td><td>04.3.2</td><td>2004.3.2</td><td>Antradienis, 2004, Kovo 2</td><td>Antradienis, 2004, Kovo 2</td><td></td></tr><tr><td>Portuguese (Brasil)</td><td>02/03/04</td><td>02/03/2004</td><td>2 de Março de 2004</td><td>Terça-feira, 2 de Março de 2004</td><td></td></tr><tr><td>Albanian</td><td>04-03-02</td><td>2004-03-02</td><td>2004-03-02</td><td>2004-03-02</td><td>Formats very similar</td></tr><tr><td>Turkish</td><td>02.03.2004</td><td>02.Mar.2004</td><td>02 Mart 2004 Salı</td><td>02 Mart 2004 Salı</td><td>Dotless "i" character.</td></tr><tr><td>Arabic</td><td dir="rtl">02/03/04</td><td dir="rtl">02/03/2004</td><td dir="rtl">02 مارس, 2004
</td><td dir="rtl">02 مارس, 2004
</td><td>Bidi!</td></tr></tbody></table><p>Times vary slightly less, but there is still wide variation. Here is a smaller selection of  time formats:</p><table width="100%" bgcolor="#66CCFF" border="1" cellpadding="1" cellspacing="1"><thead><tr><td></td><td>SHORT</td><td>MEDIUM</td><td>LONG</td><td>FULL</td><td>Comment</td></tr></thead><tbody><tr><td>Korean</td><td>오후 4:32</td><td>오후 4:32:58</td><td>오후 4시 32분 58초</td><td>오후 4시 32분 58초 PST</td><td>Hanguel from the start!</td></tr><tr><td>Thai</td><td>16:32 น.</td><td>16:32:58</td><td>16 นาฬิกา 32 นาที</td><td>16 นาฬิกา 32 นาที 58 วินาที</td><td></td></tr><tr><td>Chinese (China)</td><td>下午4:32</td><td>16:32:58</td><td>下午04时32分58秒</td><td>下午04时32分58秒 PST</td><td>Ideographs as separators. AM/PM vs. 24-hour clock</td></tr><tr><td>Byelorussian</td><td>16.32</td><td>16.32.58</td><td>16.32.58 PST</td><td>16.32.58 PST</td><td>dot separator</td></tr><tr><td>Catalan (Spain)</td><td>16:32</td><td>16:32:58</td><td>16:32:58 PST</td><td>16:32:58 PST</td><td></td></tr><tr><td>German (Switzerland)</td><td>16:32</td><td>16:32:58</td><td>16:32:58 PST</td><td>16:32:58 Uhr PST</td><td>keyword</td></tr><tr><td>Spanish</td><td>16:32</td><td>16:32:58</td><td>16:32:58 PST</td><td>16H32' PST</td><td>Funny full format</td></tr><tr><td>Spanish (Argentina)</td><td>16:32</td><td>16:32:58</td><td>16:32:58 PST</td><td>16h32' PST</td><td>Capitalization changes</td></tr><tr><td>French (France)</td><td>16:32</td><td>16:32:58</td><td>16:32:58 PST</td><td>16 h 32 PST</td><td></td></tr><tr><td>Lithuanian</td><td>16.32</td><td>16.32.58</td><td>16.32.58 PST</td><td>16.32.58 PST</td><td></td></tr><tr><td>Portuguese (Brasil)</td><td>16:32</td><td>16:32:58</td><td>16h32min58s PST</td><td>16h32min58s PST</td><td></td></tr><tr><td>Albanian</td><td>4.32.MD</td><td>4:32:58.MD</td><td>4.32.58.MD PST</td><td>4.32.58.MD PST</td><td>Pay very close attention to the number of dots in each one!</td></tr><tr><td>Arabic</td><td dir="rtl">04:32 م</td><td dir="rtl">04:32:58 م</td><td dir="rtl">PST 04:32:58 م</td><td dir="rtl">PST 04:32:58 م</td><td>Bidi!</td></tr></tbody></table><p>From the tables above it is easy to construct some idea of the variability in format that our systems can produce. Date formats in particular can be ambiguous, since the month and day number can be in any order (let alone the year number). Correct presentation may require more space in your user interface than expected.</p><p>Developers can also construct strings using a pattern language and the class <code>SimpleDateFormat</code>. What a particular pattern sequence produces, though, is strongly influenced by the locale in which the formatting takes place. For example, if you wish to build a table showing results by day-of-the-week, you might wish to use the short form of the day name. Try the following code:</p><pre>   public static void dayNameAbbrevs() {
       Locale[] locs = Locale.getAvailableLocales();
       int[] result = new int[] {0,0,0,0,0,0,0,0,0,0};
       for (int x=0; x&lt;locs.length; x++) {
           SimpleDateFormat sdf = new SimpleDateFormat("E",locs[x]); // E is day name
	   String test = sdf.format(new Date());
	   if (test.length() &lt; 11) {
		   result[test.length()-1]++;
	   }
       }
       for (int x=0; x&lt;result.length; x++) {
	       System.out.println(x + " " + result[x]);
       }
   }</pre><p>In JDK 1.4.2, this produces 38 locales with a one character abbreviation, 57 with two, 10 with three—and three locales with seven character abbreviations!</p><h4>Parsing Dates from Strings</h4><p>Input from strings can also present a challenge. The above display examples represents some of the range of variation possible in human speech. It doesn't begin to represent the range of variation in what users may input into an application. </p><p>In addition, the <code>DateFormat</code> <code>parse(#str)</code> method is extremely literal. It will throw a <code>ParseException</code> for a missing piece of punctuation or on the difference between a non-breaking and breaking space (most users are too lazy or don't know how to type the non-breaking variety). If the pattern doesn't match perfectly, you'll get a parsing error instead of a <code>Date</code> object.</p><p>If you use a <code>ParsePosition</code> object to avoid the messy <code>ParseException</code> catch block, then you have to insert code to check the result you get. In many cases a partial parse will produce a value quite far from the original string.</p><pre>
 // The following line limits what the parser can parse to SHORT-like formats
 DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.FRENCH);
 for (int x=0; x&lt;in.length; x++) {
    try {
       Date d = df.parse(in[x]);
       System.out.println(d);
    } catch (ParseException pe) {
       // It's easy to get into this section
       System.out.println("ParseException on " + in[x] + 
          " at " + pe.getErrorOffset());
    }
    try {
       ParsePosition pp = new ParsePosition(0);
       Date d = df.parse(in[x], pp);
       // The above line always produces a date, but the Index and ErrorIndex 
       // may not match your expectations.
       System.out.println(d + " " + in[x] + " " + pp.getIndex() + 
          " " + pp.getErrorIndex());
    } catch (Exception e) {
    // You will never get into this block
    e.printStackTrace();
    }
 }</pre><p>To the extent possible, your code should use visual controls to set dates and times, instead of trying to parse strings. There are too many things that can go wrong in parsing. </p><p>At webMethods, we maintain a globalization utility library which contains a very aggressive parser (in the <code>com.wm.g11n.text.DateUtils</code> class) that is often a better choice than <code>DateFormat</code>, but even this parser is limited by the current locale you select. The user must know the format the code expects in order for  a parser to work well.</p><h3>Working Directly with Dates</h3><p>For the most part, working with date objects is straightforward. Using integers to represent time makes many common operations easy to perform. For example, a date is before another date if its value is smaller. Integer math operations are easy to perform.</p><p>You can get into trouble, though, if you begin to make assumptions about dates and times and try to work directly with the integer values. For example, it is common to assume that a "day" consists of 86,400 seconds (24 hours times 60 minutes times 60 seconds). While this is nominally true, there are cases where the number of seconds vary. </p><p>For example, a day on which a daylight savings transition occurs will have more (or fewer) seconds in it. If you try to do math on date values directly (rather than using Date's utility methods or a Calendar object), you can run into unusual performance quirks.</p><p>Some developers try to build longer durations (such as a week, month, or quarter) by creating the interval. There are two traps here.</p><p>First, if you create the interval by using 86400 times the expected number of days, your actual interval (when checking start or end dates) will depend on whether a daylight savings transition or other even occured during the affected period. For example, this code doesn't work even though it uses the correct logic for getting the number of days in the quarter:</p><pre>  public static void calculateQuarterBadly() {
	  Calendar c = (Calendar)new GregorianCalendar();
	  //c.setTimeZone(TimeZone.getTimeZone("UTC"));
	  c.set(Calendar.YEAR, 2000);
	  c.set(Calendar.MONTH, 3); // April: month is zero based!
	  c.set(Calendar.DATE, 1);
	  c.set(Calendar.HOUR_OF_DAY, 0); // NOT 'HOUR'!
	  c.set(Calendar.MINUTE, 0);
	  c.set(Calendar.SECOND, 0);
	  Date start = c.getTime(); // April 1, midnight

	  int numberOfDays = c.getActualMaximum(Calendar.DAY_OF_MONTH);
	  c.roll(Calendar.MONTH, 1);
	  numberOfDays += c.getActualMaximum(Calendar.DAY_OF_MONTH);
	  c.roll(Calendar.MONTH, 1);
	  numberOfDays += c.getActualMaximum(Calendar.DAY_OF_MONTH);
	  long numberOfMillis = numberOfDays * 86400000L;

	  long increment = start.getTime() + numberOfMillis;
	  Date end = new Date(increment);
	  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", new Locale("",""));
	  System.out.println("bad interval test: " + df.format(end)); // wasn't what you expected?
  }</pre><pre>bad interval test: 2000-07-01 01:00:00 -0700</pre><p>Second, if you construct the interval using a calendar, you may still run into problems with varying intervals and boundary conditions (especially on either end of the year).</p><p>Another source of problems is when dates are converted to a long and then stored. This can lead to a variety of problems. For example, if one assumes that the number of digits in the string representation of a date's long value is constant, one can run out of digits when the value overflows. The digit rollover dates are shown in <a href="#apdx.a">Appendix A</a>.</p><p>Finally, you can have difficulties with storage type conversions. Pay particular attention to rounding errors that occur when you cast values up onto floating point types (or the accidental use of <code>int</code> in Java). For example:</p><pre>  public static void intCastingWoes() {
	  Date d = new Date();
	  System.out.println(d);
	  long l = d.getTime();
	  int interval = 30 * 86400000;
	  l += interval;
	  d = new Date(l);
	  System.out.println("intCastingWoes: " + d);
  }</pre><p>Produces time running backwards:</p><pre>Wed Dec 08 14:35:43 PST 2004
intCastingWoes: Thu Nov 18 21:32:56 PST 2004</pre><h3>Calendars (Logical)</h3><p>Some data isn't supposed to represent a discrete moment of "wall time". For example, when I am asked for my birthdate, I give June 28<sup>th</sup> as the response. I don't mean "June 28 in the time zone I was born in". I mean a sort of "canonical" June 28<sup>th</sup>. Try this code with your birthdate:</p><pre>  public static void myBirthdayAsDate(int year, int month, int day) {
	  Calendar c = new GregorianCalendar();
   // I was born in France. Adjust appropriately...
	  c.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
	  c.set(Calendar.YEAR, year);
	  c.set(Calendar.MONTH, month); // month is zero-based, so 0 = January
	  c.set(Calendar.DATE, day);
	  c.set(Calendar.HOUR_OF_DAY, 0); // don't use Calendar.HOUR here!
	  c.set(Calendar.MINUTE, 0);
	  c.set(Calendar.SECOND, 0);
	  Date d = c.getTime();
	  long value = d.getTime(); // note that it is a negative number for many people!
	  c.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
	  c.setTime(d);
	  System.out.println("myBirthDateAsDate: " + d); // Depending on local TZ...
	  System.out.println(value);
	  System.out.println(c.get(Calendar.DAY_OF_MONTH)); // hmm....
  }</pre><p>This kind of data is represented in Java as a <code>java.util.Calendar</code> object. Calendars represent the transition between wall time and computer time. They can be set to a specific value, like "June 28th", which has a kind of canonical meaning. Calendars abstract the kinds of operations that one expects from dates from our day-to-day activities. For example, one month from June 28th is always July 28th in a Calendar.</p><p>Java provides one concrete calendar implementation, which is the one for the Gregorian Calendar. This is the one used in America and Europe and which is generally used for business world wide. There are many other kinds of calendars, some of which are in modern use, with a variety of purposes, structures and rules (Japanese Era, Buddhist, Islamic, Astronomical, Chinese Traditional, Mayan are just a few examples). The rules and structures of each calendar vary greatly and go beyond the scope of this document, but the main thing to recognize is that calendar practices vary and can affect software processes.</p><p>There is a notorious example in Java. The "Thai Buddhist" calendar is actually an implementation of the Gregorian calendar with one difference. The difference is that the current Era for the calendar starts 543 years earlier than the Gregorian calendar's Common Era. Thus, February 27, 2004 in the Gregorian calendar is February 27<sup>th</sup>. It's just in the year 2547.</p><p>The Thai government managed to persuede Sun to implement this year number in the <code>DateFormat</code> class for some of the various Thai locales. Thus, if you write the following code, you'll get the result shown:</p><pre title="Sample Code">   DateFormat thai = new SimpleDateFormat("yyyy-MM-dd", new Locale("th","TH"));
   DateFormat regular = new SimpleDateFormat("yyyy-MM-dd", new Locale("",""));
   Calendar c = new GregorianCalendar();
   c.set(Calendar.YEAR, 2000);
   c.set(Calendar.MONTH, 1); // February: month is zero-based!
   c.set(Calendar.DATE, 29); // 2000 was a Leap Year!
   Date d1 = c.getTime();
   System.out.println(thai.format(d1));
   System.out.println(regular.format(d1));</pre><pre title="Results">2543-02-29
2000-02-29</pre><p>This also affects parsing date strings to obtain a Date object:</p><pre title="Parsing Dates in Thailand">        Locale.setDefault(new Locale("th","TH"));
        Date d = new Date();
        System.out.println(d);
 /**/   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        d = sdf.parse("2004-02-29");
        System.out.println(d);
        java.sql.Date sqld = new java.sql.Date(d.getTime());
        System.out.println(sqld);
        sqld = java.sql.Date.valueOf("2004-02-29");
        System.out.println(sqld);</pre><pre title="Results">Fri Nov 12 13:29:56 PST 2004
Sun Mar 01 00:00:00 PST 1461
1461-03-01
2004-02-29</pre><p>A common error is to write a line of code like the one marked with <code>/**/</code> in the example above in order to parse timestamps such as ISO 8601 formatted strings. Because no Locale was specified, in Thailand the parser produces dates in the distant past. The <code>long</code> value wrapped in the variable <code>sqld</code> above is "-0x1658b353400L".</p><p>When working with Java Calendar class objects, you have to be careful. Although the methods are relatively logical, real calendars (as I'm sure you're beginning to appreicate) are far from being logical. Consider this quote from the <code>Calendar</code> class JavaDoc:</p><p class="quote"><code><b>Usage model.</b> To motivate the behavior of add() and roll(), consider a user interface component with increment and decrement buttons for the month, day, and year, and an underlying GregorianCalendar. If the interface reads January 31, 1999 and the user presses the month increment button, what should it read? If the underlying implementation uses set(), it might read March 3, 1999. A better result would be February 28, 1999. Furthermore, if the user presses the month increment button again, it should read March 31, 1999, not March 28, 1999. By saving the original date and using either add() or roll(), depending on whether larger fields should be affected, the user interface can behave as most users will intuitively expect.</code></p><p>That's right. The <code>roll</code> and <code>set</code> methods are easy to fool. The following code fragment produces some dates that don't seem logical:</p><pre>Calendar c = new GregorianCalendar();
c.set(Calendar.YEAR, 2004);
c.set(Calendar.MONTH, 0); // January
c.set(Calendar.DATE, 31);
c.roll(Calendar.MONTH, 1);
System.out.println(c.getTime()); // Hint: this is February 29
c.roll(Calendar.MONTH, 1);
System.out.println(c.getTime()); // Hint: this is NOT March 31
c.set(Calendar.MONTH,0); // January again
c.set(Calendar.DATE, 31);
c.set(Calendar.MONTH,1); // February??
System.out.println(c.getTime()); // Hint: this isn't February 29</pre><p>Here are the results:</p><pre>Sun Feb 29 14:05:18 PST 2004
Mon Mar 29 14:05:18 PST 2004
Tue Mar 02 14:05:18 PST 2004</pre><p>Another thing to beware of is time zone differences when working with Calendars. Recall that daylight savings time transitions change the numbers for "hour" when they take place. The Date object that underlies a time is unaffected: <code>Date</code> just continues adding clock-ticks to the epochal date. But the <code>Calendar</code> class models the numbers that people see. Consider:</p><pre>   
        Calendar cal = new GregorianCalendar();
        TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
        cal.setTimeZone(tz);
        cal.set(Calendar.YEAR, 2004);
        cal.set(Calendar.MONTH, 3); // April
        cal.set(Calendar.DATE, 4); // first sunday in April, 2004
        cal.set(Calendar.HOUR_OF_DAY, 0); // midnight
        cal.set(Calendar.MINUTE, 15);
        System.out.print(cal.getTime() + " ");
        System.out.println(Long.toHexString(cal.getTime().getTime()));
        for (int x=0; x&lt;4; x++) {
            cal.roll(Calendar.HOUR, 1);
            if (tz.inDaylightTime(cal.getTime())) System.out.print("DST*");
            System.out.print(cal.getTime() + " ");
            System.out.print(cal.get(Calendar.HOUR_OF_DAY) + " ");
            System.out.println(Long.toHexString(cal.getTime().getTime()));
        }</pre><h3>Calendars (Human)</h3><p>The <code>Calendar</code> and <code>DateFormat</code> classes also encapsulate a variety of interesting information about the way that humans want calendars displayed in a graphical environment. The <code>Calendar</code> class, in particular, knows about weeks: when they start and end and what number of the year that they are. Unlike other calendar operations up to this point, these are strongly locale affected. For example:</p><ul><li>"First Week of the Year" is defined differently in different cultures. It may surprise you to learn that January 1st may occur in the last week of the previous year and that some years may have 53 weeks.</li><li>"First Day of the Week" is culturally dependent. American calendars show Sunday in the left column. European calendars show Monday as the "start of the week" in the left column. Middle Eastern calendars show Saturday or Sunday in the left column because Friday is part of the weekend (and Sunday is not).</li></ul><p>In the following block you can see four examples of the same date and time in four different locales. Note that Saturday/Sunday are highlighted in each case. You should note that this highlighting is tied to the Gregorian Calendar and is not appropriate in all cases. For example, many countries that use Arabic (as in the third calendar) have a weekend that falls on Friday/Saturday. Even ignoring this, there is a wide range of display variations:</p><img src="./about-time000.bmp" alt="U.S. English"/><img src="./about-time001.bmp" alt="French"/><img alt="Arabic" src="./about-time002.bmp"/><img src="./about-time003.bmp" alt="Hindi"/><h3>Time Zones</h3><p>Time zones represent the other major source of time-related errors. <code>Date</code> objects are time zone independent, since they represent a fixed increment in Universal time. So it is always safe to pass <code>Date</code> objects or their internal integer values around.</p><p>Calendars and dates serialized as strings represent a source of trouble, however. Once separated from the source time zone, these objects can easily change value. For example, the original <code>java.util.Date</code> object in JDK 1.0 had constructors like this one:</p><pre>public Date(int year,
            int month,
            int date,
            int hrs,
            int min,
            int sec)

    Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, 
    month, date, hrs, min, sec) or GregorianCalendar(year + 1900, month, 
    date, hrs, min, sec).

    Allocates a Date object and initializes it so that it represents the instant 
    at the start of the second specified by the year, month, date, hrs, min, and 
    sec arguments, in the local time zone.</pre><p>The original <code>Date</code> object had to perform calculations based on assumptions about the relationship of the field values to UTC time based on the local time zone (and other factors). This code had to be changed because of the complexity of calendars and also because storing the fields created problems with time zones.</p><p>For example, I once worked on a product whose date object was made up of fields for year, month, day, hour, minute, and second. There was no indication of time zone, and the code that supported the data type always used local time. The product was a messaging product and the date object actually caused numerous problems for users. </p><p>A date object sent to a machine with a different offset from UTC, or even processed for a date across the daylight savings time boundary, would have a different value than originally intended.</p><p>This also happens if you don't pay attention in XML Schema 1.0 and in certain databases. Consider this piece of XML:</p><pre>&lt;myDate&gt;2004-04-26T14:27:00&lt;/myDate&gt;</pre><p>Since no time zone is present, local time is used to interpret the time.  Here's some Java code that might construct the object above:</p><pre>  public static String sendingNoTZ() {
	  Date d = new Date();
	  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.s", new Locale("",""));
   // we demo the value that should be received first...
	  sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
	  System.out.println("encoding this value: " + sdf.format(d));
   // then we generate the string in the format above
	  sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
	  return sdf.format(d);
  }</pre><p>Then we send that date string to this method (simulating sending it to another time zone):</p><pre>  public static Date receivingNoTZ(String input) {
 System.out.println("encoded value: " + input);
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.s", new Locale("",""));
	sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
	ParsePosition pp = new ParsePosition(0);
	Date d = sdf.parse(input, pp);
	if (pp.getErrorIndex() &lt; 0) {
  System.out.println("resulting value: " + d);
		return d;
	} else {
		return null; // bad parse
	}
  }</pre><p>If I test this, here are some results I might get:</p><pre>encoding this value: 2004-12-09T11:06:16.16 // (this is Pacific Time)
encoded value: 2004-12-09T19:06:16.16 
resulting value: Thu Dec 09 19:06:16 PST 2004</pre><p>The date magically morphs to eight hours in the future. Without time zone or offset information, it is impossible to reconcile the dates and in fact impossible to compare them. Coupled with leap year and daylight savings changes, dates and times become useless. Synchronizing all of your systems to UTC or a specific time zone can help, but this becomes increasingly inconvenient in a distributed environment.</p><p>Databases too distinguish between dates with timezone information (which can include Date objects when using JDBC) and dates that have no time zone information (which can include poorly formed PreparedStatements). Losing the time zone information results in peculiar bugs in which results appear out of order, time outs are triggered when they shouldn't be, scheduled processes run at wildly variant times, and other difficult to trace issues.</p><h2>What Can Go Wrong?</h2><p>Testing software for date and time problems requires a number of approaches in order to be successful, since there are a variety of potential issues. In this section, we'll look at basic testing strategies and the related issues that they'll uncover.</p><h3>Different Locales</h3><p>Changing the runtime locale of your server and clients (including browser Accept-Language headers) allows you to see if the code is making assumptions about locale. Changing the server and client locale from US English to some other language should have these results:</p><ul><li>Dates displayed as strings should appear in the webMethods timestamp format, which is locale neutral. That is: "2004-11-20 15:47:13 PST".</li><li>If dates appear in a locale affected format (such as in a Workflow or in the Portal), then the language and format of the date should change to match the <em>client's</em> locale and not stay in English. The format should <em>not</em> match that of the server unless the client's locale does.</li><li>The time zone must always be displayed. If it is possible to match the client's time zone, then test that this is the case. In most cases, dates and times will be displayed in the server's time zone in a browser and in the client's time zone in a thick (Java) client.</li></ul><h3>Spooky Messages From the Future and Past</h3><p>Operate all of the components of the system in a different time zone, even when the locales are all set to U.S. English. Choose time zones that cross the International Date Line (such as Japan Standard Time) for some of your systems. </p><p class="example">Note that time zone is completely separate from locale. You can set this without changing to (for example) the Japanese locale, installing Japanese fonts, or keyboards or anything special.</p><p>Build tests that exercise the following scenarios:</p><ul><li>A date sent from a server whose time zone is "ahead" to a server in a time zone that is "behind" (e.g. from Eastern Time to Pacific Time) arrives and is interpreted correctly (and not "from the past").</li><li>A date sent from a server whose time zone is "behind" to a server in a time zone that is "ahead" (e.g. from Pacific Time to Eastern Time) arrives and is interpreted correctly (and not "from the future").</li><li>A date sent across the International Date Line works correctly (e.g. from Japan Standard Time to Pacific Time).</li><li>Dates that cross or occur during the Daylight Savings Time transition work correctly. Test times near 2 A.M. on the date of the transition. Also test reporting functions that select across the boundary (e.g. that selections do not occur too early or too late).</li><li>Recurring execution items and schedulers at the DST boundary. <ul><li>Check that something scheduled to run at 2 AM nightly actually executes on the date in the spring when there is no "2 AM" (there is 1 AM standard time followed by 3 AM DST).</li><li>Check that something scheduled to run at 1 AM nightly doesn't execute twice on the date in the autumn when there are two 1 AM events.</li><li>Don't forget that northern and southern hemispheres reverse DST!</li></ul></li><li>Check that leap years are handled correctly. This includes the exceptional years 2000 and 2100.</li><li>Check that your code works correctly in the Thai for Thailand locale.</li><li>Check that calendric dates are <em>not</em> time zone affected. For example, check that a "birth date" field remains static regardless of time zone applied to it. This requires a strategy that uses UTC for the field or serializing as ISO 8601 (or another calendar-friendly format).</li></ul><h3>Databases</h3><p>Databases generally use different mechanisms than your Java code. The mere fact that SQL databases use strings that are locale affected in order to do queries can lead to date conversion problems (modern Type IV JDBC drivers can avoid this by storing <code>java.sql.*</code> data types directly). Test that data that is stored in the database is retrieved and interpreted as the same time.</p><ul><li>Test with a database that does not use U.S. English as its locale connecting from a maching in a different locale (which may be U.S. English). Date/time formats inserted into statements can cause problems for drivers or result in bizarre offsets.</li><li>Use a database running in a different time zone from the server.</li><li>Store and retrieve dates sent from across time zone boundaries. Pay particular attention to result sets to ensure that values that should be present actually are.</li><li>Test DST and important date (such as Y2K-related date) transitions.</li></ul><h2>Summary</h2><p>Dates and times are the source of bugs in many applications. A little testing and some forethought when coding can help alleviate these problems.</p><h2 id="apdx.a">Appendix A. Resources</h2><p>The code snippets in this document are from a sample program "AboutTime.java", which you can use to demonstrate these issues on your own machine. </p><p>The calendar dialog boxes are from a demo program "CalendarDemo". This demo requires the webMethods Integration Server client API v6.0 or later (client.jar) and the ICU4J v2.6 library (icu4j_2_6.jar) to run.</p><p>The following table of values is the list of dates for each change in the number of digits in the long value of a Date object. The program to generate this data is called "FindTroubleDates.java". All of these times are shown in Eastern Time. Octal, decimal, and hex values are given (first for the positive number and then the negative value).</p><pre>decimal places: 0
(oct):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(dec):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(hex):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
decimal places: 1
(oct):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(dec):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(hex):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
decimal places: 2
(oct):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(dec):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(hex):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
decimal places: 3
(oct):Dec.31 19:00:00.00 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(dec):Dec.31 19:00:01.01 EST 1969 AD
      Dec.31 18:59:59.59 EST 1969 AD
(hex):Dec.31 19:00:04.04 EST 1969 AD
      Dec.31 18:59:55.55 EST 1969 AD
decimal places: 4
(oct):Dec.31 19:00:04.04 EST 1969 AD
      Dec.31 18:59:55.55 EST 1969 AD
(dec):Dec.31 19:00:10.10 EST 1969 AD
      Dec.31 18:59:50.50 EST 1969 AD
(hex):Dec.31 19:01:05.05 EST 1969 AD
      Dec.31 18:58:54.54 EST 1969 AD
decimal places: 5
(oct):Dec.31 19:00:32.32 EST 1969 AD
      Dec.31 18:59:27.27 EST 1969 AD
(dec):Dec.31 19:01:40.40 EST 1969 AD
      Dec.31 18:58:20.20 EST 1969 AD
(hex):Dec.31 19:17:28.28 EST 1969 AD
      Dec.31 18:42:31.31 EST 1969 AD
decimal places: 6
(oct):Dec.31 19:04:22.22 EST 1969 AD
      Dec.31 18:55:37.37 EST 1969 AD
(dec):Dec.31 19:16:40.40 EST 1969 AD
      Dec.31 18:43:20.20 EST 1969 AD
(hex):Dec.31 23:39:37.37 EST 1969 AD
      Dec.31 14:20:22.22 EST 1969 AD
decimal places: 7
(oct):Dec.31 19:34:57.57 EST 1969 AD
      Dec.31 18:25:02.02 EST 1969 AD
(dec):Dec.31 21:46:40.40 EST 1969 AD
      Dec.31 16:13:20.20 EST 1969 AD
(hex):Jan.03 21:33:55.55 EST 1970 AD
      Dec.28 16:26:04.04 EST 1969 AD
decimal places: 8
(oct):Dec.31 23:39:37.37 EST 1969 AD
      Dec.31 14:20:22.22 EST 1969 AD
(dec):Jan.01 22:46:40.40 EST 1970 AD
      Dec.30 15:13:20.20 EST 1969 AD
(hex):Feb.19 12:02:47.47 EST 1970 AD
      Nov.12 01:57:12.12 EST 1969 AD
decimal places: 9
(oct):Jan.02 08:16:57.57 EST 1970 AD
      Dec.30 05:43:02.02 EST 1969 AD
(dec):Jan.12 08:46:40.40 EST 1970 AD
      Dec.20 05:13:20.20 EST 1969 AD
(hex):Mar.06 03:44:36.36 EST 1972 AD
      Oct.28 11:15:23.23 EDT 1967 AD
decimal places: 10
(oct):Jan.13 05:15:41.41 EST 1970 AD
      Dec.19 08:44:18.18 EST 1969 AD
(dec):Apr.26 13:46:40.40 EDT 1970 AD
      Sep.07 02:13:20.20 EDT 1969 AD
(hex):Nov.03 14:53:47.47 EST 2004 AD
      Feb.27 23:06:12.12 EST 1935 AD
decimal places: 11
(oct):Apr.10 05:05:34.34 EST 1970 AD
      Sep.23 09:54:25.25 EDT 1969 AD
(dec):Mar.03 04:46:40.40 EST 1973 AD
      Oct.31 09:13:20.20 EST 1966 AD
(hex):Jun.23 02:20:44.44 EDT 2527 AD
      Jul.02 12:39:15.15 EST 1412 AD
decimal places: 12
(oct):Mar.06 03:44:36.36 EST 1972 AD
      Oct.28 11:15:23.23 EDT 1967 AD
(dec):Sep.08 21:46:40.40 EDT 2001 AD
      Apr.24 18:13:20.20 EDT 1938 AD
(hex):Aug.02 01:31:50.50 EDT 10889 AD
      Jul.24 13:28:09.09 EST 6951 BC
decimal places: 13
(oct):Jun.03 17:56:53.53 EDT 1987 AD
      Jul.30 22:03:06.06 EDT 1952 AD
(dec):Nov.20 12:46:40.40 EST 2286 AD
      Feb.10 01:13:20.20 EST 1653 AD
(hex):May.23 12:29:30.30 EDT 144683 AD
      Jul.04 02:30:29.29 EST 140742 BC
decimal places: 14
(oct):May.15 03:35:11.11 EDT 2109 AD
      Aug.19 11:24:48.48 EST 1830 AD
(dec):Nov.16 04:46:40.40 EST 5138 AD
      Feb.26 09:13:20.20 EST 1200 BC
(hex):Apr.02 18:52:07.07 EST 2285384 AD
      Aug.06 19:07:52.52 EST 2281399 BC
decimal places: 15
(oct):Dec.12 07:41:28.28 EST 3084 AD
      Jan.15 06:18:31.31 EST 0855 AD
(dec):Sep.26 21:46:40.40 EDT 33658 AD
      Nov.16 17:13:20.20 EST 29720 BC
(hex):Jan.28 16:54:06.06 EST 36536598 AD
      Jan.31 21:05:53.53 EST 36531909 BC
decimal places: 16
(oct):Aug.02 01:31:50.50 EDT 10889 AD
      Jul.24 13:28:09.09 EST 6951 BC
(dec):May.20 13:46:40.40 EDT 318857 AD
      Feb.01 01:13:20.20 EST 314912 BC
</pre><h2>Acknowledgements</h2><p>Some of the text and the table in the secton on "computer time" is taken from the article by Mark Davis, Chief Globalization Architect, IBM that is linked in that section. Other information was adapted from the links provided. Any errors, of course, are the responsibility of the author.</p><div id="footer" class="footer">
  <p><a href="http://jigsaw.w3.org/css-validator/">
  <img style="border:0;width:88px;height:31px;float:right" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!"/></a>
   <a href="http://validator.w3.org/check/referer">
   <img style="border:0;width:88px;height:31px;float:right" src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!"/></a>
   <a href="http://www.unicode.org"><img style="width:88px;height:31px;background:inherit;border:0;float:right" src="http://www.w3.org/International/icons/UniEncWhiteBord.gif" alt="Unicode Encoded"/></a></p>
      

  </div></body>
</html>
