Time And Date

From OSDev.wiki
Revision as of 03:10, 7 March 2007 by osdev>Jhawthorn
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Template:Convert

 ToDo: This is a first draft and should probably be checked. It might be a good idea to move all of the RTC details into a seperate "RTC Hardware" page and add more info  ... -- Brendan
  There is also the [CMOS] page - maybe details about accessing it should be moved there? It's a bit lacking, too (the CMOS page, I mean). You just raised some interesting issues, like the danger of reading CMOS during updates.. --ZomgTest

!!! Time And Date

Most OS keep track of the current time and date, and allow for work to be started at a certain time or date or at regular intervals (e.g. daily or weekly). To do this the OS needs to obtain the current time during boot and maintain this time.

!! Obtaining The Current Time And Date

For 80x86 PCs, there's a special "Real Time Clock" (or RTC). This chip contains its own memory ([CMOS]) and has its own battery so that it keeps running when the computer is turned off and the contents of its memory aren't lost ([CMOS] is also used to store BIOS settings).

The RTC is capable of many things - periodic interrupts from 2 Hz to 8192 Hz, alarm interrupts (which occur at a pre-set time of day) and update interrupts (interrupt when a new second begins). The RTC also has support for daylight savings changes that only works if you're in the northern hemisphere and change your clocks at 2:00 AM on the last Sunday of April and October (useless for a lot of people), and can keep track of the day of the week (Monday, Tuesday, etc), but these things aren't normally used on PCs. The RTC can keep track of time in 12 hour format or 24 hour format, and can store values in BCD or binary (PCs normally use BCD format).

The RTC reads values and flags from [CMOS] and updates it. Therefore, everything that can be done with the RTC can be done by reading and writing to [CMOS]. This is done using two I/O ports - an index port (I/O port 0x70) and a data port (I/O port 0x71).

Before reading the time and/or date from the RTC, the code should make sure that the RTC isn't in the middle of updating the time to avoid incorrect readings.

Simple code (in NASM) to read the current time and date would go like this:

<verbatim> %define RTCaddress 0x70 %define RTCdata 0x71

Get time and date from RTC

.l1: mov al,10 ;Get RTC register A out RTCaddress,al in al,RTCdata test al,0x80 ;Is update in progress? jne .l1 ; yes, wait

mov al,0 ;Get seconds (00 to 59) out RTCaddress,al in al,RTCdata mov [RTCtimeSecond],al

mov al,0x02 ;Get minutes (00 to 59) out RTCaddress,al in al,RTCdata mov [RTCtimeMinute],al

mov al,0x04 ;Get hours (see notes) out RTCaddress,al in al,RTCdata mov [RTCtimeHour],al

mov al,0x07 ;Get day of month (01 to 31) out RTCaddress,al in al,RTCdata mov [RTCtimeDay],al

mov al,0x08 ;Get month (01 to 12) out RTCaddress,al in al,RTCdata mov [RTCtimeMonth],al

mov al,0x09 ;Get year (00 to 99) out RTCaddress,al in al,RTCdata mov [RTCtimeYear],al

ret </verbatim>

Notes: The code above doesn't check if the RTC is using BCD mode or binary mode (for e.g. ten would be 0x10 in BCD mode or 0x0A for binary mode). For the hours, it will return a value between 00 and 23 if the RTC is using 24 hour mode, or a value between 01 and 12 with the highest bit used to indicate if it's AM or PM (bit 7 set for PM) for 12 hour mode. For the year value, the RTC doesn't include a "standard" century value, however some RTC chips do have a century value in the RTC's memory somewhere. ACPI is the only method I know of for determining if a century value is present and where it is. For most OS's is easier to assume that the year is between 2000 and 2099.

!! Maintaining The Time

Some OSs always read the current time and date from the RTC and don't keep track of it internally, however this has a few disadvantages - this method is only accurate to 1 second (the RTC can't be used to read fractions of a second), the RTC is slow to read especially if you try to read at the start of an update (and it can be needed often for file systems) and the format it uses often isn't what the OS wants (more on this later).

Instead of repeatedly reading the time and date from the RTC, most OSs use their own internal time keeping code, which relies on a timer - the [PIT] (IRQ 0), or the RTC periodic or update interrupt (IRQ8). Choosing a good format to use for keeping track of time internally, and writing the code to support this format can be more complex than it seems at first.


!! Internal Time Formats

It is possible to keep track of time using several seperate variables (second, minute, hour, day of month, etc), however this can be messy. Often it's better to store time as a counter that is regularly incrememented (for example, "seconds since the year 1234"). Because the file system can be the code that needs the time and date the most often, some OSs keep track of the time and date using the same format that it's file system/s need to avoid conversions. An example of this would be a *nix system that keeps track of seconds since the start of year 1970.

Unfortunately, keeping track of seconds only is often inadequate for modern file systems and can cause "less than perfect" results for utilities like "make", and if an OS supports different file systems (e.g. ext2 and FAT) then converting the system time can't be avoided in all cases. In addition, an OS usually uses some form of time measurement to keep track of how much time each task has used or for small delays where seconds isn't suitable (milli-seconds or micro-seconds would be more useful).

For these reasons it can make more sense for the OS to maintain a single time variable with higher accuracy. As an example, I use a signed 64 bit value to keep track of milli-seconds since the beginning of the year 2000. This is sufficiently large for almost 300 million years before and after the year 2000, and is also accurate enough for the scheduler's use.

Be warned, however, that Quantum Mechanics predicts that time intervals less than 5.391 x 10-44 seconds, known as [Planck time|http://en.wikipedia.org/wiki/Planck_time], are unmeasurable. So no matter how fast computers become, accuracy beyond that will be unused.

As another example, Windows uses a 64-bit unsigned value of the number of 100-nanosecond (100 x 10-9 second) intervals since January 1, 1601. Why 1601? It is the start of a 400-year cycle of leap years, and thus makes conversion into a more usable format simpler. If your OS does not need to handle years before 2001, you could use January 1, 2001 as a base year.

!! Which Time?

Once you've determined what format to use for keeping track of time, it's important to decide which time you'll keep track of. In general there's three different times - the user's "wall clock" time, local standard time and UTC (or "Universal Co-ordinated Time").

At any instance, UTC is the same everywhere around the world. Local standard time depends on which time zone you're in (for example, my local standard time is always UTC + 9.5 hours). "Wall clock time" is the same as local standard time unless daylight savings is in effect (for example, my wall clock time is UTC + 9.5 hours except during summer where it becomes UTC + 10.5 hours).

Some OSs use "wall clock time" while better OSs use UTC. The reason for this is that UTC is the same everywhere. Imagine you've got a multi-user server, with one user in America, one in Australia and another in Africa and you'll see why UTC makes more sense. Even if your OS isn't going to be multi-user, consider time stamps for an FTP server or file system that's shared on a network.

This can cause problems with the RTC on dual boot computers, because the "better" OSs want to set the RTC to UTC while other OSs want the RTC to be set to "wall clock time". It can even cause problems when the computer has 2 OSs that both expect the RTC to be set to wall clock time because both OSs will adjust it for daylight savings time (so that it's accidentally changed by 2 hours instead of one). See http://www.cl.cam.ac.uk/~mgk25/mswish/ut-rtc.html for a detailed discussion of this problem.

!! Complexities

Regardless of what you do you will eventually need to convert the time format that your OS uses into other time formats. Unfortunately time itself is not a simple thing, and conversion between time formats can be quite complex (especially if done accurately). Also there are some problems maintaining the OSs time that don't involve conversions. The things you may need to watch out for include:

__Time Zones__
This is mostly for converting between local standard time and UTC. Most OSs have a database so that each time zone can be given a name or location (for example, "Adelaide, South Australia" rather than "UTC +9.5 hours").
__Daylight Savings__
This is a nightmare. Some countries have different time zone rules for each state, some countries have different time zone rules for each local area within a state (the USA is particularly messed up). Worse still is that some areas decide what they are going to do each year so that it's impossible to work it out in advance, and for most areas the daylight savings rules are subject to the whims of politicians. For some OSs daylight savings information is also kept within the same database as time zone information, so that a user can tell the OS where they are and the OS can figure out the appropriate time zone and daylight savings rules from this. Daylight savings can be especially problematic for dates in the past.
__Leap Years__
As you all know, a year isn't exactly 365 days. The official leap year rules are that if a year is a multiple of 4 then it's a leap year, unless it happens to be a new century and it can't be divided by 400. For example, the years 2004, 1996 and 1968 are leap years, the years 1700, 1800, and 1900 are not leap years, but years 2000, 1600 and 2400 are. This keeps the date in synchronization with the seasons (but despite this it's still out by one day every 5025 years).
__Leap Seconds__
Unfortunately, due to standards bodies, atomic clocks and solar influences, a day is not exactly 86400 seconds long (and on average each day is slightly longer than the last). To account for this an extra leap second is added (roughly one second each 5 years). A list of when leap seconds have been added can be found at http://tf.nist.gov/pubs/bulletin/leapsecond.htm. The next leap second will occur on the 31st of Decemeber, 2005 where (just before midnight) clocks will go from 23:59:59 to 23:59:60 to 00:00:00 instead of from 23:59:59 to 00:00:00 - the last minute of the year will be 61 seconds. Some OSs account for leap seconds, some don't (it's usually only important for accurate scientific calculations).
__Calendars__
Most of the world uses the Gregorian calendar, but some people don't and some use other calendars in conjunction with the Gregorian calendar. If you intend to make your OS international, or if you convert your time format into Gregorian dates before 1920 then you'll need to research other calendars and (for past dates) the history of calendars. An excellent starting point for this can be found at http://www.tondering.dk/claus/calendar.html.
__Drift__
If your OS does keep track of the time internally (rather than repeatedly reading the RTC) then inaccuracies in your code and in the timer hardware can cause your OS's time and the RTC to "drift" apart. Some OSs use special code or utilities to prevent this from happening. If your OS uses the RTC's periodic (or update) interrupt and IRQ 8 then your OS's time and the RTC will stay the same. If you use the [PIT] chip and IRQ 0, then this can be a problem, partly because it's difficult to divide "1.19318166666666666 Mhz" by any value and get an integer result, and partly because of differences in hardware accuracy between the [PIT] and RTC.
__Accuracy__
Unfortunately the electronics in PCs isn't as accurate as it could be, and over time (regardless of everything else) the computer's time will become inaccurate. Some OSs ignore this problem and allow the user to change or adjust the time whenever they like. This causes problems with some utilities (if you've ever got a "modification time in the future" error message from 'make' you'll know why). For other OSs (often the OSs that are designed for servers that are never turned off) there's a way of adjusting the time in a more subtle way, with many tiny changes rather than a larger sudden change. An example of this is the 'adjtimex' utility on *nix systems. A better method of handling this problem is with a networking protocol called "ntpd" (Network Time Protocol), which allows the OS to be automatically sychronized with an accurate public time server on a regular basis.

--- !!! Links

  • thread: [Time: How do you store time in your OS?|Forum:9241]

Categories: [HowTo]