This is an automated email from the ASF dual-hosted git repository.

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite-avatica.git


The following commit(s) were added to refs/heads/master by this push:
     new f93e72b  [CALCITE-3881] DateTimeUtils.addMonths yields incorrect 
results (Zhenghua Gao)
f93e72b is described below

commit f93e72b8f93318ee2b1c78e772a75f5ecef97b2a
Author: Zhenghua Gao <[email protected]>
AuthorDate: Fri Mar 27 20:11:25 2020 +0800

    [CALCITE-3881] DateTimeUtils.addMonths yields incorrect results (Zhenghua 
Gao)
    
    Close apache/calcite-avatica#121
---
 .../apache/calcite/avatica/util/DateTimeUtils.java | 25 +++++++++++++++++++---
 .../calcite/avatica/util/DateTimeUtilsTest.java    |  2 ++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java 
b/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java
index 1243ef4..7e5e109 100644
--- a/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java
+++ b/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java
@@ -965,6 +965,19 @@ public class DateTimeUtils {
     return julian - EPOCH_JULIAN;
   }
 
+  /** Calculates the Julian Day Number for any valid date in the Gregorian
+   * calendar.
+   *
+   * <p>If date is invalid, result is unspecified.
+   *
+   * <p>See an
+   * <a 
href="http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/jdn-explanation.html";>
+   * explanation</a> of this algorithm.
+   *
+   * @param year Year (e.g. 2020 means 2020 CE, 1 means 1 CE, 0 means 1 BCE
+   *   because there is no 0 CE, -1 means 2 BCE, etc.)
+   * @param month Month (between 1 and 12 inclusive, 1 meaning January)
+   * @param day Day of month (between 1 and 31 inclusive) */
   public static int ymdToJulian(int year, int month, int day) {
     int a = (14 - month) / 12;
     int y = year + 4800 - a;
@@ -1003,9 +1016,15 @@ public class DateTimeUtils {
     int y0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.YEAR, date);
     int m0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.MONTH, date);
     int d0 = (int) DateTimeUtils.unixDateExtract(TimeUnitRange.DAY, date);
-    int y = m / 12;
-    y0 += y;
-    m0 += m - y * 12;
+    m0 += m;
+    int deltaYear = (int) DateTimeUtils.floorDiv(m0, 12);
+    y0 += deltaYear;
+    m0 = (int) DateTimeUtils.floorMod(m0, 12);
+    if (m0 == 0) {
+      y0 -= 1;
+      m0 += 12;
+    }
+
     int last = lastDay(y0, m0);
     if (d0 > last) {
       d0 = 1;
diff --git 
a/core/src/test/java/org/apache/calcite/avatica/util/DateTimeUtilsTest.java 
b/core/src/test/java/org/apache/calcite/avatica/util/DateTimeUtilsTest.java
index 8cf32c4..6a33adf 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/DateTimeUtilsTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/DateTimeUtilsTest.java
@@ -820,6 +820,8 @@ public class DateTimeUtilsTest {
     checkAddMonths(2016, 3, 31, 2016, 3, 1, -1);
     checkAddMonths(2016, 3, 31, 2116, 3, 31, 1200);
     checkAddMonths(2016, 2, 28, 2116, 2, 28, 1200);
+    checkAddMonths(2019, 9, 1, 2020, 3, 1, 6);
+    checkAddMonths(2019, 9, 1, 2016, 8, 1, -37);
   }
 
   private void checkAddMonths(int y0, int m0, int d0, int y1, int m1, int d1,

Reply via email to