Is that the (daylight saving) time?

In my previous column on this topic (see Outfoxed by Daylight Saving Time), I mentioned that I'd completely forgotten to account for Daylight Saving Time (DST) when capturing the code for the Cunning Chronograph.

Community member Realjjj commented: "But tomorrow you'll be bothered by the RTC's lack of accuracy; might as well go with WWVB -- more retro than other solutions." So I had a root around and discovered that WWVB offers as a great a Heath Robinson / Rube Goldberg combination of "modern" and "retro" as anyone could wish for. On the one hand, the signal is derived from a set of atomic clocks that yield a frequency uncertainty of less than 1 part in 10^12. On the other hand, this information is then modulated onto a 60kHz carrier signal and transmitted at one bit per second, resulting in each frame of time code beginning at the start of each minute and lasting the entire minute.

Well, this set me off on a tangent, resulting in my ordering a High Sensitivity WWVB Time Receiver Module with Antenna from my chum Pete Virica who owns PV Electronics in the UK (Pete also stocks modules for use in the UK and Europe). I will be playing with this as soon as is arrives. You have to admit that there's a certain cachet and je ne sais quoi attached to being able to say that the accuracy of one's Cunning Chronograph is regulated by atomic clocks, but all of this is for the future...

Another community member, Matt Weber, asked how long I intended my Cunning Chronograph to run, and noted that if I use only a 16-bit unsigned integer to represent the year, then my descendants are doomed to experience a Y64K bug in the year 65,535. Matt also noted that by that time, we (i.e., humans) might be living on Kepler-186f (the first Earth-sized planet we've discovered in the habitable zone), in which case we'll need to adjust the Cunning Chronograph to deal with years containing ~130 days.

Well, I'm ever the optimist, and there's always an outside chance we will discover faster-than-light travel while I still maintain a corporeal presence on this plane of existence, so I feel it behooves me to modify my Cunning Chronograph to allow its owner to specify the number of hours in a day, the number of days in a year, and so on and so forth. Once again, however, this is something to mull over in the future...

Returning to the problem at hand, my Cunning Chronograph is currently displaying standard time and running an hour behind. I obviously want it to reflect DST. In particular, I want it to reflect DST in Huntsville, Alabama, which is where I currently hang my hat.

The simplest solution is for me to simply reset the time by hand at the start and end of DST season, but I'm not that sort of man. The next simplest solution would be to have a switch on the back of the clock and/or an option on my Bluetooth control system (Off = standard time; On = DST).

Of course, we can keep on adding to the complexity. Do I want to add the ability to specify Pacific, Mountain, Central, and Eastern USA time? What about the fact that some states like Arizona don’t observe DST (although, confusingly, Phoenix -- the capital of Arizona -- does)? Similarly, if I one day wish to transport my Cunning Chronograph on a trek around the world, I'll have to contend with DST in Northern hemisphere summers, DST in Southern hemisphere summers, the fact that different countries move into and out of DST on different days, and the fact that some countries don’t support DST at all (see also DST by Country) .

Sometimes I have to rein myself in. Let's return to the problem at hand. My Cunning Chronograph currently resides with me in Huntsville, Alabama, and that's where we both plan to be for the foreseeable future, so the first step is to come up with an algorithm that will allow the Chronograph to automatically correct for DST here on my own turf.

In the case of DST in America, the time advances by one hour at 2:00 a.m. on the second Sunday in March, and it is set back by one hour at 2:00 a.m. on the first Sunday in November. Using the RTC (real time clock) in my Cunning Chronograph, I can easily access the following values:

year (2016, for example)
month (1 to 12)
day (1 to 31)
hour (0 to 23)
minute (0 to 59)
second (0 to 59)

From my previous column, we know that we can create a dayOfWeek() function that will accept year, month, and day arguments and return an integer value of 0 = Sunday, 1 = Monday, 2 = Tuesday, etc.; for example:

How we actually use this function depends on the inner machinations of the Cunning Chronograph's implementation. In the case of my chum Steve Manley's Cunning Chronograph in the UK, for example, he only uses his RTC to determine the current year, month, day, hour, minute, and second values on power-up. Thereafter, he employs a 1Hz signal from his RTC to generate an interrupt, which he then uses to modify these values as required.

This means that, if we were to assume Steve's clock to be located here in Alabama (remembering that DST may start and end on different days in the UK), at exactly 2:00 a.m. on the second Sunday in March, he would use something like hour += 1 to advance the time by one hour to 3:00 a.m. Similarly, at exactly 2:00 a.m. on the first Sunday in November, he would use something like hour -= 1 to regress the time by one hour to 1:00 a.m. (the reason I say "something like" in this latter case is that, if we actually used hour -= 1, we'd spend the rest of our lives locked in a 1:00 a.m. to 2:00 a.m. time loop).

In my case, however, I don’t have access to a 1Hz signal from my RTC. Thus, having displayed the current hour, minute, and second values on the face of my Cunning Chronograph, I simply sit around polling the RTC until we transition into the next second, and then I regenerate everything from scratch. This means that, once every second, my code needs to determine if we are currently between the start and end of DST season and -- if we are -- it needs to increment the hour value before displaying it.

Bearing all this in mind, let me walk you through the way in which I arrived at the algorithm I intend to implement this coming weekend. (I could jump straight into the solution, but I think some folks may find it useful to see the way in which one might set about solving problems of this ilk.)

Now, I can’t talk as to the way in which other people would tackle this conundrum. All I can say is that I'm a visual person, so I often begin by sketching things out on a piece of paper. I started with the fact that I need to know the number of the day the second Sunday occurs in March. Obviously, this will be determined by which day falls on March 1. After a bit of messing around, I came up with the following diagram:

(Source: Max Maxfield / Embedded.com)

You will recall that our original dayOfWeek() function returns 0 = Sunday, 1 = Monday, 2 = Tuesday... ending with 6 = Saturday. Sad to relate, this gives us a discontinuity when we come to Sunday being the first day of the month.

We could work around this by adding a test to see if the returned value was 0 (Sunday), in which case we could change this to 7, resulting in 1 = Monday, 2 = Tuesday, 3 = Wednesday... ending with 7 = Sunday. This solves the discontinuity problem, but it still leaves us having to perform some algorithmic gymnastics to generate the results we desire.

Since we know that we're going to "munge" the output from the function anyway, let's come at things from a different angle. It doesn’t take long to realize that we can make our lives a whole lot easier if we swap things around a bit and modify the dayOfWeek() function to return 0 = Sunday, 1 = Saturday, 2 = Friday... ending with 6 = Monday as illustrated below:

(Source: Max Maxfield / Embedded.com)

All of this is easily achieved my means of a cross-reference array, which means that -- assuming we've defined NUM_DAYS_IN_WEEK to be 7 -- our new dayOfWeek() function will look like the following: