diff --git a/blog/templeos-time-2019-06-21.markdown b/blog/templeos-time-2019-06-21.markdown new file mode 100644 index 0000000..8d6b6b6 --- /dev/null +++ b/blog/templeos-time-2019-06-21.markdown @@ -0,0 +1,146 @@ +--- +title: "TempleOS: Date/Time Code" +date: 2019-06-22 +--- + +# TempleOS: Date/Time Code + +## Introduction + +In the [last post](https://christine.website/blog/templeos-2-god-the-rng-2019-05-30) +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](https://christine.website/blog/sorting-time-2018-08-26), +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](https://www.scienceabc.com/eyeopeners/why-do-we-have-a-leap-day-leap-year-after-every-4-years.html). +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](/static/img/analog_clock.jpg) + +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](https://en.wikipedia.org/wiki/Year_2000_problem). Thankfully this problem was averted. + +## How Linux handles time + +Linux handles time by keeping track of [the number of seconds since January 1, 1970](https://en.wikipedia.org/wiki/Unix_time). +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](https://lore.kernel.org/patchwork/patch/628142/). +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](https://github.com/Xe/TempleOS/blob/master/Kernel/KernelA.HH#L193-L198) +and [CDate](https://github.com/Xe/TempleOS/blob/master/Kernel/KernelA.HH#L186-L190). +Let's look at each of these in more detail: + +```c++ +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: + +```zig +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](https://templeos.holyc.xyz/Wb/Doc/TimeDate.html) +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](https://templeos.holyc.xyz/Wb/Doc/Date.html) +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) + diff --git a/static/img/analog_clock.jpg b/static/img/analog_clock.jpg new file mode 100644 index 0000000..3bf2b74 Binary files /dev/null and b/static/img/analog_clock.jpg differ