Summary: General summary of calendars, dates, and times from past to the present. This includes details on using the ISO 8601 standard in and out of computers. It ends with information for software developers wanting to properly use dates and times.
shortcut to
ISO 8601
standard
|
This document should be interesting to anyone interested in
dates, times, or calendars.
Readers may be regular people, managers,
or people that develop computer software.
The document has been written so that anyone may start at the beginning
and stop once they have had enough on the subject.
The document starts with a short history of calendars and timekeeping. Next comes a discussion of various standards, especially the "new" ISO 8601 that is gaining in popularity on an international basis. The final sections are for authors of computer programs. The technical sections start with general use of date and times and then advance to specific examples in different programming languages. While these final sections cover many programming languages, the main effort is for C and UNIX along with derived languages and operating systems, such as Linux, C++, and the Javas.
|
|
This document is under revision and subject to change (2005-11).
Indeed, work is (slowly) being done on a major revision of this document.
Some of the links that have expired since this document was first written have yet to be found and corrected by this author. Please visit http://www.exit109.com/~ghealton/.dates.html for the list of my current time and date links (dot dates dot html). |
| While this document was originally written before the Year 2000 to help software developers cope with it, and much of the tense herein is past tense, the majority of the information still applies to new programs being written today. |
| The information in this document is on a best effort basis. The author actively solicits additions, corrections, and clarifications. Because this documentation and code herein is free of charge, there is no warranty for the contents. All use of the information herein is at the user's own risk. |
Webmasters with links to this site should notify the author to be
advised of the update.
This is important as the new file will have a new file name.
Perhaps even a new domain name.
This list of registered references is included in
http://www.exit109.com/~ghealton/.home.html
(dot home dot html)
under References To My Web Pages.
Prefer links similar to:
|
| Portions of this document copyright 1995-2005 by
Gilbert Healton
(ghealton@exit109.com)
All rights reserved. Permission is granted to reproduce the document, in whole or in part, for local use providing this copyright notice, this table box, and the title, including author's name, are reproduced in full and downloaders keeps their archives current by checking back at least once a quarter or registering with the author to be advised of any significant updates. |
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Trademarks this author is aware of use the capitalization associated with the trademark. Known trademarks follow. Click on the trademark to get the official Trademark Usage Guide from the trademark owner (if available on the web). Click on the owner name to get the owner's home page (again, if available).
- IBM
is a registered trademark of International Business Machines, Inc.
- Microsoft
, MS-DOS
, Windows
, Windows 95
and Windows NT
are registered trademarks of Microsoft Corporation.
- UNIX
is a registered trademark of The Open Group.
Please let the author know of any trademarks used in this document that are not listed here.
The section for general readers provide a history of calendars, times, and related background information many find interesting. The document starts with a section for general readers and gets more complex as it goes along. Therefore general readers may simply read until they've had enough on the subject. A few pieces of technical gibberish have been sprinkled throughout this section to provide important information to technical readers. Normal people may simply ignore these short bursts of strangeness.
The sections for programmers describe ways programs misuse or properly use dates and times. How to spot and repair bad date code along with writing good date code. Year 2000 problems are just one point covered herein.
[Y2K] leads information describing techniques frequently associated with Year 2000 problems. Clicking on the [Y2K] should advance you through a circular list of all [Y2K] notes in this document.
Y2K presents a unique challenge to the computer industry and its users. Never before has such an immovable deadline hit so much of the industry. Year 2000 can not be postponed if the software is late. Unlike typical bugs, which strike at random intervals or at those customers trying something new, Y2K can strike across the entire customer base, striking at the same time, at customers that haven't changed anything. Not just in one part of the program, but at numerous locations of many programs. Critical supplies from key vendors are also at risk at the same time, both for Y2K and overloading, which may reduce the resources you have available to you for repairing your problems.
The Roman Calendar, which the current Gregorian Calendar is derived from, was viewed differently by the Romans than we do today. Rather than counting days up in the month, they set two key reference points in each month and counted the days remaining until the reference point. The first of the month was the Kalendae (or Calends in today's desk dictionary, sometimes spelled as Kalends in other sources) while the middle of the month was the Idus (or Ides). The Ides was the 13'th day of most months and the 15'th day for months with 31 days.
One day before the Ides of March was March-14.
One day before the Calends of April was March-31.
(With the Year 2000 problem, we need to "beware the Calends of January".)
This author has also seen references to the Nonae (Nones) which seems to be the 9'th day before the Idesi (13th or 15th of the month), Adjust the previous confusion accordingly if you encounter this term.
The old Roman Calendar also considered the Calends of January to start a new year (personal observation: shortly after the winter days start to get longer). However, when it came along, the Christian Church changed this in 567 by order of the Council of Tours, for religious/political purposes. However, exactly what day years should start on was not well specified and varied from country to country and time to time. March was a popular month to start new years (spring time, when the earth came alive again), though there was no agreement on what day in March should start a new year. The Calends and Ides of March were among the more popular selections for March new years.
By 46 BCE the Roman calendar was a major mess. Among other things the lack of leap years had gradually lost enough days to make the calendar claim spring, the start of a new year, the Calends of March, actually occurred in what was really late November, a few days before the Calends of December. Not a good time to plant your spring crops.
Julius Caesar, under the advice of the astronomer Sosigenes of Alexandria, issued a decree that lengthened 46 BCE to 445 days to bring the calendar year into line with the solar year. This made the longest year on record.
As part of the 46 BCE correction, subsequent years had an extra day added six days before the Calends of March every fourth year. Rather than making a separate day number, this month had two "six days before the Calends of March", or "two sixes", which the current word bissextile is derived from. Thus February-24 is historically the leap day, not February-29. In the America and the European community this is often called the "Old Style Date" or "Old Style Calendar".
Ignoring differing leap years, the months used in this calendar match the months in the current Gregorian Calendar.
Unfortunately, the priests of the time greatly botched leap year calculations after this calendar correction and it took a few decades to discover this fact. Claus Tøndering's Calendar FAQ details the aftermath of these errors lasting through 4 CE, which omitted 0004-02-29.
Every 128 years the Julian Calendar became off by an additional day. By 1263 Pope Urban IV received a letter from Roger Bacon urging a calendar adjustment to correct the current error and prevent future errors. In 1582 Pope Gregory XIII, working with the Council of Trent, acted on this solution when it was proposed again. The 10 extra days in the year were taken from October to restore the equinox to March-21.
The rules of 100 and 400 in calculating leap years were also added at this time.
Leap years are years evenly divisible by 4, unless the year is evenly divisible by 100. However years evenly divisible by 400 remain leap years.
In the America and the European community this is often called the "New Style Date" or "New Style Calendar".
While the Gregorian Calendar was surprisingly accurate, it was slow to be adopted by some countries, especially in Protestant countries. The Protestant Reformation started in 1517-October-31 and, for political reasons, often greatly delayed the adoption of the Gregorian Calendar in Protestant countries.
Effective in 1752 the British Parliament adopted the British Calendar Act of 1751, taking the eleven extra days from September (the British calendar became an additional day off in the year 1700, which British Calendars considered a leap year and Gregorian Calendars did not). The parts of America under the control of the British followed this change. The parts under control of France and Spain changed in 1582. Other places changed at other times. What a mess.
Along with dropping 11 days from September, the legal start of year, March-25, was moved to match the common practice of January-01. This made the stub year 1751 the shortest year on record: it consisted only of March-25 through December-31. It was only 282 days long
The second shortest year depends on the country you are in. Except for countries where the start of the year changed, such as England, the shortest year was during the Julian to Gregorian calendar change. The year length depended on how many days were dropped from that year. Corrections made during leap years usually resulted in an additional day being added to the year (normally 1752 would of been a leap year, but as this stub year did not have a February, it could not be a leap year). Changes made in 1582 resulted in years of 355 days. Changes in the 1700's made years 354 days long, or 355 days in leap years. Changes made in the 1800's produced 353/354 day years. Changes made in the 1900's or 2000's require years 352/353 days long.
The common practice of using the Pope's calendar in England before 1752 resulted in some confusion as to what year it was for the months of January, February, and part of March. To avoid confusion many colonial records used dates providing both the official and common year. A typical example is "5 Feb 1750/51".
After 11 days were dropped from 1752-September many people adjusted annual events based on previous dates, such as birthdays, to continue observing them a true year apart. This resulted in people writing both days and both years for some dates when referring to the "old style" dates. George Washington's birthday could be written as "11/22 Feb 1732/33".
The Year 2000 problem is not the first point of major confusion over calendars.
Countries like Greece didn't adopt the Gregorian reform until years as late as 1923, when they had to drop 13 days. Whitaker's Almanac contains a complete section on the differing calendars in use around the world and throughout the ages. Claus Tøndering's Calendar FAQ makes the dates of the changeover for many countries available on the web.
The Gregorian Calendar is by no means universal. Some places, or religions, still use the old Julian Calendar while others have their own historic calendars that continue to be used to this day. There are many such calendars in use today... well into three digit values.
The concept of months appears to have originally been based on the moon's "monthly cycle" (synodic period) of about 354.367 days Early calendars based on the synodic month quickly came out of sync with the year as a lunar month is about 29.5309 days.
Today's Gregorian calendar is based only on the period of earth's year around the sun. However, the Islamic calendar still uses the moon's period and not the sun's.
Lunisolar calendars use both the lunar and solar cycles. Every few years a whole month is inserted into the year to bring the calendar back into line with the solar calendar. The Chinese and Hebrew calendars are modern examples of lunisoloar calendars.
When astronomers run dates backwards before year 1 BCE they simply use straight number signs. Rather than use 1 BCE they use year 0. The year 2 BCE becomes year -1, etc. This helps keep the computers doing their calculations happy.
The three other times to start a new day have been seen by this author. Morning, when the sun rises; noon, when the sun is high in the sky; and evening, when dusk starts. These are still in use today in different parts of the world, especially for religious or other special uses.
Noon is the historic start of day for the old Roman Empire. This author suspects that the decision to start a new day at noon had something to do with watching sundial shadows peak and fall at noon along with keeping all astrological observations at night, where the sky was much more interesting, in the same "day". What really is different between current and Roman days is that Romans tracked time with sundials using 12 hours of daylight and 12 hours of night. Therefore the length of a Roman "hour" was longer in summer and shorter in winter. Today's astronomers continue to use the noon-to-noon days when tracking astronomical days.
Rainfall and river flow in the UK are measured from 9am to 9am and ascribed to the day which contains the greater part of the time.
It's been rumored that some transport companies record days using 03:00 to 27:00 to allow customers going to their work day to be scheduled on the same transport day. This author would love to hear from anyone with definitive knowledge on the subject, historical or current.
How we track time also has changed. Long ago noon was when the sun was high in the sky, a purely local event. The local clock keeper of the town would ensure the clock matched the sun each day and everyone took their time from the official local clock. With the advent of faster travel, in particular the railroads, a need for a standard, predictable, time arose. Many long distances only had a single-track railroad and without electronic communications running trains strictly on schedule was vital to avoiding collisions.
In 1884 an international convention divided the world into twenty-four time zones. There is no international standard for the actual names or abbreviations of these zones. Each country is free to define its own names and abbreviations and RFC-822 defines its own set of names. Countries may declare their own compliance to time zones. Indeed some countries are 15, 30, and 45 minutes off of UTC. Historically even stranger offsets from UTC have been used. From 1909-May-01 through 1937-June-30 the Netherlands was exactly 19 minutes and 32.13 seconds ahead of UTC by law (such offsets can not be represented exactly in the ISO 8601 standard). Programs that need to process time zones must allow minute, even second, offsets. The time zones are not straight lines, but snake around to meet the needs of the local people.
Time zones center on the "prime meridian", which was originally defined as longitude zero, a line that bisected a critical part of the main telescope at the Royal Observatory at Greenwich in south-east London. All countries defined their time as some offset, positive or negative, away from "Greenwich Mean Time" (GMT). GMT is based on mean local time at the an agreed on zero longitude. This Mean Time at Greenwich England is not subject to daylight-saving rules (local Greenwich time, however, is subject to British daylight-saving time rules). The Americas are negative while Asia and most of Europe tend to be positive. See the National Institute of Standards and Technology Glossary for more information.
As this was basically an American and European convention, the problem of new days was dumped in the middle of the biggest body of water, the Pacific Ocean, twelve time zones away, on the other side of the world. This is the "International Date Line" and tends to be as far from different countries as possible. Crossing the International Date Line adds or subtracts a day from your local time, depending on the direction of travel. While written about by a few people for over a century, the first people this actually happened to, much to their surprise, were survivors of Magellan's crew on their 1522 return to Cape Verde Islands when the day turned out to be Thursday rather than the expected Wednesday.
Nautical time keeping, and various other international users, including the U.S. Military, have set up a series of single-letter codes to represent different zone offsets.
M Y X V U T S R Q P O N Z A B C D E F G H I K L M
with "Z" ("Zulu") holding the prime meridian, or Zero offset. "Y" being "-11", "M" being "+12" (note the lack of the letters "J" and "W"). These letter codes do not work in countries with offsets not an even multiple of 60 minutes from Zulu (UTC) time.
RFC-822 attempted to implement these letter codes. While the text portion of the RFC described the offsets correctly, the sample numeric values had their signs reversed from the (Mil?) standard RFC-822 was attempting to model. Except for Z, which has an offset of Zero, the success of a program using RFC-822 would depend on what section of the RFC was used to write the code.
There are no international standards for "saving time". Unless bound by some agreement, each country is free to define its own rules on the subject.
Leap seconds may be positive or negative, adding or subtracting a second on the last minute of a day. On a "leap second" day the day ends at the completion of 23:59:58 for negative leap seconds and after the completion of 23:59:60 for positive leap seconds. The next second is "00:00:00" of the next day, which is also known as 24:00:00.
The previous leap second was 2008-December-31 (2008-12-31).
Long "dry spells" in leap seconds can occur from time to time, such as the one that started 1998-December-31 (1998-12-31) and ended on 2005-December-12 for a period of six years. That's how the world turns.
Leap Seconds are added (or subtracted) at the same time around the globe at 23:59:59 UTC, whatever the local time may be, regardless of any local time zones.
Date TIME Location 1998-12-31 23:59:60 UTC 1999-01-01 08:59:60 Melbourne Australia 1998-12-31 17:59:60 Local Central USA time
Currently (2009-01) the timing of leap seconds is now determined by the International Earth Rotation and Reference Systems Service (IERS).
There has been some discussion on the future of UTC by replacing UTC and its leap seconds in the year 2022 with a new "Temps International" (TI) time when UTC is 50 years old. TI time is not linked with the earth's rotation and would require changing local time zone offsets every few centuries to keep within an hour of daylight times (leap hours?). Time zones maintaining daylight savings time could eliminate the extra hour at the end of savings time for that year's correction.
This author's though: why bother. The legal concept of time zones, etc., have not stayed stable for fifty years in the last century and the current century shows no signs of stopping. Other ways of addressing the technical issues seem to exist.
In 1992 the European Committee For Standardization has adopted ISO 8601 under the standard EN 28601 to end the traditional confusion involving periods, slashes, the order of the numbers, and other date formats formerly used throughout Europe.
Companies that wish to do business on a global scale are best served by avoiding date formats local to their own country. Distributing local date formats on a global basis tends to cause confusion to people in other countries. For web pages being read by world wide audiences, using ISO 8601 format dates and times seems the only sane way to present dates and times. One Internet poll decidedly favors using ISO 8601 format for date and times on web pages.
A growing number of individuals and companies are changing from writing dates in their traditional local format to using ISO 8601 compliant dates and times (e.g., yyyy-mm-dd hh:mm or yyyy-ooo hh:mm) in every day documents. This is especially true for documents used in international trade. ISO 8601 week numbers are also increasingly being used to specify specific weeks.
The growing availability and popularity of low cost digital watches and the increasing use of computers is making the hh:mm and hh:mm:ss formats adopted by ISO 8601 for time well known throughout the world.
The United Nations Economic Commission for Europe, Working Party on Facilitation of International Trade Procedures, Recommendation 07, The Numerical Representation of Dates, Time and Periods of Time, is based on the ISO 8601 standard. Visit UN/ECE Trade Facilitation Recommendation 07 at http://www.unece.org/cefact/rec/rec07en.htm for more information.
NOTE: While the following interpretation of ISO 8601 should be sufficient for the vast majority of users, it is still only a summary. The actual standard is much longer, repeats many details, and should be consulted for full details. Major corporations or people developing applications particularly sensitive to date time standards should purchase an official copy of the standard rather than rely on comments or free draft copies.
Those who want more, but without the standard, may vist RFC-3339, which defines a date and time format for use in Internet protocols that is a profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
NOTE: Because ISO 8601 is so vast and complex many companies are issuing their own standard that follows only a selected subset of the full standard. In practice this tends to be use the yyyy-mm-dd format with an hh:mm or hh:mm:ss format for time. When more accuracy is needed, the hh:mm:ss,nnn format (note comma) allows whatever precision is appropriate to be used. Trailing zeros are always added to have all times use the same number of significant digits.
The ISO 8601 format is large and complex and sets forth many ways of representing dates and times. The three major forms of date and times defined by ISO 8601 follow. In practice only the first two formats enjoy general use.
yyyy-mm-ddTHH:MM:SS
yyyy-dddTHH:MM:SS
yyyy-Www-dTHH:MM:SS
Note that hyphens separate date fields and colons separate time fields. Dates using these characters are said to be in "extended format". The fields are:
- yyyy-mm-dd
- Year (usually four digits, but see "truncation", in section 4.2.3), month, and day. When present, month and day are written using two-digit numbers, with leading zeros as appropriate. Month is 01 through 12 and day is 01 through 31, as appropriate.
printf( "%04d-%02d-%02d", d.tm_year+1900, d.tm_mon+1, d.tm_day );NOTE: As a partial transition to ISO 8601, a number of web sites use the month name or abbreviation in a date when changing their dates to use year, month, day formats. The month names January through December and the weekdays Monday through Sunday are acknowledged in 4.3.2.1 of ISO 8601:2000 for reference, but not for official use. Abbreviations of these names are not mentioned in the standard.
NOTE: the standard requires that years on or before 1582 be avoided except by mutual agreement. For practical efforts the year 1752 may provide a safer limit. The standard assumes the Gregorian calendar is run backwards as if it was always in use (a "proleptic" calendar). This is unlikely to be acceptable to many uses involving historic dates. Historians discussing early dates tend to use the Julian calendar, and for dates before 45 BCE, a proleptic Julian calendar.
Thus proleptic years need to be considered an agreed upon, but imaginary, calendar when referring to dates before the Gregorian calendar correction came effective. Such dates need to be converted to the appropriate local date.
- yyyy-ddd
- Year and Ordinal Day number (001-365, 366 on leap years: always three digits).
printf( "%04d-%03d", d.tm_year+1900, d.tm_yday+1 );- yyyy-Www-d
- Year and Week Number (01 to 52 or 53). The week number may be followed by an optional "day of week" number with 1 being Monday and 7 being Sunday.
printf( "%04d-W%02d-%d", d.tm_year+1900, Week, WeekDay );- T
- The literal character T is used to separate the date from the time of day when combining dates and time. While an upper case "T" is the letter of choice a lower case "t" may be used if the upper case "T" is not available in the character set. See "Truncation and Reduction", in section 4.2.3, for details of omitting the T from dates and times.
If only a time field is present, a T may be placed before it to identify it as a time: T010203
While replacing the "T" with a space makes the date and time much easier for human eyes, and appears to be a very common practice, technically it is a violation of strict ISO 8601 notation (see ISO 8601:2000 4.4). This is true for spaces embedded anywhere within a date or time. However,
While the original scope for ISO 8601 was for computer to computer "Information Interchange", ISO 8601 is now being used in many areas the original standards committee never considered when the standard was designed. Thus an out of specification space character is acceptable for displaying dates for people as computer to human transfers are not strictly within ISO 8601's scope. Even on computer transfers this date can be made in scope if the date and time are considered two separate, but related, values.
Suggestions from this author for character format dates and times: Use the "T" when the prime audience for dates and times are other software packages and space for dates and times read by humans. When using spaces, ensure you word the specification to state/imply that separate date and time fields are being used rather than a single date and time field to avoid being accused of being an idiot by ISO 8601 purists.
- HH:MM:SS
- time stamp, in a 24-hour clock. Typically each portion of the time is written using two-digit numbers, using leading zeros as needed.
printf( "%02d:%02d:%02d", d.tm_hour, d.tm_min, d.tm_sec );Fractional time can be represented using decimal notations after the HH, MM, or SS. Typically after the SS. The character ISO 8601 prefers to use for the decimal character is a comma (,). The only other choice is a period (".", e.g., "full stops"). Two digits will always be found to the left of the decimal sign. Once a fraction is started, subsequent MM or SS fields, if any, must be omitted (e.g., 15,5:30 is invalid).
printf( "%02d:%02d:%02d,%03d", d.tm_hour, d.tm_min, d.tm_sec, (int)ftime_time.millitm );
printf( "%02d:%02d:%06.3f", d.tm_hour, d.tm_min, FloatSecond );
(NOTE: do not use %g notation!)
More Information: There is quite a lot more to ISO 8601, some of which is covered in this section. See the standard if you need serious or legal details. This author maintains a list of locations copies of ISO 8601 may be accessed at in ISO 8601 Commentary Links. The list is kept list outside this document due to the constantly changing nature of the list.
Leap years are years evenly divisible by 4, unless the year is evenly divisible by 100. However years evenly divisible by 400 remain leap years. ISO 8601 considers the proleptic Gregorian year "0000" a leap year
See Gregorian Calendar and Leap Years", 3.3, for the history of Leap Years.
Leap seconds add or subtract a second to a day. Positive leap seconds added to a day are denoted 23:59:60 and occur after 23:59:59, but before 24:00:00. See Leap Seconds and UTC, 3.6.4, for the history, and additional details, of Leap Seconds.
While the ISO 8601 standard allows for negative leap seconds, where the day ends at 23:59:58, a negative leap second has yet to occur. Application software sensitive to leap seconds must be designed to allow for both the more traditional positive and rarer negative leap seconds. NOTE: most operating systems do not support leap seconds.
Midnight: 24:00:00 of one day is considered to be the same as 00:00:00 of the next day. When the hour is 24, the rest of the time must be zeros. For practical purposes, this author advises 24:00:00 to be considered beyond the last instant of the current day in calculations, which should never be used for logging the time of actual events.
Authors advice: using 24:00:00 has a history of causing confusion on what day it is on. This explicit ISO definition of 24:00 being 00:00 of the next day is not well known.
If 24:00 must be used, only use 24:00 as an ending time. Events using 24:00 should not actually be in, billed to, cross over, or otherwise use, midnight. Rather, treat 24:00 as an instant after the completion of the current day (instant after 23:59.59.9999999...).
Basic versus Extended Formats: The "basic" format provides the minimum characters needed for the desired precision (e.g., 19991231T235900). The "extended" format adds additional separator characters, by specific rules, to make fields easier to read (e.g., 1999-12-31T23:59:00).
Expanded Formats By mutual agreement of all parties the number of digits in a year may be expanded to record years with values greater than 9999. Further, a plus (+) or minus sign (-) must precede the year's value to indicate if the year is C.E. (a.k.a., A.D), which uses plus, or B.C.E. (a.k.a. B.C.), which uses minus. The use of a sign appears to be required, even if only C.E. (positive) years are being used.
This expanded year format may be used in any year field. The number of digits in a year must be part of the mutual agreement.
Great caution needs to be observed when using expanded formats as ISO 8601 requires the Gregorian calendar to be used for all specifications. The break between Julian and Gregorian is not acknowledged by ISO 8601. This makes early dates, especially those before the local calendar conversion, suspect. It is common practice by historians to use Julian calendars before 1582. See the notes in Date Formats, 4.2.2, about "proleptic" calendars for more details about this problem.
Week Numbers: ISO 8601 also allows for week numbers to be tracked using a yyyy-Www notation rather than using month and day numbers. Week "01" is defined as being the first Monday through Sunday week that has a Thursday in it (author's hint: weeks containing January-04 are always week 01).
Day numbers in a week (ISO ordinal day numbers) start at 1 for Monday and
run through 7 for Sunday.
There are always three days before Thursday
and three days after Thursday in ISO weeks.
printf( "%04d-W%02d", d.tm_year+1900 );
printf( "%04d-W%02d-%1d", d.tm_year+1900, WeekNumber,
DayInWeek );
Notes:
In the following tables the left table shows every possible ending week for an ISO 8601 year. Each row in this table represents one of the possible years. The corresponding row of the right-hand table shows the first week for the following ISO 8601 year.
Last week of prior year (December) M Tu W Th F St Su 22 23 24 25 26 27 28 23 24 25 26 27 28 29 24 25 26 27 28 29 30 25 26 27 28 29 30 31 26 27 28 29 30 31 1 27 28 29 30 31 1 2 28 29 30 31 1 2 3 ==>
First week of following year (January) M Tu W Th F St Su 29 30 31 1 2 3 4 30 31 1 2 3 4 5 31 1 2 3 4 5 6 1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 4 5 6 7 8 9 4 5 6 7 8 9 10 Examples: the date 2001-Dec-31 (a Monday) is considered to be a part of the first week of 2002 in the ISO week calendar. This is written as 2002-W01-1 (that is "Year 2002, Week 01, Day 1"), even though in the Gregorian calendar it is actually the last day of 2001. The next day, 2002-Jan-01 (Tuesday), is therefore 2002-W01-2 ('Year 2002, Week 01, Day 2').
Time Intervals: ISO 8601
also allows intervals between two points in time to be specified.
These intervals may be associated with actual time points
or they may be more abstract without being associated with specific time points.
Intervals may include any valid combination of dates and/or times.
Recurring intervals may also be specified.
P2Y3M5DT8H4M3S
1999-12-31T23:59:59/2000-02-29T24:00:00
1999-12-31T23:59:59/P0Y1M29DT1S
P0Y1M29DT1S/2002-02-29T24:00:00
P0004-05-06T12Full truncation and reduction seem to be allowed with this alternative format.
P0004-156T12
P0004-W22-2T12
R8/P1Y
R6/P15W
R0/P12D
R1/PT12H
The ISO 8601 standard also allows R to be specified with intervals providing a specific time point:
R4/1999-12-31/2000-12-31
This format identifies the duration of the first period (1999-12-31/2000-12-31) along with the number of times it is to be repeated (four times: R4). The above sample is the same as R4/1999-12-31/P1Y.
Time zones: Time zones may be specified after times by placing a time zone indicator after the time. A zone indicator of Z represents zero offset for UTC (also called "Zulu" time some places outside of ISO 8601). A notation of =hhmm (basic format, =hh:mm extended format), where "=" is a sign ("+" or "-") and hh mm an interval, provides the hours, and optional minutes, offset from UTC. See section 3.6.2, Time Zones for details on time zones.
Tip for times intended for use internally by software or in an international distribution by people. Rather than encode time zones into a time, simply convert the time to UTC and provide a zone name of Z. A zone of UTC may be used for documents read by people as the average person will not understand Z. Let the readers convert UTC to their local time. Astronomers and UNIX systems have been using UTC for years. For software developers the zoneinfo files provide a standard way of manipulating time zones. In international distribution time zone names can be near useless and numeric offsets more confusing than a simple UTC time. Note that this document uses such a revision time in its heading area.
ISO standard 9945-1 has established a series of standard names for time zones. While this is an ISO standard, it is not used by ISO 8601 in any way. The ISO 9945-1 names use longer words rather than three-character abbreviations, and would not be understood as zones by average readers. This standard seems to specify a standard way of specifying time locales to operating systems rather than time zones to people. The zoneinfo files appear to use them. Information on ISO 9945-1 time zone names may be found by visiting:
http://www.bsdi.com/date/Truncation and Reduction: ISO 8601 allows you to reduce the precision used to recorded dates and times. The general rule for ISO 8601 is to properly replace leading fields with hyphens if their values are not desired. While "truncation" must be strictly done in a left to right manner, ISO 8601 rules for these extra hyphens have a few quirks in them. See the following table.
Low order fields may simply be dropped from right to left (reduced) without using any special characters.
Examples of truncations and reductions follow. Rows in italic type note conditions of special interest. People in a hurry should read these even if they skip the others. Truncation requires mutual consent by all involved parties. A format that ensures that all truncated values can be uniquely recovered is essential. Where there is no risk of confusion users may also agree to omit unwanted leading hyphens (again, see the table for quirks). Truncation of century digits of years have been a fertile source of confusion. Caveat Truncator.
The T between the date and time may be omitted in most cases. If a T is present it must be followed by a time. If only a time is given, the T may precede it to better indicate it is a time. The T must be present in truncated dates with reduced times.
Date / Time Examples Truncated Reduction Extended Basic 1999-12-31 1999-12-31 19991231 99-12-31 991231 Century[1] --12-31 --1231 Full year n/a --12 Full year Day n/a ---31 Full year and month n/a 1999-12 Day[2] -99-12 -9912 Century[1] Day n/a -99 Century Month and day n/a 1999 Month and day n/a 19 All but century 1999-365 1999365 99-365 99365 Century[1] n/a -365 Century and year[3] 1999-W52-5 1999W525 99-W52 99W52 Century Day in week -W52-5 W525 Full year -W52 W52 Full year Day in week n/a W-5 All but day in week 23:59:00 23:59:00 235900 -59:00 -5900 Hour n/a --00 Hour and minute 23:59 2359 Seconds n/a -59 Hour Second n/a 23 Minutes and seconds 23:59:00,153 n/a --00,153[4] Hour and minute
- When dates and times are combined, only the date can be truncated and only the time can be reduced.
- n/a indicates ISO 8601 explicitly declares this use "not applicable". Usually to avoid confusion between two abbreviations of the same format but containing different fields.
- Section 4.6 of ISO 8601:2000 covers "truncation". Section 5.2.1.3 of ISO 8601:2000 expands on truncated representations. By agreement the leading hyphen may be omitted when truncating only the century providing the day number is not also being dropped by reduced precision. Once any other portion of the date is omitted by reduction, the leading hyphens to indicate omitted fields, especially omitted century digits, seem to be required.
The sections on truncation have wording that has generated considerable confusion and discussion. Archives of some discussions can be found at:
http://groups.yahoo.com/group/ISO8601/message/189
http://groups.yahoo.com/group/ISO8601/message/197Earlier versions of the standard had points covering truncation of century digits that this author found particularly confusing. Readers of earlier versions of this document based on the earlier ISO standard may observe major changes to century truncation rules.
When negative or expanded years are possible, this author will never want to truncate a year.
- When only the day is omitted, a separator must be placed between the year and month. This is the only place basic format uses a hyphen separator. because the six digits, "121212", are to be read as 12-12-12 (YYMMDD), not 1212-12 (YYYYMM).
- While --365 could be used (double hyphens), the first hyphen is redundant and therefore omitted.
- The comma or full stop (period) between the whole and fractional digits is not a separator character as hyphens and colons are. Rather the whole and fractional portion of the number make a single field.
In this sample the agreed precision has added 1/1000'th of a second to the time. Trailing zeros are required to keep the fraction the same number of digits in each recorded time.
Another date and time standard frequently used within the computing community, especially the Internet community, is included in RFC-822, which provides standards for date and time used on Internet type networks. RFC-822 dates are in the format "Tue, 16 Feb 99 17:56:23 EST".
RFC-822 is no longer used for new development as it has been replaced by RFC-2822. Though, when many people casually refer to "RFC-822" they are really refering to RFC-2822. This author believes some reasons RFC-822 fell out of favor include its inherent Year 2000 problems, "English Language" flavor, time zone problems, and the introduction of ISO 8601). A short summary follows. And if you find something called RFC-822 that doesn't look quite like this, check out RFC-2822 format.
[ Day, ] dd Mmm yy HH:MM[:SS] zone
These fields are:
- Day
- Optional day of week (e.g., Sun, Mon, Tue, Wed, Thu, Fri, Sat), followed by a comma (tip to computer programmers: consider the comma optional when reading dates, but always generate them if the day of week is present). Always in English.
- dd Mmm yyyy
- Date. E.g., 07 Nov 99.
This standard always uses a two-digit year. In practice this should be interpreted as the closest year to the current date. As RFC-822 is concerned with the transmission of information over networks there is no need to track periods over 99 years in length.
printf( "%2d %3s %02d", d.tm_mday, MonthName[d.tm_mon], d.tm_year%100 );- HH:MM:SS
- time stamp, in a 24-hour clock. Seconds is optional.
printf( "%02d:%02d:%02d", d.tm_hour, d.tm_min, d.tm_sec );
printf( "%02d:%02d", d.tm_hour, d.tm_min );- zone Time zone information.
- Provides offset from UTC to local time in the standard [+-]hhmm format or one of several standard names.
IMPORTANT NOTE: while RFC-822 defines one-letter time zone codes as described in section 3.6.2, the signs of the numeric offsets were reversed. Thus programs should avoid the one-letter codes with RFC-822 time zone offsets as the receiving program may process it exactly the opposite way you expect. Z (zero) is the only reliable code.
Note that years are always two-digits and must be century corrected when read.
RFC-2822 is a big improvement over RFC-822, but still not as good as ISO 8601.
[ day_of_week, ] Day Month Year HH:MM[:SS] Zone
These fields are:
- day_of_week
- Weekday name (Mon / Tue / Wed / Thu / Fri / Sat / Sun). If present, this name must be followed by a comma. Software developers should see the note in RFC-822 about this comma.
- Day
- One or two digit day.
- Month
- Month name (Jan / Feb / Mar / Apr / May / Jun / Jul / Aug / Sep / Oct / Nov / Dec).
- Year
- Year: four digit year.
- HH:MM:SS
- Time of day. Each field being two digits in length. The :SS field providing seconds is optional.
- Zone
- Time zone offset from UTC. In the form of a sign character (+/-) followed by a four digit time providing hours and minutes of the offset. A colon is not used in this field.
A typical RFC-2822 value follows:
Wed, 18 Jul 2001 11:54:46 -0400
NOTE: the timestamp placed on the initial "From " line of mail box files ritten by the sendmail program are in the format "Mon Mar 15 10:25:32 1999", which does not follow RFC-822 or RFC-2822. They are generated by calls to the asctime() function. As this date is not sent over the network it does not need to comply with RFC-[2]822.
While the field order is the same the following fields have different values:
- year
- Two digit value. Values of 00 through 49 represent 2000 through 2049 and values of 50 through 99 represent 1950 through 1999. Values of 100 and beyond represent year 2000 and beyond. Please note that this date window of 49/50 is different from the standard UNIX date window of 68/69.
- zone
- A value of GMT or UT for UTC, otherwise a series of values representing different time zones. EST / EDT / CST / CDT / MST / MTD / PST / PDT / Z
Like RFC-822, all single letter time zones, except Z, are untrustworthy.
Some E-mail messages may use other time zone formats.
This dating system is not to be confused with the "Ordinal Date" calendar, often, but incorrectly, also called the Julian Calendar. This calendar tracks years like the Gregorian calendar, but uses the day number within the year: day 1 to 365 (366 in leap years), for the day. There is no concept of months.Julian Day one was determined by combining three commonly used cycles of 28 (solar cycle), 19 (Golden Numbers) and 15 (indiction cycle) years to obtain a larger cycle of 7980 years, which is the least common multiple of the cycles. Traditionally credited to Justus Scaliger (1540-08-05, France) it was also discovered earlier by others. Running the Julian Calendar backwards from the current date to the start of the current "great cycle" avoided the need for negative numbers for years along with providing a uniform way of measuring dates and times during a period of accumulating calendar errors.
Please visit http://hermetic.magnet.ch/cal_stud/jdn.htm for more information about Julian Days.
Today Julian Days are used in various scientific or other extended calculations. As long as you are willing to ignore the 1582 (1752 in Britain and its colonies) calendar correction, staying within recent years, it is surprisingly easy to transform Julian days to "Gregorian" calendar dates.
Chronological Julian Days CJDs shift the start of a day backwards 12 hours to match our current concept for the start of each day and follow local savings time conventions. Thus the CJD day zero started at Julian 4713-January-01 00:00:00 BCE. When most people refer to "Julian Days" they are referring to the chronological kind. The more casual the reference the more likely it is the author did not even know of noon-to-noon days. Ignoring savings time and calendar corrections:
ChronologicalJulianDay = JulianDay + 0.5
JulianDay = ChronologicalJulianDay - 0.5
A Modified Julian Day shifts midnight like Chronological Julian Days do, but also adjusts day numbers to start at 1858-November-17 to obtain a date no more than five-digits in length. This is accomplished by subtracting 2,400,000.5 from the JD to produce MJD one (not zero). The resulting day numbers are more manageable to work with when using large numbers of dates. MJDs strictly follow UTC and are not subject to savings time or calendar correction events. MJDs are widely used in the scientific world for logging events.
IMPORTANT QUESTION, ALERT, and QUESTION
MJD values have been five digits in length since 1886-April-03
and a great many date MJD transmission standards
expect and require five digits of MJD.
Yet the authoritative definitions I have been able to
find all define MJD is JulianDay - 2,400,000.5 and not
( JulianDay - 0.5 ) modulo 100,000.
On Sunday 2131-August-31 the Julian Days will reach 2,500,000,
overflowing five digits.
This presents following questions:
|
This reminds me of C's struct tm tm_year field overflowing to 100 in year 2000.
Truncated Julian Days are also in use. This is the MJD truncated to four digits (remainder of MJD divided by 10,000) producing a more manageable four-digit date. The cycle returns to zero about every 27.4 years. The first TJD "day zero" was 1968-May-24 (a Friday). The second TJD cycle started on 1995-Oct-10. The third cycle will start on 2023-February-25. Computer programs using TJDs must take all due care to avoid problems when the cycle wraps. TJDs were created by NASA during the times of Apollo moon launches and have been picked up for use in other areas.
Centuries follow the same conventions millennia do. We need a "20" in our century digits before we can close out the 20th century.
If you are still not convinced, try to think in Roman numerals like the early calendar designers did. The first year was year I. Each series of numbers starts with a single I: I through V, VI through X, XI through D, DI through C, and so on. Therefore the last year of the first century was year C. In the "natural" order of Roman Numerals a single I is needed in the first year of a new century. Therefore year M ended the first millennium and MM ends the second millennium, with year MMI starting the third.The first year of the Christian Era was dated year I and was preceded by year I B.C.. While some calendar calculation formulas consider year "0" to be what is today commonly called "1 BCE", the official convention for publication is still "1 BCE". Remember, the Romans did not use place-holder mathematics like we do and therefore did not have a number for zero. Roman numerals were still being used in the medieval times our current dating system was invented in.
However, decades seem to start when the one's digit returns to zero.
While people still wring floods of "facts" out of numbers you won't read them here. However, a few fun tidbits follow.
The UK uses the D M Y order for writing dates.
Therefore Feb 20 was be digitally palindromic, 20/02/2002;
and, in the evening, the UK will have times of 20:11:02 .. 20:55:02 -
including 20/02/2002 20:02:20.02.
AUTHOR'S REQUEST: I would like to know of any official name for this type of date. The same for the following sequential numbers. ghealton@exit109.com
The first "Even Day" after the Y2K roll over was 2000-02-02, the first since 888-08-28 (sic.). The date of 01-01-01 was also numerically interesting.
- Caius Julius Caesar (a.k.a., Gaius) 0100BC/0044BC:
Pontifex; Emperor; Dictator; Invader; Commentator; Calendar Reformer; Assassinee.Date involvement: the Julian Calendar and the month July.
Calender of 365 days, with every four years being a leap year.
Also know from: the Shakespeare play.
- Julius Caesar Scaliger: 1484/1558
Father of Joseph Justus Scaliger (1540/1609) of France.Date involvement: The son JJS introduced the Julian Period.
Julian Period of (7980 years) and the Julian Day Number (day count from BC 4713-01-01 12:00 GMT = 0.0), from which MJD, CJD, TJD are derived.
It is said that these are named in honor of his father JCS; but others claim it was a reference is to the Julian Calendar. Perhaps both.
- Misinformed:
Julian Date is frequently, and improperly, used for ordinal date. Term is propular within the IBM mainframe community, but IBM may well have adopted the term from another source.A date using a year with an ordinal day number from 1 through 365, 366 on leap years, within the year.
The author wishes to thank Dr John Stockton and his contribution at http://www.merlyn.demon.co.uk/moredate.htm#Jul for this information.
All the assessment in the world can miss bugs like this, making it necessary to test critical paths of programs you inherit.
NOTE: the original UNIX definition for %y of date calls for year-1900 to be returned while the current POSIX standard calls for the last two-digits of the year to be returned. Thus date commands returning 100 for %y in the year 2000 are not Y2K compliant. Your tests should look for this problem value of 100 during year 2000 and values greater than 100 in following years.
Many of the "solutions" used by programmers to keep programs living in an after the year 2000 did not truly fix the problems. They only put the software on life support systems that only pushed the bug back a number of years. Companies would be well advised to determine if they have any of these time bombs lurking in their corporate code. Finding near term problems may be of critical interest. The sections on Y2K repairs should help developers spot such fixes and determine the life span of the "repair".
COBOL, RPG, and some other languages naturally allow programmers to explicitly declare variables are to be kept as two-digit values. These uses are very aggressive in keeping two-digit values as two-digits. Always and forever. Many other languages can do the same thing, though it may take more effort. Anything that uses "BCD" (Binary-Coded Decimal) to hold two-digit years must be considered guilty until proven innocent.
In these rules 99+1 yields not 100, but "00", the low-order two digits of the value. The carry of "1" that makes 100 is lost.
This wrap back to zero adversely impacts all date calculations and tests. There are many variations on the theme that depend on the programming language, operating system, and applications the program makes use of. Some sample problems include:
Sadly the scope of Y2K problems were not limited to two-digit years. Even modern programs in modern languages, such as C, perl, and Java, can have problems with year 2000. This author has personally seen bad code in new programs written as late as 1998, and will not be surprised if he finds some problems in 1999 code. Section 8, Bad Coding Techniques, goes into the technical details.
A well-known work around exists for operations where it is not vital for the computer to have the correct date. This is may work for industrial, and even many office, applications that are not networked or are sufficiently isolated from other major networks. If your operating system allows it (sorry Microsoft fans), set the date back 28 years. This returns to a previous point in the calendar cycle where the days of the weeks, leap year calculations, etc., is the same as the current year. The current 28-year cycle is valid for the years 1901 through 2099.
If you "setback" the dates in your database 28 years, and manually
subtract 28 years from all dates entered into your software, etc.,
you may be able to continue using old software with a
"cosmetic problem" of the wrong year being printed on reports.
This is actually being done in places until they properly fix their
problems.
(Do you really care if, say the power companies computers,
believe the year 2000 was 1972 as long as you got power in 2000?)
Note: some businesses may not be able to do this for legal reasons
if the reports are legal records, etc.
Any date setbacks should have been started months before the year 2000 to debug them before the panic of 2000.
Using date setbacks have their own risks. Most of the problems, and defenses, involved in (9) Testing Applications By Changing CPU Dates also apply to date setbacks. This includes, but is not limited to,
NOTE: the Network Time Protocol software generally ignores years transmitted in the type packets, assuming the CPU's local clock has been properly tracking the current year. Any times obtained from other systems with NTP may therefore preserve the setback, advancing to the next year as appropriate. Test your system for this if you rely on NTP.
At the dawn of age of business computers, computers simply took over the reading of Hollerith cards. To make switching to computers as easy as possible, most companies kept the same card format for the computes as they did with their EAM machines. Back then computer memory was very expensive, well exceeding $1 (U.S.) a byte. Add to this the huge amount of labor required for changing the existing programs using the files and retraining of personnel you get a huge amount of money. Spice this total with sheer corporate inertia and you get a recipe for sticking with two-digit years long after card systems vanished at a company. The designs of some languages, such as COBOL, made this very easy to do.
These early computers did not have any concept of time. At that time if a program needed to wait a specific amount of time, the programmer would send the computer into a short loop of instructions that did nothing but waste time. How long the computer stayed in the loop determined how long the wait was. Typically the computer could not do anything useful while in the time wasting loop. Moving the program to a faster computer could make the waits unacceptably shorter.
The next trick this author is aware of was adding "real time" timers to the computer to allow software to track how long various processes the computer was performing or watching took. The timers also allowed computers to track time of day and dates. As these early computers were slow, the timers tracking "wall clock" times were often driven by the frequency of the incoming line power. This made them independent of the inconsistent clock frequencies in the computer's hardware. Sixty-hertz became the standard in the United States. Fifty-hertz in much of Europe.
The next step was to add quartz timers to computers to split times into much finer fractions. Use of batteries allowed computers to keep time when powered off. (As the power companies spends millions of dollars to ensure the long term accuracy of line power is very good, even to this day, without special software adjustments, most modern quartz crystal clocks will drift from true time faster than the old-style line frequency timers.)
While people may look at 2038 and say, "that is 36 years away, why worry?", this is what people said in the early 1900s when setting up EAM machines to use two-digit years. Even if the machines and software do not survive, data formats have proven to have much longer life spans.
The time_t values are "binary" time values. As such they are "Year 2000 safe", at least until programmers start doing something dangerous with them, like dividing or taking remainders of divisions. Addition and subtraction for small values are generally safe.
#!/usr/bin/perl ### demonstration of UNIX "2038 Bug" $EndOfTime = 0x7FFFFFFF; #last value valid as +signed 32-bit $Format = '%04d-%02d-%02d %02d:%02d:%02dZ' . "\n"; @Gm = gmtime( $EndOfTime ); #break down last moment printf $Format, $Gm[5]+1900,$Gm[4]+1,$Gm[3],@Gm[2,1,0]; @Gm = gmtime( $EndOfTime + 1 ); #beyond last valid moment printf $Format, $Gm[5]+1900,$Gm[4]+1,$Gm[3],@Gm[2,1,0]; 2038-01-19 03:14:07Z 1901-12-13 20:45:52Z
Leap seconds (section 3.6.4) may make some small adjustment to the actual time the bug expresses itself.
Some programmers cast (i.e., copy) time_t values to "long" or other data types not properly compatible with time values. This is a cavalier assumption that can not only limit the portability of the program to different environments, it can also cause the code to mysteriously break with future compiler enhancements.
The remaining members of struct tm defined by the ISO/ANSI C standard follow. tm_hour, tm_min, and tm_sec store the time of day using a 24-hour clock. tm_wday provides the day of the week (Sunday=0). tm_yday provides the day of the year (0-364//365). tm_isdst provides a daylight saving time flag (positive if true, zero if standard time, negative if unknown/unsupported).
The actual order of fields within the structure is implementation dependent.
Other operating systems track time in other ways. Nothing is universal.
PC, and compatibles, TimeInterval Timers: as a granularity of a whole second is not sufficient for most operating systems the common practice is for an operating system (Windows, DOS, Linux, etc) to read the clock very carefully during boot. Before reading the RTC the OS will have previously started a higher resolution timer that can be used to track elapsed seconds. Such timers are often called "interval timers" and are used after the RTC is read to track the time of day with resolutions much higher than the RTC provides.
Different operating systems make different use of the RTC and interval timers. See your local operating system for details. Indeed, changing the time on some operating systems only updates the interval timer time and not the RTC. If the system keeps reverting to the old time on each boot this may be what is happening. Either find the command that sets the RTC or set the time from the BIOS on the next boot.
Epoch Year Microsoft Product Pivot Year Special Notes 0001 Microsoft .NET Framework Class Lib n/a 100nsec ticks since 0001-January-01 C.E. 1601 Microsoft NT/2000 (Win32) n/a 100nsec ticks since 1601-January-01 for a range of about 29,200 years 1899 Visual C++ DATE n/a 8-byte floating point value providing days since 1899-December-30 1900 Excel dates for Windows. 19/20 (cell entry)
DATE function n/aVT_DATE: days since 1900-January-01 (which has a value of 2... buggy programs accepting 1900-February-29 start at 1).
Q95948 Q2150941904 Excel dates for Macintosh. 19/20 (cell entry) Days since 1904-January-02 (value 1, see all notes for Windows Excel).
Switch between Mac. and Windows epochs by using Tools, Options, Calculation, and selecting or clearing the "1904 date system" checkbox.1980 MS-DOS{MarkR12b} FAT File Systems and DATE command. 00/99 1980 Windows 3.11 n/a
Other products may use different epochs. Please E-mail me epochs for any major Microsoft product not listed here.
While the time format ostensibly has a resolution of 100 ns, no Win32 platform actually keeps time at that resolution. Windows 2000's clock is only good to 1/64th of a second (15.625 ms), the length of a clock tick. Other Win32 platforms have clock ticks of different lengths, and some can even change the length of a tick on the fly (!).
The Win32 API provides two functions for retrieving the current time, GetSystemTime() and GetSystemTimeAsFileTime(). The former retrieves the current time broken down into a SYSTEMTIME structure (analogous to struct tm), and the latter retrieves it as a 64-bit integer stuffed into two DWORDs in a FILETIME struct. (With the latter function, you can pass it an __int64 variable, with a typecast.)
However, when operating on a 64-bit timestamp, careless mixing of 32- and 64-bit quantities in a single expression in C/C++ can lead to the truncation of the 64-bit timestamp to 32 bits. There are a few easy things you can do to avoid the truncation, however:
While this may smack of a "belt-and-suspenders" approach to programming, this causes endless problems to people who are not careful.
If your code needs to be acceptable to more compilers than just Microsoft Visual C++, the following preprocessor incantations will probably be useful:
#if defined(WIN32)
#define _64(x) x ## i64
typedef __int64 int64;
typedef unsigned __int64 uint64;
#elif defined(__GNUC__)
#define _64(x) x ## LL
typedef long long int int64;
typedef unsigned long long int uint64;
#else
#error woops, need to fix _64() for this compiler!
#endif
The kicker is that the TOD is incremented at some decimal increment, such as every millisecond, rather than a true binary fraction. The result is a "long second" where the second is incremented once every 1.048576 seconds.
Individual programs and languages that run on IBM mainframes have large libraries of time and date options. See specific programs and languages for individual details. The IBM publication The Year 2000 and Two-Digit Dates - A Guide to Planning and Implementation GC28-1251-05, may help mainframe users get started on time and date related issues. An unofficial copy was available at http://ano2000.kpnqwest.pt/ibm/best_ibm.pdf in PDF format.
Leap seconds (section 3.6.4) may make some small adjustment to the actual time the time overflows.
TimeMacintosh systems can be set to use the ISO 8601 date and time format. Please visit http://karchive.info.apple.com/article.html?orig=til&artnum=60753 for details.
Leap seconds (section 3.6.4) may make some small adjustment to the actual time the epoch overflows.
int TheTime = time( (time_t *)NULL ); /* not portable! */
This works under most current UNIX systems where int and long are the same. But if the program is "fixed" by moving it to a 64-bit system, it will still fail in 2038 if int remains 31-bits while time_t (and long) grows to 63-bits.
Programs using "int" for time will immediately fail when migrated to compilers defining int's as 16 bits.
Using ints for variables that contain times makes it much more difficult to track down all statements impacted by date calculations during repairs or enhancements to their logic.
Not as many immediate portability problems as int, but this is still pasting a "kick me" sign on your back. Especially now that ANSI/ISO C 99 (C99) supports long long data types for 64-bits, leaving int and long for 32 bits. If time_t internally becomes long long programs assuming it is just long will be in trouble.
When printing time_t values on printf() type statements (or other variable argument list statements), the value should be explicitly cast to some well-known data type if a time_t variable is not expected.
printf( "time_t TheTime=%llu\n", (unsigned long long)TheTime );
The only way, in a portable manner, to obtain the interval, in seconds, between two times in the C language is to use the difftime() function.
Unknown = Time1 - Time2;
Seconds = difftime( Time1, Time2 );
For other languages study the definition of the time functions very carefully. If needed, find the corresponding function in that language.
While starting at 1970-January-01 is popular for UNIX, other operating systems are free to choose different base times. (And they do!)
Calculating struct tm years by using modulo 100 rather than subtracting 1900.
x.tm_year = Year4 % 100; /* popular, but sad, method */
Time = time( (time_t *)NULL );
AboutSixMonthsAgo = Time - ( 6 * 30 * 24 * 60 * 60 );
AboutSixDaysAgo = Time - ( 6 * 24 * 60 * 60 );
/* above may be safe for crude approximations */
Years = ( Time2 - Time1 ) / ( 365 * 24 * 60 * 60 );
/* very likely a problem, especially if you need to
catch differences in years. does not allow for
time zones (OK in UTC time), and does not allow for
leap years, nor leap seconds. */
{ /* one accurate way to calculate year offsets follows */
struct tm StructTm1, StructTm2;
StructTm1 = *localtime( &Time1 );
StructTm2 = *localtime( &Time2 );
Years = StructTm2.tm_year - StructTm1.tm_year;
}
"Pivot Years" allow two-digit years to be converted to four-digit years. The standard pivot year for UNIX is 68 (e.g., 68/69). 69-99 are assumed to be 1969 through 1999 while 00-68 are assumed to be 2000 through 2068.
This author prefers to provide two values for pivot years (68/69) rather than just a single number (68) to avoid confusion on exactly where the boundary is.
Mistake:
Different pivot years in different programs.
Repair:
The same pivot year should be used in all programs.
Mistake:
Pivot years of 69/70 must not be used in most UNIX or C environments.
Due to time-zone differences, the Americas, and other areas,
actually see years of 69 for small
values of time_t on 1970-January-01 where the time_t value is less than
the offset from UTC time (e.g., before 5AM on EST time).
Since these areas have a negative offset from UTC,
their early values are the day before UTC time: 1969-December-31.
Programs using 69/70 for pivot years incorrectly translate 1969 into
2069 for these early times.
Repair:
Use pivot years of 68/69.
The standard C method for tracking year values is the tm_year member of struct tm. The value of tm_year is kept in "Year-1900". Many people assume these are two-digit values that will become zero in the year 2000, but this is not true. Starting in the year 2000 the value will use the three digit value 100, year 2001 will use 101, etc.
The following is a popular perl bug. Creative programmers in other languages have migrated this bug to languages where it is difficult to express it.
@LocalTime = localtime time; #obtain local time $Year = "19" . $LocalTime[5] if $LocalTime[5] >= 70; $Year = "20" . $LocalTime[5] if $LocalTime[5] < 70;
This not only has the pivot year bug previously described (69/70), it will also yield the five-digit year "19100" for the year 2000. Even if it did work, you would get 200 through 209 for the years 2000 through 2009. The correct fix is to use:
$Year = $LocalTime[5] + 1900;
Perl is such that you can use the numerically calculated value anyplace a character string is needed.
Also see 8.2.4, Errors In Printing Years for common problems relating to printing tm_year values.