Fixing a Small Calc.exe Bug
petertissen.de
petertissen.de
Some of you might recall how all Zune devices died on 12/31/08.
Windows_Globalization_Calendar_AddMonths_System_Int32 was the root of it all, apparently.
(For further reading on the Zune outage: https://techcrunch.com/2008/12/31/zune-bug-explained-in-deta...)
https://bugs.launchpad.net/ubuntu/+source/cupsys/+bug/255161...
Absolutely loved reading through the bug! haha
What's the underlying issue, really? Is it that detecting file types by checking for magic strings is always a bad idea? Or is it something more basic about the architecture here, more like the leaky abstractions problem?
So, I would actually disagree with the author that it is strictly a bug in the ‘file’ utility, as there is simply no completely reliable way to determine intended file type by just looking at the content[1]. You have to transmit that information out of band, and this is why we have MIME types sent through Content-type: headers in HTTP or email headers. File extensions are another method (though also ambiguous: .TXT and .EXE are almost certain, but a .DB or .BAK can be one of many things).
CUPS is probably applying this heuristic for convenience (“send anything to your printer and it just prints!”), at the cost of correctness.
[1] A simple proof for that is the existence of “polyglots”, which in this context are source code that happens to be a valid program in two or even more different programming languages (often doing the same or similar things for sport). Were CUPS to differentiate printing based on the programming language, e.g. by applying different syntax highlighting, it would not know what language to choose, and without out of band information there hardly even is a “right” answer. In practice though you can detect a file type more reliably than ‘file’, but at much more complexity than “let’s check some magic numbers in some offsets to give the user an idea of what this might be”, and it still wouldn’t be perfect.
But yes, the difficulty in verifying a correct implementation of date and time calculation calls out for a standard test apparatus to "prove" correct results for a defined scope.
I believe this to be one of those rites of passage for any programmer.
1. As a string you don't touch
2. Convert to seconds_since_the_epoch immediately. Convert back only when necessary (when printing to the screen or sending to a SQL query for example).
This calc problem is somewhat unique because months and years aren't fixed length and it's probably bad if your program says Feb 1 to March 1 is less than a month, or Jan 1 2000 to Jan 1 2001 is a year and a day. Or if Jan 1 2001 to Jan 1 2002 is a year and a quarter of a day. And then you have to account for those occasional years that are divisible by 4 but are not a leap year. And then you have to account for when someone asks for the difference between September 1 1752 and September 20 1752. Pretty soon you're remembering why rules 1 and 2 exist. It should be noted that calc.exe gets this wrong in many ways.
oh my sweet summer child
Many interesting debugging stories are collected in this GitHub repository [3].
[1] https://github.com/angular/angular.js/issues/5017
I've found countless ones of these. Some of them in date/time/timezone handling libraries.. :/
It's good to see that Microsoft's "open source" programs aren't just code-dumps
New MSFT really "gets" open source. It's an exciting time.
The same thing it means when something is 2 years away when the years could be different lengths?
The month is a well-defined unit within the context of a certain calendar. And since a normal date representation contains the month as a singular component, month additions are usually well-defined (the obvious exception being, adding N months to yyyy-mm-31 -- the result is undefined, though most people will assume it to refer to the first day of the month following).
There is no need to bring mathematical strictness into it, because months are never used for that purpose. Moreover, no calendar system is built for mathematical strictness anyway, so arguing for that kind of strictness is like building a house on quicksand.
In my experience (in my culture), we avoid these problems by just assuming that we'd never convey a precise date in this manner: anything more than a week away we tend to convey with the exact date (March 15th); or, we might say "exactly two weeks from today" or "exactly one month ago" (implying the same numerical day-of-month, regardless of how long each month is), but I don't think we'd ever say "exactly one and a half months from now".
And this is why calendars are hard: it's as much (or more) anthropology as it is arithmetic.
I wouldn't, I'd assume it's the last day. For me, any date that is "two months after" any date in July should fall in September, with the days longer than the target month scaling down. So two months after July 31 should be, to me, September 30.
But,
$ date -d "2019-07-31 +2 months"
Tue, Oct 1, 2019 12:00:00 AM
Suggests I'm in the minority. > (date 2019-07-31).AddMonths(2)
Montag, 30. September 2019 00:00:00
.NET agrees, though :)For software libraries it's a bit of a pickle, though, as you have the trade-off between »do what an end user would expect« and »do exactly as told, and let the programmer deal with the weirdness«. Admittedly, adding months is something that I'd rarely do as a programmer when the context isn't what a user would expect. Adding 30 days can be done in much the same way if that's really what's intended.
Interesting question, though: Is 2 months from 2019-07-28 2019-09-28 because the day part is the same, or 2019-09-27 because it's three days from the end of the month? ;-)
That's actually exactly what happened. The original calc.exe (in all versions up to Windows 8.1) came from Windows 1.0, in plain C, very seldomly updated over the years.
The one in Windows 10 is totally rewritten in C++ using the "Universal Windows Platform" as an API rather than classic Win32.
> tldr; saw a Windows Calculator bug on reddit. Since calc.exe was open-sourced I thought I’d try to find the bug and fix it.
As for the bug in question, it could not have happened in the old calculator, as that one didn't have the date math panel.
So for the UWP version they merely redid the UI and added a few things. The actual calculator part is still the same as before (just open-source now).
From July 31 2019 to Dec 30 2019: "5 months; 6 days", 152 days
From July 31 2019 to Dec 31 2019: "5 months", 153 days
I agree that there are 153 days from July 31 to Dec 31 (aug+sep+oct+nov+dec = 31+30+31+30+31 = 153) but I'd say that there are too many Februaries among the months in the first result.I remember being super happy when I replicated the functionality, using wdasm32 and HIEW to patch my notepad code.
The best I could found is a similar tut where they are adding other features to notepad:
http://www.kaoteq.com/sites/fravia/fravia-darkridge/nnhnpad....
This brought me lots of memories, learning from +ORC, tKC and +HCU was the bomb back when I was in University.
I could not find the one specific for adding line numbers though.
https://www.gangboard.com/business-intelligence-training/tab...
> license/cla All CLA requirements met.
Also mentioned in https://github.com/microsoft/calculator/blob/master/CONTRIBU...
The page you linked indicates that a bot will comment on the PR. I am looking at https://github.com/microsoft/calculator/pull/553, but I do not see any bot-generated comments, other than the "All CLA requirements met." status line you mentioned; and I do not see a "cla-signed" or a "cla-not-required" tag on the PR.
Still annoying, regardless.
But it looks like the CONTRIBUTING.md file wasn't updated to reflect this change.
It is clear that the duration between 2015-05-15 [1] and 2019-06-19 is about 2019 - 2015 = 4 years or exactly 1,496 days (or 1,497 days including both endpoints, yeah this is also somewhat ambiguous). It is much less clear that the duration in question is 4 years, 1 month and 4 days; depending on the use case months can be uniformly 30 days long, may or may count the "excess" days, or even do not matter (in which case the duration would be 4 years and 35 days). Generally such a duration is ambiguous without a context and it would be misleading to present it as exact.
[1] https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve... (in case you wonder)
June 15th 2015 and July 19th 2019 is 4 years 1 month and 4 days apart. That is the duration that occurred between the two dates and is totally unambiguous to non-programmers.
The fact that calendar distance and 'time' distance don't have a linear relationship and that math that governs the relationship between the different units isn't straightforward doesn't make it unprecise or misleading.
It's totally exact. Just because you can't convert the calendar distance to time distance without context doesn't make it any less exact. Not so different to being unable to compute distance traveled by the revolution count of your wheels.
Edit: Also the same way that "tomorrow" can be in 5 minutes.
(It has rules, of course, for dealing with 30 day months when you're on the 31st and you add a "month". The normal timedelta class from the standard library doesn't do "months", since, as you note, it's not really a measure of time.)
In Unix timestamps, over a leap second, a difference of 1 Unix second is occasionally 2 seconds long.
To say months shouldn't be used is sort of like saying that complex numbers or vectors shouldn't be used. They are absolutely useful. We just deal with their component parts separately.
Complex numbers and vectors are not a good analogy.
The mapping from "month" units to "days" units is well-defined. It's just some function that happens to be non-constant over the month ordinal.
Heck, if we start down the "precise time definition" rabbit hole, though, then neither does "day" have some philosophically unassailable notion, cf. leap seconds. Even the unit of "second" ends up pulling in a whole heck of a lot of physics machinery just to nail down some semblance of rigor.
Anyway, despite being such an intuitively simple and practically functional concept, the notion of time amd time measurement turns out to be suprisingly subtle and to have a fascinating history. I highly recommend jumping down that rabbit hole. Hehe
Anyway, I'm surprised calc.exe doesn't calculate with and store dates using some kind of epoch time.
Edit: except when giving an approximation, which the program doesn't
In some cases you can take "a month from now" to mean the same calendar day of the next month. This leaves what a month from January 31 means ambiguous, and also dependent on when the duration starts.
You can take an easier route and say that a month is 30 days. Still, the duration is ambiguous because it depends on when it takes place (i.e. an interval), because of summer/winter time adjustment. You can say that it's 720 hours, but that's still dependent on the start of the duration because of leap seconds. In the end, the only way to describe a duration unambiguously regardless of its start time is with seconds. There is no such thing as a well defined duration for any other unit of time.
ie: https://infiniteundo.com/post/25326999628/falsehoods-program...
it’s far more sane to define it that way than to say the duration of a minute (and hence hour, and day, and week) is variable.
The truth in both cases is of course that while the meaning is contextual and imprecise, it's still useful because people generally don't use precise measurements in their day-to-day activities. When someone tells me that something will happen in a month, I take it to mean something in the ballpark of 28-31 days, and that information can be useful to me.
Because of leap seconds, the only really unexceptional unit of time is seconds, but someone telling me that something will happen in 2592000 seconds isn't particularly useful to me.
The Windows calculator is terrible design. To calculate deltas between two dates you need to convert them to seconds, subtract them, and convert the result back to an absolute time.
The date that occurs "in one month" is the same day day-of-month in the following month. The same is true for years. Between christmas day one one year and boxing day the next year, it's "one year and one day", regardless of whether that actually means 366 or 367 days.
If on christmas day you say "In one year and one day we'll travel to australia", you aren't really specifying a duration but a date in the future. Listeners understand that regardless of whether the following year is a leap year, what you are describing is boxing day the following year.
While you could specify the same thing with an more precise interval such as 367 days, that's actually less useful as a way of describing the date of the event, but a more exact way of describing the interval of time to the event.
So what the calculator shows, is how to communicate a date to another human, in the inexact way that they expect. This is actually a tricky problem in programming (as is obvious by this bug)
`1 month - 10 hours` = 30 days
`2 months - 20 hours` = 60 days
May be the strategy when doing this is change to a different approach. Not calc as in unix or try hard to do it. But to it as a separate rule based program.
The old calculator was briefly shipped as a separate component called "win32calc.exe" in 10-based versions without apps, and that's what the calc.exe stub defers to in those cases.
Also, props for working for free for a multibillion corporation.
Sure, because no one should be proud of fixing a bug for the millions of people that use that operating system. Satisfying intellectual curiosity and helping somebody for free, the big evils of our time!