Zune death

6

Not sure how many people have seen this story but the Microsoft Zune had a widespread problem where it died if powered up on Dec. 31st and refused to start. Apparently it was a leap year problem in calculating the length of the leap year. Even better, here’s the code in question (starting line 259):

while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}

Looks like that days > 366 should be days = 366. Hmmm…maybe a good candidate for a unit test, you think?

Comments

6 Responses to “Zune death”
  1. Andrew says:

    Actually that code is really confusing, mainly because it looks like ‘days’ is trying to be 1-based, not 0-based.

    So on that basis, changing > to == will have different unintended consequences.

    If they wanted to continue with this logic, then they would best lift the IsLeapYear into the main loop condition.

    ie

    while ((days > 365 && !IsLeapYear(year)) || days > 366)

    But this is a dumb way of calculating this stuff. If you want to do it without a loop, see:

    http://en.wikipedia.org/wiki/Julian_day

    In particular, look at the “Gregorian calendar from Julian day number” section at the bottom.

  2. Dave Latham says:

    I think rather the innermost is clause should have an else { break; } in there.

  3. AMcguinn says:

    Yes, I agree with Andrew & Dave, the >366 logic is correct, as the day is 1-based, otherwise it would be wrong every year. It’s meant to say if the day is after 365, then roll the year, unless it’s a leap year and the day is not after 366. But without the break it’s going into an endless loop on the 31 dec of a leap year.

  4. Eric Burke says:

    Also, the method says “Returns TRUE if successful, otherwise returns FALSE.”, but it looks like it always returns TRUE. Why return anything, if that’s the case?

    Anyway, looks a lot better than the code I have to maintain on a daily basis. :-(

  5. Walter Harley says:

    This sort of confusion between ‘count’ and ‘index’ was one of the motivators of Charles Simonyi’s original version of Hungarian notation (as distinct from the rightfully-derided, dumbed-down, unuseful version of Hungarian that was popularized in Petzold’s Programming Windows book, and that appears in this sample). The point of Simonyi’s Hungarian was to efficiently convey datatype distinctions that the compiler can’t know about, like the distinction between the size of an array and an index into the array, or between a count of pixels and a count of dialog units.

    If the constants were named (e.g., DAYS_IN_LEAP_YEAR versus LAST_DAY_OF_LEAP_YEAR), and/or if the “days” variable were prefixed with something that indicated whether it is zero- or one-based, it would be easier to figure out what the code was supposed to do. Code always tells you what it does do, but it doesn’t always tell you what the developer thinks it should do.

    Stepping back a bit: there are certain common confusions, and those (not others) are the ones that deserve comments. Is an int value a sign or a count? Is a C string null-terminated or not? Can a pointer be null? Does a window size include the borders? Is a utility method reentrant? What is the expected lifecycle of a class? And so forth. It’s just amazing to me how often I see comments like “determine whether it is a leap year” before a call to isLeapYear(), versus how rarely I see comments that might actually be useful.

    Stepping back even further: why does the Zune need to know what day it is, anyway? I’ve never had to set the clock on my CD player.

  6. Anonymous says:

    How many times is 10 minutes contained in one hour?

    1 hour = 60 minutes, therefore,

    60 minutes ÷ 10 minutes = 6

    I have used simple division, but Zune uses repetitive subtractions to know the answer:

    60 – 10 = 50 (1 time)
    50 – 10 = 40 (2 times)
    40 – 10 = 30 (3 times)
    30 – 10 = 20 (4 times)
    20 – 10 = 10 (5 times)
    10 – 10 = 0 (6 times)

    To know how many years are between a some known and convenient base date (for example January 1, 2000), and a a future date giving the elapsed days, we only have to divide by 365.2475:

    days= modf (elapsedDays/ 365.2475, &years);

    it is only one line code.

    And if we only have integer arithmetic, it can be done with a little more difficulty.

    The bug with Zune is difficult to note because it isn’t obvious, but the program logic is very ugly. Is Windows Vista coded in this bloated way?

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!