What is the format for FirstInstallDateTime on Windows 95?


Public Service Announcement: Daylight Saving Time ends in most parts of the United States this weekend.

Windows 98/98/Me recorded the date and time at which Setup was run in the registry under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion as a binary value named FirstInstallDateTime. What is the format of this data?

Take the binary value and treat it as a 32-bit little-endian value. The format of the value is basically DOS date/time format, except that the seconds are always 0 or 1 (usually 1), due to a programming error.

Exercise: What error would result in the seconds always being 0 or 1 (usually 1)?

[Update: Falcon is the first to post the correct answer.]

Comments (19)
  1. John says:

    I don’t know.  It’s kind of hard to mess up:

    DWORD dwSeconds = (dwDosDateTime & 0x1F) * 2;

  2. MrZebra says:

    My guess: they tried to do a bitwise OR but accidentally did a logical OR, thus casting the seconds from an integer to a boolean and therefore causing it to always be either 1 or 0.

    [I’m not quite following. Can you produce the erroneous line of code? wDosTime = …. -Raymond]
  3. John says:

    Doh.  I was going in the opposite direction.

  4. Felix Kasza says:

    The seconds field contains the number of two-seconf increments:

    dosdatetime.seconds = seconds / 2;

    Now type “%” instead of “/”.

    [Getting closer, but this doesn’t explain why it’s usually 1. A % substitution would make it a 50-50 chance of being either 0 or 1. -Raymond]
  5. Henrik says:

    Pity about the daylight saving ending. I enjoyed having new entries show up at 15:00 instead of 16:00 for the past week.

  6. Falcon says:

    I think MrZebra is on the right track – just replace OR with AND.

    (seconds && 0x1F) will be 1 for every value of seconds except 0.

    [Why would anybody write “seconds & 0x1F”? Please provide the actual proposed line of code. wDosTime = …. -Raymond]
  7. like MrZebra said says:

    dwSeconds = wDosTime & MASK_SECONDS; //no?

    [That doesn’t explain why the time is encoded incorrectly. Your proposed line of code is in the decoder. -Raymond]
  8. Leif says:

    dwSeconds = (BOOL) wDosSeconds ?

    [Again, this doesn’t explain the bug in the encoder. And why would somebody write that line of code in the first place? (And even if they did, it wouldn’t explain why the value is always 0 or 1, usually 1) -Raymond]
  9. Garry Trinder says:

    dosdatetime =   …

                | (hours        &  0x1f) << 11  

                | (minutes      &  0x3f) << 5

                | (seconds / 2) && 0x1F;

    [That would explain it, but (and you weren’t expected to know this) the error was a different kind of typo. (See remarks below.) -Raymond]
  10. Falcon says:

    Ok, let’s start with correct code to compute the DOS date/time value:

    dwDosTime = ((dwYear & 0x7F) << 25) | ((dwMonth & 0x0F) << 21) | ((dwDay & 0x1F) << 16) | ((dwHours & 0x1F) << 11) | ((dwMinutes & 0x3F) << 5) | ((dwSeconds >> 1) & 0x1F);

    dwSeconds is right-shifted by one bit to divide it by two. If you mess up by typing “>” instead of “>>”, you’ll be testing whether dwSeconds is greater than 1 instead, which will be true (evaluate to 1) for most values of dwSeconds.

    [We have a winner! Congratulations. -Raymond]

    Another possible error is the one I mentioned earlier: typing “&&” instead of “&”. However, this seems less likely, assuming the programmer knows what they’re doing (which they do if they got the rest of the expression right) – it’s an excessive keystroke, as opposed to a missed one.

    [The doubled-ampersand is less likely because the ampersand isn’t needed at all, since you know that for example the month is always at most 12: dwDosTime = (dwYear << 25) | (dwMonth << 21) | (dwDay << 16) | (dwHours << 11) | (dwMinutes << 5) | (dwSeconds >> 1); -Raymond]
  11. Falcon says:

    Nice to know I got it! I have to give credit to MrZebra for inspiration.

    Good point about not needing to use AND; I was just being cautious.

  12. IA says:

    > the month is always at most 12

    unless it isn’t. I would be quite cautious in what is bit-masked to the timestamp. If something goes wrong and you receive a garbage instead of minutes, it messes up the whole value.

    On the other hand – there is much more oportunities to make a mistake when playing with masking :-)

    [Even if the month value is invalid, ANDing with 0x1F is no better – either way, you generate a result from invalid input. -Raymond]
  13. Vorn says:

    I haven’t installed Windows in a while but I seem to recall at least some OS installers asking what time it is.  If that is the case, then it’s likely that the time input doesn’t have a seconds spot – I don’t know anyone who cares down to the second when setting the time.

    But that’s not a programming error, really, is it.

    …with 0 or 1, uh, heck.  Well if you’ve got your timestamps going with, say, milliseconds since epoch or something (fp unix or win32 time), I’d say they did round(time % 60, 1) / 60 or something silly like that.  For high second counts it’ll give you 1.

  14. 640k says:

    The true Error is the managment with allow this kind of bugs slip away for ages.

    [This bug was not known until July 2007, when I stumbled across it while writing up this entry. So at least in this case, management is not to blame. (And even if they were aware of it, who cares? The error is of no consequence.) -Raymond]
  15. Lawrence says:

    @640k: Why, when reading a description of a bug last manifested in software released almost ten years ago, that was so inconsequential that none of the millions of Windows users ever noticed it OR were affected by it in any way, do you immediately jump to conclusion that it’s a Microsoft management conspiracy?

    Is that *really* the most likely explanation for the bug Raymond described, given that Raymond (a Microsoft developer) is the one describing this bug to you in the first place?

  16. The real error is using a language with absurd C syntax. (Would anyone do this with Delphi/Pascal and ‘>’/’shr’ operators?)

  17. 640k says:

    Is the bug fixed in:

    HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionInstallDate yet?

  18. DriverDude says:

    "The real error is using a language with absurd C syntax"

    That is why Real Men program in C.

    @Lawrence, a smart developer would ask whether the bug is in a shared function (I guess Raymond would have said so if that were the case), and whether the buggy source code has been cut-n-pasted elsewhere (which I don’t expect Raymond to know.)

    So, yes, a 10-year old bugs do matter, even though I agree in this case the consequences seem minor.

  19. Lawrence says:

    @Burak: To answer your question: No, Pascal will prevent entire classes of ‘typo’ bugs like this, which is a good thing.

    But to counter your bogus assertion: I don’t believe Delphi was an option when developing the Win95 installer. Remember the title of this blog.

Comments are closed.

Skip to main content