<p>The formula is correct. However, the &quot;problem&quot; is with Python<sup>1</sup>. <a href="https://stackoverflow.com/questions/5535206/negative-integer-division-surprising-result">https://stackoverflow.com/questions/5535206/negative-integer-division-surprising-result</a>.</p>
<p>Here is the fix to the formula:</p>
<blockquote>
<p>jd = (1461 * (y + 4800 + int(float(m-14)/12))) // 4 + (367 * (m - 2 - 12 * (int(float(m-14)/12)))) // 12 - (3 * ((y + 4900 + int(float(m-14)/12)) // 100)) // 4 + d - 32075</p>
</blockquote>
<hr />
<p><sup>1</sup>Usually integer division means you drop all the decimal digits... like 4 / 3 = 1.333 = 1. But in Python, integer division means &quot;floor&quot; division which means you go to the smaller integer. Again, example above, 4/3 = 1. Problem is with negative. -4/3 = -1.3333 (which lies between -1 and -2, hence the smaller is -2). They suppose to fix that with Python 3.... but my version 3 still does not work. The work around is convert to float then using int on the answer to drop the decimals. As for the script above, (m-14) always negative no matter what month m is; hence, problem arises.</p>

CC BY-SA 4.0
2020-07-17T05:30:57.037Z
You don't need the `float()` call in Python 3. And in Python 2 you can put `from __future__ import division` to get Python 3 float division behaviour with integer operands. Also, it would be neater & more efficient to do this calculation in two steps, rather than repeating the month reduction 3 times, eg `q = int((m - 14) / 12)`
PM 2Ring
CC BY-SA 4.0
2020-07-17T06:48:53.343Z
Mine is python 3.73.... and still integer division doesn't work...
Huy Pham
CC BY-SA 4.0
2020-07-17T08:49:13.550Z
I also get the same results as you in Python 3, but I don't understand what "the problem is with Python" really means. Can you add a little more explanation about what it is about the script in the question that is wrong and what exactly is fixed here? *Thanks!*
uhoh
CC BY-SA 4.0
2020-07-17T12:40:59.920Z
Usually integer division means you drop all the decimal digits... like 4 / 3 = 1.333 = 1. But in Python, integer division means "floor" division which means you go to the smaller integer. Again, example above, 4/3 = 1. Problem is with negative. -4/3 = -1.3333 (which lies between -1 and -2, hence the smaller is -2). They suppose to fix that with Python 3.... but my version 3 still does not work. The work around is convert to float then using int on the answer to drop the decimals. As for the script above, (m-14) always negative no matter what month m is; hence, problem arises.
Huy Pham
CC BY-SA 4.0
2020-07-18T11:25:03.543Z
@HuyPham -- Re "*They suppose to fix that with Python 3*" Fix what? Python3 was introduced a decade before Guido van Rossum stepped down as the Python BDFL. From Van Rossum's perspective, python did integer division correctly from day one; there was nothing to fix. He viewed the Fortran implementation of integer division as faulty, and that included the C family of languages that followed the Fortran implementation.
David Hammen
CC BY-SA 4.0
2020-07-18T11:46:51.947Z
Any consistent implementation of integer division and modulus will have `(a//b)*b + a%b == a`. Algol was inconsistent in this regard, as are some languages (e.g., Pascal, Ada) that derive from Algol. Fortran is consistent, as are languages that follow the Fortran practice (C, C++, C#, Java, ...). Fortran defines modulus such that `a%b` has the same sign as `a`. This is not the only choice. Python, along with several other languages, defines modulus such that `a%b` has the same sign as `b`. There are many arguments for why the route taken by Python is better than the route taken by Fortran.
David Hammen
CC BY-SA 4.0
2020-07-17T05:10:47.173Z
2020-07-18T03:26:09.250Z
2020-07-18T03:26:09.250Z
Huy Pham
<p>Adding to the answers above:
One of the problems here is that Julian Day Numbers start at noon of a particular Gregorian Date.  For the dates under consideration</p>
<ul>
<li>January 31, 2010 starts on JDN 2455227.5</li>
<li>February 1, 2010 starts on JDN 2455228.5</li>
</ul>
<p>You mentioned needing a reliable source for date algorithms.  I recommend <a href="https://www.researchgate.net/publication/316558298_Date_Algorithms" rel="nofollow noreferrer">https://www.researchgate.net/publication/316558298_Date_Algorithms</a> (an earlier version is archived at <a href="https://web.archive.org/web/20140902005628/http://mysite.verizon.net/aesir_research/date/date0.htm" rel="nofollow noreferrer">https://web.archive.org/web/20090405221644/http:/mysite.verizon.net:80/aesir_research/date/date0.htm</a>) which is specifically designed to help programmers write fast date algorithms.  It includes specific dates needed to check your program, discusses integer vs. float, word length, and other issues.  The document also gives proofs for variations of all the algorithms.</p>

CC BY-SA 4.0
2020-07-17T19:49:41.697Z
2020-07-17T19:49:41.697Z
Peter Baum
<p>The formula in the wikipedia article explicitly uses integer division with round toward zero. Python's integer division uses round toward negative infinity (i.e., floor).</p>
<p>The wikipedia article formula repeatedly uses <code>(m-14)/12</code>. This evaluates to -1 for months 1 and 2 (January and February), zero otherwise. You can use the wikipedia article formula in python3 if you change every instance of <code>(m-14)/12</code> in the wikipedia article formula to any of the following:</p>
<ul>
<li><code>int((m-14)/12)</code><br>The single <code>/</code> performs floating point division. Python's built-in <code>int</code> function rounds toward zero.</li>
<li><code>((m+9)//12-1)</code><br>The inner <code>(m+9)//12)</code> evaluates to 0 for January and February (m=1 and 2), 1 for all later months.</li>
<li><code>(-1 if m&lt;3 else 0)</code><br>While more verbose, this does a better job of conveying the intent of the wikipedia article's (m-14)/12.</li>
</ul>

CC BY-SA 4.0
2020-07-17T12:44:57.213Z
2020-07-17T12:50:10.630Z
2020-07-17T12:50:10.630Z
David Hammen
<p>I'm trying to calculate the Julian Day, given a UTC year, month and date in the Gregorian calendar.  I tried using the formula on <a href="https://en.wikipedia.org/wiki/Julian_day#Converting_Gregorian_calendar_date_to_Julian_Day_Number" rel="noreferrer">Wikipedia</a>, but that doesn't work.  Consider 2010-01-31 and 2010-02-01.  These dates are exactly one day apart, but their JDNs, according to the formula on Wikipedia, are 2455230 and 2455229, respectively.</p>
<p>In fact, it seems that this issue appears at the beginning and end of February of every year.  I wrote a Python script to go through every day from 2010-2020, and these are all similar discrepancies:</p>
<pre><code>ERROR: 2010-01-31 00:00:00 (2455230) vs 2010-02-01 00:00:00 (2455229)
ERROR: 2010-02-28 00:00:00 (2455256) vs 2010-03-01 00:00:00 (2455259)
ERROR: 2011-01-31 00:00:00 (2455595) vs 2011-02-01 00:00:00 (2455594)
ERROR: 2011-02-28 00:00:00 (2455621) vs 2011-03-01 00:00:00 (2455624)
ERROR: 2012-01-31 00:00:00 (2455960) vs 2012-02-01 00:00:00 (2455959)
ERROR: 2012-02-29 00:00:00 (2455987) vs 2012-03-01 00:00:00 (2455989)
ERROR: 2013-01-31 00:00:00 (2456325) vs 2013-02-01 00:00:00 (2456325)
ERROR: 2013-02-28 00:00:00 (2456352) vs 2013-03-01 00:00:00 (2456355)
ERROR: 2014-01-31 00:00:00 (2456691) vs 2014-02-01 00:00:00 (2456690)
ERROR: 2014-02-28 00:00:00 (2456717) vs 2014-03-01 00:00:00 (2456720)
ERROR: 2015-01-31 00:00:00 (2457056) vs 2015-02-01 00:00:00 (2457055)
ERROR: 2015-02-28 00:00:00 (2457082) vs 2015-03-01 00:00:00 (2457085)
ERROR: 2016-01-31 00:00:00 (2457421) vs 2016-02-01 00:00:00 (2457420)
ERROR: 2016-02-29 00:00:00 (2457448) vs 2016-03-01 00:00:00 (2457450)
ERROR: 2017-01-31 00:00:00 (2457786) vs 2017-02-01 00:00:00 (2457786)
ERROR: 2017-02-28 00:00:00 (2457813) vs 2017-03-01 00:00:00 (2457816)
ERROR: 2018-01-31 00:00:00 (2458152) vs 2018-02-01 00:00:00 (2458151)
ERROR: 2018-02-28 00:00:00 (2458178) vs 2018-03-01 00:00:00 (2458181)
ERROR: 2019-01-31 00:00:00 (2458517) vs 2019-02-01 00:00:00 (2458516)
ERROR: 2019-02-28 00:00:00 (2458543) vs 2019-03-01 00:00:00 (2458546)
</code></pre>
<p>The JDNs also do not match those on <a href="https://core2.gsfc.nasa.gov/time/julian.html" rel="noreferrer">NASA's calculator</a>, as it gives 2010-01-31 to be JD 2455228.</p>
<p>Since Wikipedia isn't always the most reliable resource, I scoured the internet for another website with a formula, and all I found was <a href="https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html" rel="noreferrer">this page</a>, which gives me the same issue, with a slightly different, step-by-step formula.</p>
<p>Am I doing something wrong?  I'm sorry if I am posting this in the wrong community, if there is a better place please let me know.</p>
<p>The code I used to get the list above is below, with the Wikipedia algorithm:</p>
<pre><code>import datetime

prev_d = None
prev = 0

def calc(_d):
    global prev_d
    global prev

    y = _d.year
    m = _d.month
    d = _d.day

    # Formula from Wikipedia
    jd = ((1461 * (y + 4800 + (m - 14) // 12)) // 4 + (367 * (m - 2 - 12 * ((m - 14) // 12))) // 12 - (3 * ((y + 4900 + (m - 14) // 12) // 100)) // 4 + d - 32075)

    if jd - prev != 1:
        print(&quot;ERROR: {} ({}) vs {} ({})&quot;.format(prev_d, prev, _d, jd))

    prev = jd
    prev_d = _d

# Iterate day-by-day, starting 2010-01-01 UTC
for d in range(1262304000, 1262304000 + 60 * 60 * 24 * 365 * 10, 60 * 60 * 24):
    calc(datetime.datetime.utcfromtimestamp(d))
<span class="math-container">```</span>
</code></pre>

<time>
Julian Day Calculation
vcapra1
# Julian Day Calculation

(Asked by: username_0 on 2020-07-17)

I'm trying to calculate the Julian Day, given a UTC year, month and date in the Gregorian calendar.  I tried using the formula on Wikipedia, but that doesn't work.  Consider 2010-01-31 and 2010-02-01.  These dates are exactly one day apart, but their JDNs, according to the formula on Wikipedia, are 2455230 and 2455229, respectively.
In fact, it seems that this issue appears at the beginning and end of February of every year.  I wrote a Python script to go through every day from 2010-2020, and these are all similar discrepancies:
ERROR: 2010-01-31 00:00:00 (2455230) vs 2010-02-01 00:00:00 (2455229)
ERROR: 2010-02-28 00:00:00 (2455256) vs 2010-03-01 00:00:00 (2455259)
ERROR: 2011-01-31 00:00:00 (2455595) vs 2011-02-01 00:00:00 (2455594)
ERROR: 2011-02-28 00:00:00 (2455621) vs 2011-03-01 00:00:00 (2455624)
ERROR: 2012-01-31 00:00:00 (2455960) vs 2012-02-01 00:00:00 (2455959)
ERROR: 2012-02-29 00:00:00 (2455987) vs 2012-03-01 00:00:00 (2455989)
ERROR: 2013-01-31 00:00:00 (2456325) vs 2013-02-01 00:00:00 (2456325)
ERROR: 2013-02-28 00:00:00 (2456352) vs 2013-03-01 00:00:00 (2456355)
ERROR: 2014-01-31 00:00:00 (2456691) vs 2014-02-01 00:00:00 (2456690)
ERROR: 2014-02-28 00:00:00 (2456717) vs 2014-03-01 00:00:00 (2456720)
ERROR: 2015-01-31 00:00:00 (2457056) vs 2015-02-01 00:00:00 (2457055)
ERROR: 2015-02-28 00:00:00 (2457082) vs 2015-03-01 00:00:00 (2457085)
ERROR: 2016-01-31 00:00:00 (2457421) vs 2016-02-01 00:00:00 (2457420)
ERROR: 2016-02-29 00:00:00 (2457448) vs 2016-03-01 00:00:00 (2457450)
ERROR: 2017-01-31 00:00:00 (2457786) vs 2017-02-01 00:00:00 (2457786)
ERROR: 2017-02-28 00:00:00 (2457813) vs 2017-03-01 00:00:00 (2457816)
ERROR: 2018-01-31 00:00:00 (2458152) vs 2018-02-01 00:00:00 (2458151)
ERROR: 2018-02-28 00:00:00 (2458178) vs 2018-03-01 00:00:00 (2458181)
ERROR: 2019-01-31 00:00:00 (2458517) vs 2019-02-01 00:00:00 (2458516)
ERROR: 2019-02-28 00:00:00 (2458543) vs 2019-03-01 00:00:00 (2458546)

The JDNs also do not match those on NASA's calculator, as it gives 2010-01-31 to be JD 2455228.
Since Wikipedia isn't always the most reliable resource, I scoured the internet for another website with a formula, and all I found was this page, which gives me the same issue, with a slightly different, step-by-step formula.
Am I doing something wrong?  I'm sorry if I am posting this in the wrong community, if there is a better place please let me know.
The code I used to get the list above is below, with the Wikipedia algorithm:
import datetime

prev_d = None
prev = 0

def calc(_d):
    global prev_d
    global prev

    y = _d.year
    m = _d.month
    d = _d.day

    # Formula from Wikipedia
    jd = ((1461 * (y + 4800 + (m - 14) // 12)) // 4 + (367 * (m - 2 - 12 * ((m - 14) // 12))) // 12 - (3 * ((y + 4900 + (m - 14) // 12) // 100)) // 4 + d - 32075)

    if jd - prev != 1:
        print("ERROR: {} ({}) vs {} ({})".format(prev_d, prev, _d, jd))

    prev = jd
    prev_d = _d

# Iterate day-by-day, starting 2010-01-01 UTC
for d in range(1262304000, 1262304000 + 60 * 60 * 24 * 365 * 10, 60 * 60 * 24):
    calc(datetime.datetime.utcfromtimestamp(d))
```

**Tags:** time


---

## 3 answers

### Answer by username_4 on 2020-07-17. Score: 12 | Accepted answer

The formula in the wikipedia article explicitly uses integer division with round toward zero. Python's integer division uses round toward negative infinity (i.e., floor).

The wikipedia article formula repeatedly uses `(m-14)/12`. This evaluates to -1 for months 1 and 2 (January and February), zero otherwise. You can use the wikipedia article formula in python3 if you change every instance of `(m-14)/12` in the wikipedia article formula to any of the following:

* `int((m-14)/12)`  
  The single `/` performs floating point division. Python's built-in `int` function rounds toward zero.
* `((m+9)//12-1)`  
  The inner `(m+9)//12)` evaluates to 0 for January and February (m=1 and 2), 1 for all later months.
* `(-1 if m<3 else 0)`  
  While more verbose, this does a better job of conveying the intent of the wikipedia article's (m-14)/12.


---

### Answer by username_1 on 2020-07-17. Score: 7

The formula is correct. However, the "problem" is with Python1. <https://stackoverflow.com/questions/5535206/negative-integer-division-surprising-result>.

Here is the fix to the formula:

> jd = (1461 \* (y + 4800 + int(float(m-14)/12))) // 4 + (367 \* (m - 2 - 12 \* (int(float(m-14)/12)))) // 12 - (3 \* ((y + 4900 + int(float(m-14)/12)) // 100)) // 4 + d - 32075

---

1Usually integer division means you drop all the decimal digits... like 4 / 3 = 1.333 = 1. But in Python, integer division means "floor" division which means you go to the smaller integer. Again, example above, 4/3 = 1. Problem is with negative. -4/3 = -1.3333 (which lies between -1 and -2, hence the smaller is -2). They suppose to fix that with Python 3.... but my version 3 still does not work. The work around is convert to float then using int on the answer to drop the decimals. As for the script above, (m-14) always negative no matter what month m is; hence, problem arises.

> **Comments:**
> **username_2**: You don't need the `float()` call in Python 3. And in Python 2 you can put `from __future__ import division` to get Python 3 float division behaviour with integer operands. Also, it would be neater & more efficient to do this calculation in two steps, rather than repeating the month reduction 3 times, eg `q = int((m - 14) / 12)`  
> **username_1**: Mine is python 3.73.... and still integer division doesn't work...  
> **username_3**: I also get the same results as you in Python 3, but I don't understand what "the problem is with Python" really means. Can you add a little more explanation about what it is about the script in the question that is wrong and what exactly is fixed here? *Thanks!*  
> **username_1**: Usually integer division means you drop all the decimal digits... like 4 / 3 = 1.333 = 1. But in Python, integer division means "floor" division which means you go to the smaller integer. Again, example above, 4/3 = 1. Problem is with negative. -4/3 = -1.3333 (which lies between -1 and -2, hence the smaller is -2). They suppose to fix that with Python 3.... but my version 3 still does not work. The work around is convert to float then using int on the answer to drop the decimals. As for the script above, (m-14) always negative no matter what month m is; hence, problem arises.  
> **username_4**: @HuyPham -- Re "*They suppose to fix that with Python 3*" Fix what? Python3 was introduced a decade before Guido van Rossum stepped down as the Python BDFL. From Van Rossum's perspective, python did integer division correctly from day one; there was nothing to fix. He viewed the Fortran implementation of integer division as faulty, and that included the C family of languages that followed the Fortran implementation.  
> **username_4**: Any consistent implementation of integer division and modulus will have `(a//b)*b + a%b == a`. Algol was inconsistent in this regard, as are some languages (e.g., Pascal, Ada) that derive from Algol. Fortran is consistent, as are languages that follow the Fortran practice (C, C++, C#, Java, ...). Fortran defines modulus such that `a%b` has the same sign as `a`. This is not the only choice. Python, along with several other languages, defines modulus such that `a%b` has the same sign as `b`. There are many arguments for why the route taken by Python is better than the route taken by Fortran.  

---

### Answer by username_5 on 2020-07-17. Score: 4

Adding to the answers above:
One of the problems here is that Julian Day Numbers start at noon of a particular Gregorian Date. For the dates under consideration

* January 31, 2010 starts on JDN 2455227.5
* February 1, 2010 starts on JDN 2455228.5

You mentioned needing a reliable source for date algorithms. I recommend <https://www.researchgate.net/publication/316558298_Date_Algorithms> (an earlier version is archived at [https://web.archive.org/web/20090405221644/http:/mysite.verizon.net:80/aesir\_research/date/date0.htm](https://web.archive.org/web/20140902005628/http://mysite.verizon.net/aesir_research/date/date0.htm)) which is specifically designed to help programmers write fast date algorithms. It includes specific dates needed to check your program, discusses integer vs. float, word length, and other issues. The document also gives proofs for variations of all the algorithms.


---

