In my essay "Use the 24-hour clock", I claim that trying to represent the 12-hour clock directly in data is a terrible exercise in patchy, inelegant programming:

"No problem, we'll just use computers to do these calculations for us." Yes, but computers need to be programmed. And trying to account for AM and PM directly in a computer program, especially the extremely tricky way we've encoded it, with 12 representing 0, is prone to bugs and programming mistakes, which can cost millions at the airport in scheduling mishaps. As it is, it's much easier for computers to work in 24-hour time in internal calculations, and then convert the times to 12-hour time for easy human reading, instead of having to deal with dozens of notational issues as would be the case when using 12-hour time directly. In which case, why not just get rid of the whole 12-hour conversion and work with 24-hour time in the first place?

Here's your chance to prove me wrong. Your task is to build a Clock class that supports the following functions:

  • addHours(x), that advances the clock by x hours (or moves back |x| hours if x is negative)
  • addMinutes(x), that advances the clock by x minutes.
  • diffMinutes(c1, c2) that gives the time difference from clock c1 to clock c2 in minutes (which always assumes that c1 and c2 are representing times in the same day). If c2 is earlier than c1, the time should be negative.

and has the following publicly accessible variables:

  • hours, which represents the hour digit of the clock, from 1 to 12.
  • minutes, which represents the minute digit of the clock, from 0 to 59.
  • ampm, which is true if the clock is AM and false if the clock is PM.

as well as a setter and getter method (e.g. setHours(hours) and getHours()) for each. (You may assume that the setters and getters will always be passed valid values.) The reason the variables must be publicly accessible is to ensure that the internal data representation of the clock is also in a 12-hour format, to fit the data representation of the clock described in the essay.

Your code must pass all the unit tests contained in this file (translated to the programming language of your choice) except for test 0.2, which should be removed for this problem. (If the descriptions of the corner cases and their resultant times start to make your head spin, that's good. It means that my point about the strangeness of the notation is verified. It certainly made my head spin trying to make sure I had all the corner cases covered.)

Your score is calculated based on the number of operators and function calls in your class code, rather than the number of characters (so don't golf your code, make it readable but still short). Lowest score wins, of course.

Note: This problem has a part 2, namely, to create a 12-hour clock that uses 24-hour time in its internal representation. If my hypothesis is true, the winner of that problem will have a much lower score than the winner of this problem.

  • 2
    \$\begingroup\$ file= dead link! \$\endgroup\$ – sergiol Jan 9 '17 at 3:34
  • \$\begingroup\$ does it really need to be a class? What if the language I use is not "classy" by nature? \$\endgroup\$ – sergiol Jan 9 '17 at 3:36

Python (38)

Full code with tests here. A ton of the tests were wrong, so I modified them. Most of the changes are marked with the string "patch" in a comment, but I'm sure I forgot to mark some.

It was completely unclear if diffMinutes(a, b) was abs(a-b), a-b or b-a, so I went with b-a because I had to change less tests that way.

Also, ampm is a terrible variable name. isAM would be a far more readable name, and isPM would be preferable, as true and false are often associated with 1 and 0, and PM is a higher/later value.

The interesting part (getters and setters in the link above):

def getMinutesFromMidnight(clock):
    return clock.hours * 60 % 720 + 720 * (not clock.ampm) + clock.minutes

def diffMinutes(a,b):
    return getMinutesFromMidnight(b) - getMinutesFromMidnight(a)

class Clock(object):
    def __init__(self):
        self.hours = 12
        self.minutes = 0
        self.ampm = True

    def addHours(self, hours):
        self.addMinutes(hours * 60)

    def addMinutes(self, minutes):
        minutes = getMinutesFromMidnight(self) + minutes
        self.hours = minutes / 60 % 12 or 12
        self.minutes = minutes % 60
        self.ampm = minutes % 1440 < 720
  • \$\begingroup\$ Yeah, ampm is a pretty bad variable name. It's a carry-over from ampm being "am" and "pm" text variables instead, but I just didn't change it when I decided to use a boolean variable instead. \$\endgroup\$ – Joe Z. Feb 24 '13 at 3:07
  • \$\begingroup\$ I've repatched the unit tests according to your patches. Could you verify that they're correct? \$\endgroup\$ – Joe Z. Feb 24 '13 at 3:18
  • \$\begingroup\$ I've counted the number of operators and function calls and your score turns out to be 38. I counted the "." for accessing a class name (except when it involved a "self" variable) as an operator. \$\endgroup\$ – Joe Z. Feb 24 '13 at 3:29
  • 1
    \$\begingroup\$ Sounds good, thanks for scoring it. Remaining problems in the tests: s/setampm/setAMPM/g, s/diffHours/diffMinutes/g, in 2.5.2 s/-1/1/, in 3.2.4 s/true/false, in 3.2.7 s/719/-719/ \$\endgroup\$ – Dougall Feb 24 '13 at 6:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.