xesite/blog/templeos-time-2019-06-21.ma...

5.1 KiB

title date
TempleOS: Date/Time Code 2019-06-22

TempleOS: Date/Time Code

Introduction

In the last post we discussed god, the random number generator of TempleOS. This post is going to cover the time handling subsystem of the TempleOS kernel. As mentioned before, time is an unfortunately complicated thing, and legacy systems stapled onto legacy systems complicate this a lot. It also doesn't help that we consider one day 24 hours, even though it's more accurately slightly less than that. Most people consider a year to be 365 days, but the actual movement of the ball Earth around the Sun is closer to 365 days and about six hours. To compensate for this, every 4 years we add a day to the calendar called a Leap Day. This complicates time calculations. And this isn't even going to cover time zones because I want you readers to have some shred of sanity left.

Problem space description

Time is an unfortunately complicated thing to handle. The goal of this part of the TempleOS kernel is to allow users to programmatically get the current "real time", or the time of the day. This is sometimes called "wall clock time", referring to the offices where Unix was developed having literal clocks on the wall to tell you the time. When you read a clock off the wall, you get the current time in hours, minutes and sometimes seconds. See this example below:

an analog clock

This clock either says it is 2:51:59 or 14:51:59, as clocks only show a 12 hour view of 24 hour days for historical reasons.

How x86 hardware handles time

The x86 real-time clock keeps track of time with a similar kind of API. The OS can query the real-time clock and get the following fields individually:

  • Seconds
  • Minutes
  • Hours
  • Weekday
  • Day of month
  • Month
  • Last two digits of the year
  • Sometimes the current century (19 or 20)

Note the last two digits of the year. This is returned because computers historically did not keep track of the current century in order to save memory. This famously caused the Y2K bug that almost caused chaos globally. Thankfully this problem was averted.

How Linux handles time

Linux handles time by keeping track of the number of seconds since January 1, 1970. Traditionally programs use a signed 32 bit integer value for this. You might notice that this is a drastically different time format than what the real-time clock provides. When Linux reads from the real time clock, it does some math to convert these real time values to a unix timestamp.

The Rockchip calendar hack

Of course, this assumes that the hardware is behaving correctly. There have been cases in the past where buggy hardware required patches. If the hardware calendar and the software understanding of that calendar get out of sync, things get really confused.

How TempleOS handles time

TempleOS has two main time types, CDateStruct and CDate. Let's look at each of these in more detail:

public class CDateStruct
{
  U8	sec10000,sec100,sec,min,hour,
	day_of_week,day_of_mon,mon;
  I32	year;
};

public I64 class CDate
{
  U32	time;
  I32	date;
};

The I64 class CDate part of the definition makes the HolyC compiler align instances of it across the size of a int64 value, or 8 bytes. This also makes the compiler treat instances of it like an integer value.

Here are approximate Zig equivalents:

pub const CDateStruct = packed struct {
  sec10000:    u8,
  sec100:      u8,
  sec:         u8,
  min:         u8,
  hour:        u8,
  day_of_week: u8,
  day_of_mon:  u8,
  mon:         u8,
  year:        i32,
};

pub const CDate = packed struct {
  time: u32,
  date: i32,
}

The TempleOS documentation describes CDate like this:

TempleOS uses a 64-bit value, CDate, for date/time.  The upper 32-bits are the 
days since Christ.  The lower 32-bits store time of day divided by 4 billion 
which works out to 49710ths of a second.  You can subtract two CDate's to get a 
time span.

Use CDATE_FREQ to convert.

And it describes the date field of CDate like this:

Dates are 32-bit signed ints representing the number of days since the birth of 
Christ.  Negative values represent B.C.E. dates.

B.C.E. usually means "Before Common Era", which is a way to say "the time before Jesus Christ was born". Christianity ended up being such a core part of global culture that the calendar was reset because of it.

  • CMOS real time clock API
    • NowDateTimeStruct();
      • How to read from the CMOS clock
      • The bug in the time code
  • Live Demo (Zig/wasm+JS)