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

dlych pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 43966ea  [NO ISSUE][FUN] Improve quarter printing/parsing in date 
functions
43966ea is described below

commit 43966eab5f43398de5b93a9a959c16ad08742b6b
Author: Dmitry Lychagin <[email protected]>
AuthorDate: Tue Oct 5 10:49:27 2021 -0700

    [NO ISSUE][FUN] Improve quarter printing/parsing in date functions
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Add 'QQ' format to print_date/print_datetime()
      functions to print quarter of year with leading 0
    - Add 'Q' and 'QQ' formats to parse_date/parse_datetime()
      functions to parse quarter of year
    - Add testcases and update documentation
    
    Change-Id: Ie71a1f59ab96ed0382255109d1f59bfa6e50ad82
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/13544
    Integration-Tests: Jenkins <[email protected]>
    Tested-by: Jenkins <[email protected]>
    Reviewed-by: Ian Maxon <[email protected]>
---
 .../parse_03.6.query.sqlpp}                        | 14 +++---
 .../temporal/print_01/print_01.1.query.sqlpp       |  7 +--
 .../results/temporal/parse_03/parse_03.6.adm       |  4 ++
 .../results/temporal/print_01/print_01.1.adm       |  8 +--
 .../src/main/markdown/builtins/7_temporal.md       |  4 ++
 .../om/base/temporal/DateTimeFormatUtils.java      | 58 +++++++++++++++++++++-
 6 files changed, 80 insertions(+), 15 deletions(-)

diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/parse_03/parse_03.6.query.sqlpp
similarity index 80%
copy from 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
copy to 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/parse_03/parse_03.6.query.sqlpp
index ae1db50..522a8dc 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/parse_03/parse_03.6.query.sqlpp
@@ -17,10 +17,12 @@
  * under the License.
  */
 
-/* Print quarter */
+/*
+ * Parse year and quarter
+ */
 
-select p, count(*) cnt
-from range(0, 365) r
-let d = 
date_from_unix_time_in_days(unix_time_from_date_in_days(date("2020-01-01")) + 
r),
-  p = print_date(d, "YYYY-Q")
-group by p;
+select r, d, dt
+from range(1, 4) r
+let d = parse_date("2020-" || string(r) , "YYYY-Q"),
+    dt = parse_datetime("2021-0" || string(r), "YYYY-QQ")
+order by r;
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
index ae1db50..1579c95 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/print_01/print_01.1.query.sqlpp
@@ -19,8 +19,9 @@
 
 /* Print quarter */
 
-select p, count(*) cnt
+select p1, p2, count(*) cnt
 from range(0, 365) r
 let d = 
date_from_unix_time_in_days(unix_time_from_date_in_days(date("2020-01-01")) + 
r),
-  p = print_date(d, "YYYY-Q")
-group by p;
+  p1 = print_date(d, "YYYY-Q"),
+  p2 = print_date(d, "YYYY-QQ")
+group by p1, p2;
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/parse_03/parse_03.6.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/parse_03/parse_03.6.adm
new file mode 100644
index 0000000..5a7c485
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/parse_03/parse_03.6.adm
@@ -0,0 +1,4 @@
+{ "r": 1, "d": date("2020-01-01"), "dt": datetime("2021-01-01T00:00:00.000") }
+{ "r": 2, "d": date("2020-04-01"), "dt": datetime("2021-04-01T00:00:00.000") }
+{ "r": 3, "d": date("2020-07-01"), "dt": datetime("2021-07-01T00:00:00.000") }
+{ "r": 4, "d": date("2020-10-01"), "dt": datetime("2021-10-01T00:00:00.000") }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/print_01/print_01.1.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/print_01/print_01.1.adm
index facff48..83e0610 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/print_01/print_01.1.adm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/print_01/print_01.1.adm
@@ -1,4 +1,4 @@
-{ "p": "2020-1", "cnt": 91 }
-{ "p": "2020-2", "cnt": 91 }
-{ "p": "2020-3", "cnt": 92 }
-{ "p": "2020-4", "cnt": 92 }
\ No newline at end of file
+{ "p1": "2020-1", "p2": "2020-01", "cnt": 91 }
+{ "p1": "2020-2", "p2": "2020-02", "cnt": 91 }
+{ "p1": "2020-3", "p2": "2020-03", "cnt": 92 }
+{ "p1": "2020-4", "p2": "2020-04", "cnt": 92 }
\ No newline at end of file
diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md 
b/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
index 5c11b46..a1cdda2 100644
--- a/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
+++ b/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
@@ -648,6 +648,8 @@ 
parse_date/parse_time/parse_datetime(date,formatting_expression)
        * `a` am/pm
        * `z` timezone (parsed and ignored)
        * `Y` year
+       * `Q` quarter of year (1-4)
+       * `QQ` quarter of year (01-04)
        * `M` month
        * `D` day
        * `EEE` weekday (abbreviated name, parsed and ignored)
@@ -685,6 +687,8 @@ 
parse_date/parse_time/parse_datetime(date,formatting_expression)
        * `n` (or `S`) milliseconds
        * `a` am/pm
        * `Y` year
+       * `Q` quarter of year (1-4)
+       * `QQ` quarter of year (01-04)
        * `M` month
        * `MMM` month (abbreviated name)
        * `MMMM` month (full name)
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java
index 73ba3d8..db771f9 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java
@@ -37,7 +37,7 @@ import org.apache.hyracks.api.exceptions.HyracksDataException;
  * <p/>
  * - <b>Y</b>: a digit for the year field. At most 4 year format characters 
are allowed for a valid format string.<br/>
  * - <b>M</b>: a digit or character for the month field. At most 3 month 
format characters are allowed for a valid format string. When three month 
format characters are used, the shorten month names (like JAN, FEB etc.) are 
expected in the string to be parsed. Otherwise digits are expected.<br/>
- * - <b>Q</b>: (print-only) a digit for the quarter field (1-4). At most 1 
format character is allowed.<br/>
+ * - <b>Q</b>: a digit for the quarter field (1-4). At most 2 format 
characters are allowed.<br/>
  * - <b>D</b>: a digit for the day field. At most 2 day format characters are 
allowed.<br/>
  * - <b>h</b>: a digit for the hour field. At most 2 hour format characters 
are allowed.<br/>
  * - <b>m</b>: a digit for the minute field. At most 2 minute format 
characters are allowed.<br/>
@@ -100,7 +100,7 @@ public class DateTimeFormatUtils {
     private static final char WEEKDAY_CHAR = 'E';
 
     private static final int MAX_YEAR_CHARS = 4;
-    private static final int MAX_QUARTER_CHARS = 1;
+    private static final int MAX_QUARTER_CHARS = 2;
     private static final int MAX_MONTH_CHARS = 4;
     private static final int MAX_DAY_CHARS_PARSE = 2;
     private static final int MAX_DAY_CHARS_PRINT = 3; // + DDD = Day of Year
@@ -341,6 +341,13 @@ public class DateTimeFormatUtils {
                     formatPointer += pointerMove;
                     formatCharCopies += pointerMove;
                     break;
+                case QUARTER_CHAR:
+                    processState = DateTimeProcessState.QUARTER;
+                    pointerMove = parseFormatField(format, formatStart, 
formatLength, formatPointer, QUARTER_CHAR,
+                            MAX_QUARTER_CHARS);
+                    formatPointer += pointerMove;
+                    formatCharCopies += pointerMove;
+                    break;
                 case MONTH_CHAR:
                     processState = DateTimeProcessState.MONTH;
                     pointerMove = parseFormatField(format, formatStart, 
formatLength, formatPointer, MONTH_CHAR,
@@ -452,6 +459,7 @@ public class DateTimeFormatUtils {
 
             switch (processState) {
                 case YEAR:
+                case QUARTER:
                 case MONTH:
                 case DAY:
                     if (parseMode == DateTimeParseMode.TIME_ONLY) {
@@ -529,6 +537,52 @@ public class DateTimeFormatUtils {
                         day = parsedValue;
                     }
                     break;
+                case QUARTER:
+                    // the month is in the number format
+                    parsedValue = 0;
+                    int processedQuarterFieldsCount = 0;
+                    for (int i = 0; i < formatCharCopies; i++) {
+                        if (data[dataStart + dataStringPointer] < '0' || 
data[dataStart + dataStringPointer] > '9') {
+                            if (raiseParseDataError) {
+                                throw new 
AsterixTemporalTypeParseException("Unexpected char for quarter field at "
+                                        + (dataStart + dataStringPointer) + ": 
" + data[dataStart + dataStringPointer]);
+                            } else {
+                                return false;
+                            }
+                        }
+                        parsedValue = parsedValue * 10 + (data[dataStart + 
dataStringPointer] - '0');
+                        dataStringPointer++;
+                        if (processedQuarterFieldsCount++ > 2) {
+                            if (raiseParseDataError) {
+                                throw new 
AsterixTemporalTypeParseException("Unexpected char for quarter field at "
+                                        + (dataStart + dataStringPointer) + ": 
" + data[dataStart + dataStringPointer]);
+                            } else {
+                                return false;
+                            }
+                        }
+                    }
+                    // if there are more than 2 digits for the quarter string
+                    while (processedQuarterFieldsCount < 2 && 
dataStringPointer < dataLength
+                            && data[dataStart + dataStringPointer] >= '0'
+                            && data[dataStart + dataStringPointer] <= '9') {
+                        parsedValue = parsedValue * 10 + (data[dataStart + 
dataStringPointer] - '0');
+                        dataStringPointer++;
+                        processedQuarterFieldsCount++;
+                    }
+                    if (parsedValue == 0) {
+                        if (raiseParseDataError) {
+                            throw new AsterixTemporalTypeParseException(
+                                    "Incorrect quarter value at " + (dataStart 
+ dataStringPointer));
+                        } else {
+                            return false;
+                        }
+                    }
+                    month = (parsedValue - 1) * 3 + 1;
+                    // Allow day to be missing if we parsed quarter
+                    if (day == 0) {
+                        day = 
GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
+                    }
+                    break;
                 case MONTH:
                     if (formatCharCopies >= 3) {
                         // the month is in the text format

Reply via email to