2

Recently, I found myself in the need to know the number of days separating two dates for a little program I was writing in C.

I searched online for a solution but found nothing for C.

How could I do it?

Enrique
  • 61
  • 1
  • 6
  • There are many duplicate candidates for this question: https://stackoverflow.com/search?q=calculate+days+between+two+dates+%5Bc%5D – Clifford Sep 25 '22 at 17:45
  • @Clifford Non of them could help me as most of them consist of people asking for help. So I when I found my own solution I decided to post a question and answer it myself. – Enrique Sep 25 '22 at 18:09
  • Aieeeeeeeeeeeee! I did not notice that you already had an answer. If I knew you already had an answer, I would not have spent so much time composing mine. :-( – Steve Summit Sep 25 '22 at 18:30
  • That makes no sense -- all questions are asking for help - that is kind of the point. some of them even have answers ;-). Those along the lines of @chux-ReinstateMonica are simpler than your solution. The standard library time.h functions are likely to be less error prone than rolling your own, and the `time_t` and `struct tm` representations are , well _standard_. The only reason I did not vote to close is because answers posted here were more thorough than elsewhere, and by users you should trust. – Clifford Sep 25 '22 at 18:35
  • @Clifford I understand what you say and thought the same, but later I thought I was doing fine as I read this from one of the StackOverflow co-founders: https://stackoverflow.blog/2011/07/01/its-ok-to-ask-and-answer-your-own-questions/?_ga=2.258260623.445966244.1664109445-245637659.1636228270 – Enrique Sep 25 '22 at 18:41
  • @SteveSummit Im so sorry, but I was induced to publish a question I already knew the answer to (with my answer) by this "article": https://stackoverflow.blog/2011/07/01/its-ok-to-ask-and-answer-your-own-questions/?_ga=2.258260623.445966244.1664109445-245637659.1636228270 – Enrique Sep 25 '22 at 18:43
  • 1
    @Enrique No worries. You're right: there's no rule, in general, against posting a question and a good answer for it. And all kidding aside, I composed my own answer primarily to satisfy myself, and for Stack Overflow in general, not for you in particular! (Nothing personal. :-) ) – Steve Summit Sep 25 '22 at 19:15

4 Answers4

4

There are basically two ways of doing this:

  1. Use standard tools. Use the standard library function mktime to construct a time_t value corresponding to each date. Then subtract, and convert the difference to units of days.
  2. Write your own little ad-hoc code to construct a form of Julian day number. Again, subtract. This is at least a little bit complicated, full of fussy little details that are difficult to get right, but it's a great and satisfying exercise. ("Satisfying", at least, if you're a time nerd.)

Method number 1 looks like this:

#include <stdio.h>
#include <time.h>
#include <math.h>

int main()
{
    struct tm tm1 = { 0 };
    struct tm tm2 = { 0 };

    /* date 1: 2022-09-25 */
    tm1.tm_year = 2022 - 1900;
    tm1.tm_mon = 9 - 1;
    tm1.tm_mday = 25;
    tm1.tm_hour = tm1.tm_min = tm1.tm_sec = 0;
    tm1.tm_isdst = -1;

    /* date 2: 1990-10-02 */
    tm2.tm_year = 1990 - 1900;
    tm2.tm_mon = 10 - 1;
    tm2.tm_mday = 2;
    tm2.tm_hour = tm2.tm_min = tm2.tm_sec = 0;
    tm2.tm_isdst = -1;

    time_t t1 = mktime(&tm1);
    time_t t2 = mktime(&tm2);

    double dt = difftime(t1, t2);
    int days = round(dt / 86400);

    printf("difference: %d days\n", days);
}

Filling out a struct tm like tm1 and tm2 is a little tricky. The tm_year field is counted from 1900, so you have to subtract 1900 when filling it in, as shown. The tm_mon field is 0-based, so you have to subtract 1 from the month number. You have to pick a time; here I've arbitrarily picked 00:00:00 midnight. Finally, in the tm_isdst field you have to specify whether you're inputting a standard or daylight time (0 or 1), or if you don't know or care (-1).

Then the function mktime returns a time_t value corresponding to the date and time you specified. time_t is usually a Unix count of UTC seconds since January 1, 1970, although strictly speaking the C Standard says it can have any implementation-defined encoding, so the safest way to subtract two time_t values is to use the difftime function, which returns a difference guaranteed to be in seconds. As every time nerd knows, there are 86400 seconds in a day, so divide the difference-in-seconds by 86400, and you've got a number of days.

This all looks pretty straightforward, although there are a couple of subtleties to beware of. If you look carefully at the difftime differences you get, you will find that they are often not an exact multiple of 86400, if the two dates you specified happen to span a daylight saving time changeover. (If so, you had at least one day that was either 23 or 25 hours long.) That's why it's vital to round the result of dividing by 86400, as shown in the example code. Usually it's also a very good idea to fill in tm_hour as 12, not 0, since using noon (i.e in the middle of day, not right at the midnight day changeover) can also help to avoid various anomalies.

So that's method 1. Here's the beginning of method 2. We're going to write a function makejd that computes a modified "Julian day" number. In general, a Julian day number is one that increases from day to day, without regard to month and day boundaries. For example, this makejd function is going to compute day number 154035 for today, September 25, 2022. September 1 was day number 154011, and the day before that, August 31, was day number 154010. For reasons we'll get to, these day numbers go all the way back to the year 1601, where January 1 was day number 1.

(In the real world, different Julian day numbering schemes use different base days. The official Julian Day numbers go back to 4713 BC; there's also an official "Modified Julian Day" or MJD number that's based on 1858.)

Anyway, here's makejd:

#define BASEYEAR 1601      /* *not* arbitrary; see explanation in text */

long int makejd(int year, int month, int day)
{
    long int jdnum = 0;
    jdnum += (year - BASEYEAR) * 365L;
    jdnum += (year - BASEYEAR) / 4;
    jdnum -= (year - BASEYEAR) / 100;
    jdnum += (year - BASEYEAR) / 400;
    jdnum += monthcount(month - 1, year);
    jdnum += day;
    return jdnum;
}

I love this function, because the problem that it solves sounds very complicated at first, but the function itself looks halfway reasonable, and once you understand how it works it's downright simple.

Basically, to count up the total number of days, since that base date in the far past, up to the date we care about, we have three pieces to worry about:

  1. We'll have 365 days for every full year.
  2. Then we'll have some number of days corresponding to full months that have gone by from the start of the year, to the month we're in.
  3. Finally, we have some number of days into the month we're in.

(And then of course there are some leap year corrections, which I'll explain in a minute.)

For example, if the base year was 2020 and we were worried about today's date (September 25, 2022), we'd have two years times 365 = 730 days, plus 243 (which is the sum of the lengths of the months January through August), plus 25, for a total of 998. (That'd be for a hypothetical base year of 2020. As mentioned, we're actually going to use 1601 as our base year.)

So the makejd function simply performs those three calculations, plus the various leap year corrections. The first line,

jdnum += (year - BASEYEAR) * 365L;

literally does step 1 above, computing the difference between the year we care about, and the base year, times 365. Step 2 is the line

jdnum += monthcount(month - 1, year);

which uses a separate function to compute the total number of days in the months 1 through N, where N (that is, month - 1) is the month before the one we care about. Finally, step 3 is the very simple

jdnum += day;

where day is the day we care about.

And then we come to the leap year corrections. Every 4 years is a leap year, so the line

jdnum += (year - BASEYEAR) / 4;

takes the number of full years we care about, divided by 4, and that's a few more days we need to add in. (In other words, we have to add in one day for every four years that elapsed since our base year.)

But the rule is not quite that every fourth year is a leap year. The actual rule for the Gregorian calendar we use is that every four years there's a leap year, except that every 100 years there's not a leap year (that is, 1900 was not a leap year), except that every 400 years there is a leap year, after all (that is, 2000 was a leap year). So those two lines

jdnum -= (year - BASEYEAR) / 100;
jdnum += (year - BASEYEAR) / 400;

take care of subtracting out the every-100-years non leap years, and adding back in the every-400-years leap years.

Note, however, that these simple expressions work properly only for certain carefully-chosen values of the base year, such as 1601. If we'd used some other base year, there would have been a certain number of awkward ±1 fudge factors.

Now we can go back to the monthcount function. If we cared about the date "September 25", it's monthcount's job to count up all the days in the full months January through August. (Stated another way, monthcount computes the partial Julian day number of "September 0", setting us up to be able to add in the exact day we care about, like 25.) monthcount is simple and straightforward:

                     /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
int monthlengths[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/* return total days from January up to the end of the given month */
int monthcount(int month, int year)
{
    int r = 0;
    for(int i = 1; i <= month; i++)
        r += monthlengths[i];
    if(isleap(year) && month >= 2)
        r++;
    return r;
}

This function uses a pre-initialized array monthlengths[] containing the lengths of each month. ("Thirty days hath September...") Since C arrays are 0-based, but we always think of January as being month number 1, to keep things simple this array "throws away" (wastes) cell 0, so that monthlengths[1] is 31 for January.

This function is also a second place we have to worry about leap years. In leap years, of course, February has 29 days. So if this is a leap year, and if we're being asked to compute the count of days in months through February or beyond, we have to add in one more day. (That's why the monthcount function needs to have the year number passed in also.)

The only remaining detail is that little isleap function that monthcount uses as part of its decision of whether to add in February 29. It's simply:

int isleap(int year)
{
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

, using the formulation from question 20.32 of the C FAQ list.

...And that's it. Hopefully now the workings of the makejd function are clear, even if you choose not to use anything like it.

And, speaking of that choice, it's worth asking: which way should you use, method 1 or method 2?

Most of the time, of course, it's better to use prewritten code if you can, rather than "rolling your own" or reinventing the wheel. And when it comes to code for dealing with dates and times, that advice ("use somebody else's prewritten code") is doubly or even triply valid, because dates and times are notoriously complex, and it's ridiculously easy (almost guaranteed) to get at least one of the obscure details wrong, resulting in subtle bugs.

So I will almost always use method 1. In fact, it's usually worth going out of your way to figure out how to use the standard date/time functions, even to solve a problem that they're not an immediately obvious fit for. (See, for example, this answer, where I contrive to use mktime to answer the question, "On what day of the week does a given month begin?".)

Once in a while, though, you may find yourself in a situation where the standard functions aren't suitable, and in that case, knowing how to "roll your own" can be extremely useful. Just be careful, and test your code thoroughly, for lots of different dates and times! (Situations where you might need to roll your own are when you're working with far-past or far-future dates that type time_t might not be able to handle, or when you're working in an embedded environment where you don't have a full C library available.)

The other way to choose might be to just look at which code is shorter or simpler. Method 1 is a bit more cumbersome than I'd like, mostly because filling in all the fields of a struct tm one by one is a plain nuisance. Method 2 is a bit longer, although not actually all that much longer. (It looks quite a bit longer here, but that's just because I've surrounded it with so much longwinded explanation.)


Footnote: I said "I love this function", and I do, but I confess it's got one blemish, a violation of the DRY principle. The Gregorian leap year rules are embedded twice, once in the lines

jdnum += (year - BASEYEAR) / 4;
jdnum -= (year - BASEYEAR) / 100;
jdnum += (year - BASEYEAR) / 400;

in makejd, and then a second time, completely separately, in the isleap function. If we ever change calendars, someone will have to remember to change the rules in both places. (I'm not joking! DRY is a splendid principle, and I do like to follow it when I can, and this is definitely a violation. But exploring the possibility of applying the principle here will have to be a topic for another day, as I've already written about 3× as much here as I intended to.)


Addendum: I wrote that ad-hoc code like makejd is "full of fussy little details that are difficult to get right", and to prove that point, I can confess that despite thinking I knew how to circumvent those details, the makejd function I initially posted here fell prey to precisely that problem. I dashed off a quick version, tested it on one or two data points, made one slight correction, then called it good and posted it. But I did not follow my own advice and "test the code thoroughly"! That task fell to @chux, who did the testing I should have, and found a data point (actually there were lots) for which the code as posted gave an answer that was off by a day.

So, yes, code like this is tricky to get right, there are lots of opportunities for nasty little off-by-one errors, if you're going to write some new code you're going to have to test it very thoroughly, and if you don't want to do that you'd probably rather use something prewritten.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • "tm2.tm_isdst = 0;" avoids the "two dates you specified span a daylight saving time changeover"" issue. Rounding the result still a good idea. Helps to deal with rare leap seconds implementations. Agree with "good idea to fill on tm_hour as 12,". – chux - Reinstate Monica Sep 25 '22 at 17:48
  • @chux Setting isdst to 0 would work here, but I feel it's basically a lie, and for other `mktime` uses it'd be quite wrong, so I like to encourage the habit of always setting it to -1. – Steve Summit Sep 25 '22 at 18:35
  • Very nice and complete answer. I found out that the function you describe in the second method is similar to the one I created from scratch. I could use yours to upgrade mine, and in the end I would prefer mine (am I an egomaniac?), or for something important, method 1. – Enrique Sep 25 '22 at 18:35
  • @chux Initialization fixed. (Only cost one line. :-) ) – Steve Summit Sep 25 '22 at 18:35
  • @Enrique Use whichever you wish — truly, I don't mind. (I'll have one or two points to offer on your answer, in due course.) – Steve Summit Sep 25 '22 at 19:17
  • 2
    @Enrique Chances are "the one I created from scratch" contains corner case errors. Even seasoned coders seek review on time functions before claiming success. Best to assume such code is wrong until proven right. Off by one errors are common. – chux - Reinstate Monica Sep 25 '22 at 19:18
  • @SteveSummit I would appreciate any feddback very much :) – Enrique Sep 25 '22 at 19:21
  • 1
    @Enrique Solutions you write, with test code, could be posted on [Code review](https://codereview.stackexchange.com/) for a critique. Be sure to identify the range of acceptable values. – chux - Reinstate Monica Sep 25 '22 at 19:31
  • @chux Oh, dear! Yes, something was definitely amiss. Now fixed, and I've belatedly done some semi-exhaustive testing, but there's more to do. Thanks for your attentiveness. – Steve Summit Sep 26 '22 at 13:58
  • Better. With 1601, code has trouble with 1601/1/1, 1600/12/31 both report 1, same for many earlier dates. But then maybe that is OK as code it not meant for earlier date then 1601. Gregorian start in 1582. It is because the `%` in [not mod](https://stackoverflow.com/a/20638659/2410359). I suggest `#define BASEYEAR 1` to handle years >= 1 or use a true mod function. FWIW, [this](https://stackoverflow.com/a/73848144/2410359) may have similar trouble with `year < 0` - something that needs testing. – chux - Reinstate Monica Sep 26 '22 at 14:24
2

I have created a function which converts a date to the number of days that have passed since 01/01/0001 until the input date:

// Define a date data type.
struct date {
    int day, month, year;
};

/*
 * Function's limits (included):
     * bottom: 01/01/0001
     * top: 31/12/9999

 * Input: date data type.
 * Output: (int) number of days from 01/01/0001 to that date.
 */

unsigned long int convertDateToDays(struct date date){
    unsigned long int totalDays;
    int numLeap = 0;
    int monthsAddFromYearStart[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
    int i;

    // First, calculate the number of leap year since year one (not including date's year).
    for(i = 1; i < date.year; i++)
        if((i % 4 == 0 && i % 100 != 0) || (i % 4 == 0 && i % 400 == 0))
            numLeap++;

    // If it is a leap year, as of March there has been an extra day.
    if((date.year % 4 == 0 && date.year % 100 != 0) || (date.year % 4 == 0 && date.year % 400 == 0))
        for(i = 2; i < 12; i++)
            monthsAddFromYearStart[i]++;

    // (Year - 1) * 356 + a day per leap year + days totaling the previous months + days of this month
    totalDays = (date.year - 1) * 365 + numLeap + monthsAddFromYearStart[date.month - 1] + date.day;

    return totalDays;
}

This way you can convert two dates to days and then compare them very easily. Here is an example:

struct date startDate = {28, 02, 0465};
struct date endDate = {30, 06, 2020};
unsigned long int dateDifference, dateDifferenceLastDateIncluded;

dateDifference = convertDateToDays(endDate) - convertDateToDays(startDate);
dateDifferenceLastDateIncluded = convertDateToDays(endDate) - convertDateToDays(startDate) + 1;

printf("Difference in days: %lu.\n", dateDifference);
printf("Difference in days, last date included: %lu.", dateDifferenceLastDateIncluded);

/*
 * Output:
Difference in days: 625053.
Difference in days, last date included: 625054.
 */

Just define a date struct including day, month and year, and pass it to the convertDateToDays() function as a parameter. Notice that the function returns an unsigned long int. That's because the day count in extreme cases is huge (i.e. 31/12/9999).

You can convert now two dates to days and calculate the difference between them. If you want to include the last date in the operation just add one day, as the example shows.

Hope this was helpful!

Enrique
  • 61
  • 1
  • 6
  • Leap years from before 1500s and after AD12 are usually considered every 4 years. I'd suggest a bottom: of [15 October 1582](https://en.wikipedia.org/wiki/Gregorian_calendar) to avoid early calendar issues. – chux - Reinstate Monica Sep 25 '22 at 19:35
  • 1
    `for(i = 1; i < date.year; i++)` is very slow to determine `numLeap`. That should be done without a loop. Same for `for(i = 2; i < 12; i++)` – chux - Reinstate Monica Sep 25 '22 at 19:37
  • Many standard time functions gracefully return an error when parameters are out of valid range. A good `convertDateToDays()` would do so likewise rather than return nonsense or UB. – chux - Reinstate Monica Sep 25 '22 at 19:42
  • @chux-ReinstateMonica -- unless I am mistaken, `mktime` is not required to return an error value when it is given a `tm` struct with e.g. days outside of [1, 31] or months outside of [0, 11]. Or maybe you meant something else. – ad absurdum Sep 25 '22 at 19:46
  • @adabsurdum Yes, misstated. With `mktime()`, the `struct tm` members are not restricted in range and are updated to their primary range. "if the calendar time is not available." (e.g. outside `time_t` range), `(time_t)-1` is returned. – chux - Reinstate Monica Sep 25 '22 at 19:49
  • @chux-ReinstateMonica -- right, but if input has e.g. month 23, that is likely an input error; the result of allowing `mktime` to force member values to expected ranges may not be desirable. My point was that `mktime` will not tell you if something may be amiss here. It may be best to validate input by other methods. – ad absurdum Sep 25 '22 at 20:35
  • @adabsurdum " if input has e.g. month 23, that is likely an input error; " --> No. `mktime()` is specified that way to be useful. Consider for a given date and then 1 year, 2 months, 3 days after that. Simple add the offsets and call `mktime()` and read its re-computed members. Very handy. Data validation is also simple. Call `mktime()` with suspect date. If the same, it is valid, else not. – chux - Reinstate Monica Sep 25 '22 at 21:16
  • @chux-ReinstateMonica -- I don't think that I have been clear; my last comment certainly didn't make this clear. If a user enters a date by typing `"2022/23/1"` where yyyy/m/d is expected, they probably meant to type something else. I agree that the offsets calculation is useful, but that usefulness precludes using error values returned by `mktime` as input validation for dates. – ad absurdum Sep 25 '22 at 21:26
  • 1
    @adabsurdum The return value of `mktime()` can be used as _part_ of validation. `.tm_year == 2039-1900` readily fails for 32-bit `time_t` and `.tm_year=2030-1900` is OK. The precise edge is something best left for `mktime()` and friends than trying to validate first. – chux - Reinstate Monica Sep 25 '22 at 21:37
  • Enrique, `unsigned long totalDays = (date.year - 1) * 365 + numLeap + monthsAddFromYearStart[date.month - 1] + date.day;` has no benefit to save as an `unsigned long` as the math used is `int` math. Consider `(date.year - 1L) * 365 ...` or like code to insure wider math is used. This will be critical for correct results if `int` was 16-bit. – chux - Reinstate Monica Sep 25 '22 at 22:46
  • 1
    Enrique, Code appears _functionally_ correct for your stated range. – chux - Reinstate Monica Sep 25 '22 at 22:52
2

To solve this using standard functions:

<time.h> offers struct tm, mktime() and difftime().

#include <limits.h>
#include <math.h>
#include <time.h>

// y1/m1/d1 - y0/m0/d0 in days
// Return LONG_MIN on error 
long days_diff(int y1,int m1,int d1,int y0,int m0,int d0) {
  // Important: Note other struct tm members are zero filled.
  // This includes .tm_isdst to avoid daylight savings time issues.
  struct tm date0 = { .tm_year = y0 - 1900, .tm_mon = m0 - 1, .tm_mday = d0 }; 
  struct tm date1 = { .tm_year = y1 - 1900, .tm_mon = m1 - 1, .tm_mday = d1 }; 
  time_t t0 = mktime(&date0);
  time_t t1 = mktime(&date1);
  if (t0 == -1 || t1 == -1) {
    return LONG_MIN;
  }
  double diff = difftime(t1, t0); // Difference in seconds
  const double secs_per_day = 24.0*60*60;
  return lround(diff/secs_per_day);  // Form the difference in `long` days.
}
  
  
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    Note that the `mktime()` approach is problematic for locales that shifted the side of the international date line. Example [No January 1, 1995 in Kiribati](https://www.timeanddate.com/time/zone/kiribati) and repeated [4 July 1892](https://en.wikipedia.org/wiki/International_Date_Line#Samoan_Islands_and_Tokelau_(1892_and_2011)) - should we are about historic events. – chux - Reinstate Monica Sep 25 '22 at 19:10
0

To convert year, month, day Gregorian calendar to a day number, consider using the Modified Julian Day as the epoch. It is a well defined count of days from midnight, unlike the Julian date which starts at noon.
MJD 0.0 is November 17, 1858 midnight - local time.

Chances are good you can find well tested code that performs that named calculation.

Unless code has been tested, be wary of its correctness. Time functions have many corners cases that trip up seemingly good code.

Armed with that, simple subtract two day numbers to get the difference between dates.


Below is from an attempt from years ago.

  • Handles all int values of year, month, day without overflow by using int2x math - a type with twice the bits of int. Note int may only be 16-bit.

  • A key features is simplification that shifts dates before March 1, to months of the prior year, making March the 1st month (October the 8th month, December the 10th month, ...). This harkens back to the Romans adding a leap day in the last month of the year - February.

Note that the Gregorian calendar started in October 1582 and was only used by the majority of the planet sometimes in the early 1900s. For earlier dates, we could assume the Proleptic Gregorian calendar.


#include <limits.h>
#include <stddef.h>
#include <stdint.h>

#if LONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long int2x;
#define PRId2x "ld"

#elif LLONG_MAX/2/INT_MAX - 2 == INT_MAX
typedef long long int2x;
#define PRId2x "lld"

#elif INTMAX_MAX/2/INT_MAX - 2 == INT_MAX
typedef intmax_t int2x;
#define PRId2x "jd"

#else
#error int2x not available

#endif


static const short DaysMarch1ToBeginingOfMonth[12] = { //
    0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
#ifndef INT32_C
#define INT32_C(x) ((int_least32_t)1*(x))
#endif
#define DaysPer400Years   (INT32_C(365)*400 + 97)
#define DaysPer100Years   (INT32_C(365)*100 + 24)
#define DaysPer4Years     (365*4    +  1)
#define DaysPer1Year      365
#define MonthsPerYear     12
#define MonthsPer400Years (12*400)
#define MonthMarch        3
#define mjdOffset         0xA5BE1
#define mjd1900Jan1       15020
// November 17, 1858

// Example: 2015 December 31 -->  ymd_to_mjd(2015, 12, 31)
int2x ymd_to_mjd(int year, int month, int day) {

  int2x year2x = year;
  year2x += month / MonthsPerYear;
  month %= MonthsPerYear;
  // Adjust for month/year to Mar ... Feb
  while (month < MonthMarch) {
    month += MonthsPerYear;
    year2x--;
  }

  int2x d = (year2x / 400) * DaysPer400Years;
  int y400 = (int) (year2x % 400);
  d += (y400 / 100) * DaysPer100Years;
  int y100 = y400 % 100;
  d += (y100 / 4) * DaysPer4Years;
  int y4 = y100 % 4;
  d += y4 * DaysPer1Year;
  d += DaysMarch1ToBeginingOfMonth[month - MonthMarch];
  d += day;
  // November 17, 1858 == MJD 0
  d--;
  d -= mjdOffset;
  return d;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256