?
Dann nimm meinetwegen
double tropical_years = (julian_day(y2, m2, d2) - julian_day(y1, m1, d1)) / 365.2425;
Der Punkt ist, dass man bei Berechnungen auftretende Zwischenergebnisse auch berücksichtigen muss.
Anwendungsabhängig mag ein Jahr noch negativ werden können (obwohl ich von der Behandlung vorgregorianischer Zustände absehen würde, wenn es um zeitgenössische Zusammenhänge geht), aber das julianische Datum ist es per Konvention nicht. Will man weiter als ins Jahr -4712 zurückgehen, muss man zu anderen Mitteln greifen. Auch nehmen Monat und Tag eines Datums nie negative Werte an, es ist aber beim Rechnen mit ihnen durchaus praktisch, ein Vorzeichen zur Verfügung zu haben. Wenn du ein Sparbuch hast - da werden die Zinsen nach wie vor mit der 30/360-Methode berechnet:
int zinstage = (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1);
jetzt stell dir mal vor, wie viel hübscher das wäre, wenn die alle von Hand ge-static_cast<int>-et werden müssten.
Es gibt natürlich Zusammenhänge, in denen die Darstellung negativer Zahlen absolut unerwünscht ist, und da macht unsigned dann auch Sinn (fällt unter o.g. "gute Gründe"), und mit Sicherheit ist die Nutzung zweckgebundener typedefs eine sehr, sehr gute Idee (zumal man dann auch leicht ein Vorzeichen einführen oder abschaffen kann, wenn dieses notwendig oder überflüssig werden sollte). Ich meine nur: im Zweifel für das Vorzeichen. Will sagen, wenn keine guten Gründe dagegen sprechen, sollte man ein Vorzeichen ruhig zulassen - sonst kriegt man leicht unerwartete Nebeneffekte, wenn man mit einem vorzeichenbehafteten Typ in Berührung kommt.