mirror of https://gitee.com/bigwinds/arangodb
Alternative DATE_FORMAT() implementation
This commit is contained in:
parent
80617c8716
commit
f13c2f1fce
|
@ -310,36 +310,48 @@ FOR user IN users
|
|||
|
||||
- *DATE_FORMAT(date, format)*: Format a date according to the given format string.
|
||||
It supports the following placeholders (case-insensitive):
|
||||
- %t: timestamp
|
||||
- %t: timestamp, in milliseconds since midnight 1970-01-01
|
||||
- %z: ISO date (0000-00-00T00:00:00.000Z)
|
||||
- %w: day of week (0..6)
|
||||
- %y: year (0000..9999)
|
||||
- %m: month (01..12)
|
||||
- %d: day (01..31)
|
||||
- %h: hour (00..23)
|
||||
- %i: minute (00..59)
|
||||
- %s: second (00..59)
|
||||
- %f: millisecond (000..999)
|
||||
- %x: day of year (001..366)
|
||||
- %k: ISO week date (01..53)
|
||||
- %y: year (0..9999)
|
||||
- %yy: year (00..99), abbreviated (last two digits)
|
||||
- %yyyy: year (0000..9999), padded to length of 4
|
||||
- %yyyyyy: year (-009999 .. +009999), with sign prefix and padded to length of 6
|
||||
- %m: month (1..12)
|
||||
- %mm: month (01..12), padded to length of 2
|
||||
- %d: day (1..31)
|
||||
- %dd: day (01..31), padded to length of 2
|
||||
- %h: hour (0..23)
|
||||
- %hh: hour (00..23), padded to length of 2
|
||||
- %i: minute (0..59)
|
||||
- %ii: minute (00..59), padded to length of 2
|
||||
- %s: second (0..59)
|
||||
- %ss: second (00..59), padded to length of 2
|
||||
- %f: millisecond (0..999)
|
||||
- %fff: millisecond (000..999), padded to length of 3
|
||||
- %x: day of year (1..366)
|
||||
- %xxx: day of year (001..366), padded to length of 3
|
||||
- %k: ISO week date (1..53)
|
||||
- %kk: ISO week date (01..53), padded to length of 2
|
||||
- %l: leap year (0 or 1)
|
||||
- %q: quarter (1..4)
|
||||
- %a: days in month (28..31)
|
||||
- %n: English name of month (January..December)
|
||||
- %o: abbreviated English name of month (Jan..Dec)
|
||||
- %e: English name of weekday (Sunday..Saturday)
|
||||
- %g: abbreviated English name of weekday (Sun..Sat)
|
||||
- %mmm: abbreviated English name of month (Jan..Dec)
|
||||
- %mmmm: English name of month (January..December)
|
||||
- %www: abbreviated English name of weekday (Sun..Sat)
|
||||
- %wwww: English name of weekday (Sunday..Saturday)
|
||||
- %&: special escape sequence for rare occasions
|
||||
- %%: literal %
|
||||
- %: ignored
|
||||
|
||||
Month, day, hour, minute, second, ISO week date and days in month are zero-padded
|
||||
to 2 characters, millisecond and day of year to 3 characters. Year is zero-padded
|
||||
to 4 characters, or 6 if year is negative (it will be 7 chars long however
|
||||
because of the leading minus character, and is not suitable for comparisons
|
||||
with 4-chars positive years). Timestamp is not padded.
|
||||
`%yyyy` does not enforce a length of 4 for years before 0 and past 9999.
|
||||
The same format as for `%yyyyyy` will used instead. `%yy` preserves the
|
||||
sign for negative years and thus returns 3 characters in total.
|
||||
|
||||
Single `%` characters will appear as percent characters, as long as they aren't
|
||||
followed by a valid placeholder letter. `%%` is only required to output a
|
||||
placeholder literally.
|
||||
Single `%` characters will be ignored. Use `%%` for a literal `%`. To resolve
|
||||
ambiguities like in `%mmonth` (unpadded month number + the string "month")
|
||||
between `%mm` + "onth" and `%m` + "month", use the escape sequence `%&`:
|
||||
`%m%&month`.
|
||||
|
||||
Note that this is a rather costly operation and may not be suitable for large
|
||||
datasets (like over 1 million dates). If possible, avoid formatting dates on
|
||||
|
@ -351,10 +363,11 @@ FOR user IN users
|
|||
Examples:
|
||||
|
||||
```js
|
||||
DATE_FORMAT(DATE_NOW(), "%q/%y") // quarter and year (e.g. "3/2015")
|
||||
DATE_FORMAT(DATE_NOW(), "%d.%m.%y %h:%i:%s") // e.g. "18.09.2015 15:30:49"
|
||||
DATE_FORMAT(DATE_NOW(), "%q/%yyyy") // quarter and year (e.g. "3/2015")
|
||||
DATE_FORMAT(DATE_NOW(), "%dd.%mm.%yyyy %hh:%ii:%ss.%fff") // e.g. "18.09.2015 15:30:49.374"
|
||||
DATE_FORMAT("1969", "Summer of '%yy") // "Summer of '69"
|
||||
DATE_FORMAT("2016", "%%l = %l") // "%l = 1" (2016 is a leap year)
|
||||
DATE_FORMAT("2016-03-01", "% %x %") // "% 063 %"
|
||||
DATE_FORMAT("2016-03-01", "%xxx%") // "063", trailing % ignored
|
||||
```
|
||||
|
||||
!SECTION Working with dates and indices
|
||||
|
@ -390,6 +403,8 @@ date according to the Gregorian calendar system, even if inappropriate. That
|
|||
does not constitute a problem, unless you deal with dates prior to 1583 and
|
||||
especially years before Christ. The standard allows negative years, but requires
|
||||
special treatment of positive years too, if negative years are used (e.g.
|
||||
`+002015-05-15` and `-000753-01-01`). This is rarely used however, and thus not
|
||||
handled by AQL. Leap seconds are also ignored, just as they are in JavaScript as per
|
||||
`+002015-05-15` and `-000753-01-01`). This is rarely used however, and AQL does
|
||||
not use the 7-character version for years between 0 and 9999 in ISO strings.
|
||||
Keep in mind that they can't be properly compared to dates outside that range.
|
||||
Leap seconds are ignored, just as they are in JavaScript as per
|
||||
[ECMAScript Language Specifications](http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.1).
|
||||
|
|
|
@ -167,26 +167,39 @@ The following extra date functions are available from 2.7 on:
|
|||
|
||||
* `DATE_FORMAT(date, format)`: Format a date according to the given format string.
|
||||
It supports the following placeholders (case-insensitive):
|
||||
- %t: timestamp
|
||||
- %t: timestamp, in milliseconds since midnight 1970-01-01
|
||||
- %z: ISO date (0000-00-00T00:00:00.000Z)
|
||||
- %w: day of week (0..6)
|
||||
- %y: year (0000..9999)
|
||||
- %m: month (01..12)
|
||||
- %d: day (01..31)
|
||||
- %h: hour (00..23)
|
||||
- %i: minute (00..59)
|
||||
- %s: second (00..59)
|
||||
- %f: millisecond (000..999)
|
||||
- %x: day of year (001..366)
|
||||
- %k: ISO week date (01..53)
|
||||
- %y: year (0..9999)
|
||||
- %yy: year (00..99), abbreviated (last two digits)
|
||||
- %yyyy: year (0000..9999), padded to length of 4
|
||||
- %yyyyyy: year (-009999 .. +009999), with sign prefix and padded to length of 6
|
||||
- %m: month (1..12)
|
||||
- %mm: month (01..12), padded to length of 2
|
||||
- %d: day (1..31)
|
||||
- %dd: day (01..31), padded to length of 2
|
||||
- %h: hour (0..23)
|
||||
- %hh: hour (00..23), padded to length of 2
|
||||
- %i: minute (0..59)
|
||||
- %ii: minute (00..59), padded to length of 2
|
||||
- %s: second (0..59)
|
||||
- %ss: second (00..59), padded to length of 2
|
||||
- %f: millisecond (0..999)
|
||||
- %fff: millisecond (000..999), padded to length of 3
|
||||
- %x: day of year (1..366)
|
||||
- %xxx: day of year (001..366), padded to length of 3
|
||||
- %k: ISO week date (1..53)
|
||||
- %kk: ISO week date (01..53), padded to length of 2
|
||||
- %l: leap year (0 or 1)
|
||||
- %q: quarter (1..4)
|
||||
- %a: days in month (28..31)
|
||||
- %n: English name of month (January..December)
|
||||
- %o: abbreviated English name of month (Jan..Dec)
|
||||
- %e: English name of weekday (Sunday..Saturday)
|
||||
- %g: abbreviated English name of weekday (Sun..Sat)
|
||||
- %mmm: abbreviated English name of month (Jan..Dec)
|
||||
- %mmmm: English name of month (January..December)
|
||||
- %www: abbreviated English name of weekday (Sun..Sat)
|
||||
- %wwww: English name of weekday (Sunday..Saturday)
|
||||
- %&: special escape sequence for rare occasions
|
||||
- %%: literal %
|
||||
- %: ignored
|
||||
|
||||
|
||||
!SUBSECTION RETURN DISTINCT
|
||||
|
|
|
@ -5112,7 +5112,7 @@ function AQL_DATE_COMPARE (value1, value2, unitRangeStart, unitRangeEnd) {
|
|||
// birthday checking however. Probably best to leave compensation up to user query.
|
||||
var date1 = MAKE_DATE([ value1 ], "DATE_COMPARE");
|
||||
var date2 = MAKE_DATE([ value2 ], "DATE_COMPARE");
|
||||
if (isNaN(date1) || isNaN(date2)) {
|
||||
if (TYPEWEIGHT(date1) === TYPEWEIGHT_NULL || TYPEWEIGHT(date2) === TYPEWEIGHT_NULL) {
|
||||
return null;
|
||||
}
|
||||
if (unitRangeEnd === undefined) {
|
||||
|
@ -5124,10 +5124,12 @@ function AQL_DATE_COMPARE (value1, value2, unitRangeStart, unitRangeEnd) {
|
|||
WARN("DATE_COMPARE", INTERNAL.errors.ERROR_QUERY_INVALID_DATE_VALUE);
|
||||
return null;
|
||||
}
|
||||
if (date1.getUTCFullYear() < 0 && start !== 0) {
|
||||
var yr1 = date1.getUTCFullYear();
|
||||
if ((yr1 < 0 || yr1 > 9999) && start !== 0) {
|
||||
start += 3;
|
||||
}
|
||||
if (date2.getUTCFullYear() < 0) {
|
||||
var yr2 = date2.getUTCFullYear();
|
||||
if (yr2 < 0 || yr2 > 9999) {
|
||||
end += 3;
|
||||
}
|
||||
var substr1 = date1.toISOString().slice(start, end);
|
||||
|
@ -5151,7 +5153,7 @@ function AQL_DATE_COMPARE (value1, value2, unitRangeStart, unitRangeEnd) {
|
|||
// special escape sequence first, rest ordered by length
|
||||
var dateMapRegExp = [
|
||||
"%&", "%yyyyyy", "%yyyy", "%mmmm", "%wwww", "%mmm", "%www", "%fff", "%xxx",
|
||||
"%mm", "%dd", "%hh", "%ii", "%ss", "%kk", "%t", "%z", "%w", "%y", "%m",
|
||||
"%yy", "%mm", "%dd", "%hh", "%ii", "%ss", "%kk", "%t", "%z", "%w", "%y", "%m",
|
||||
"%d", "%h", "%i", "%s", "%f", "%x", "%k", "%l", "%q", "%a", "%%", "%"
|
||||
].join("|");
|
||||
|
||||
|
@ -5163,27 +5165,46 @@ function AQL_DATE_FORMAT (value, format) {
|
|||
var yr = date.getUTCFullYear();
|
||||
var offset = yr < 0 || yr > 9999 ? 3 : 0;
|
||||
var dateMap = {
|
||||
"%t": function(){ return date.getTime(); },
|
||||
"%z": function(){ return dateStr; },
|
||||
"%w": function(){ return AQL_DATE_DAYOFWEEK(dateStr); },
|
||||
"%y": function(){ return dateStr.slice(0, 4 + offset); },
|
||||
"%m": function(){ return dateStr.slice(5 + offset, 7 + offset); },
|
||||
"%d": function(){ return dateStr.slice(8 + offset, 10 + offset); },
|
||||
"%h": function(){ return dateStr.slice(11 + offset, 13 + offset); },
|
||||
"%i": function(){ return dateStr.slice(14 + offset, 16 + offset); },
|
||||
"%s": function(){ return dateStr.slice(17 + offset, 19 + offset); },
|
||||
"%f": function(){ return dateStr.slice(20 + offset, 23 + offset); },
|
||||
"%x": function(){ return zeropad(AQL_DATE_DAYOFYEAR(dateStr), 3); },
|
||||
"%k": function(){ return zeropad(AQL_DATE_ISOWEEK(dateStr), 2); },
|
||||
"%l": function(){ return +AQL_DATE_LEAPYEAR(dateStr); },
|
||||
"%q": function(){ return AQL_DATE_QUARTER(dateStr); },
|
||||
"%a": function(){ return zeropad(AQL_DATE_DAYS_IN_MONTH(dateStr), 2); },
|
||||
"%n": function(){ return monthNames[date.getUTCMonth()]; },
|
||||
"%o": function(){ return monthNames[date.getUTCMonth()].substring(0, 3); },
|
||||
"%e": function(){ return weekdayNames[AQL_DATE_DAYOFWEEK(dateStr)]; },
|
||||
"%g": function(){ return weekdayNames[AQL_DATE_DAYOFWEEK(dateStr)].substring(0, 3); },
|
||||
"%%": function(){ return "%"; } // Allow for literal "%Y" using "%%Y"
|
||||
//"%": "" // Not reliable, because Object.keys() does not guarantee order
|
||||
"%t": function(){ return date.getTime() },
|
||||
"%z": function(){ return dateStr },
|
||||
"%w": function(){ return AQL_DATE_DAYOFWEEK(dateStr) },
|
||||
"%y": function(){ return date.getUTCFullYear() },
|
||||
// there's no really sensible way to handle negative years, but better not drop the sign
|
||||
"%yy": function(){ return (yr < 0 ? "-" : "") + dateStr.slice(2 + offset, 4 + offset) },
|
||||
// preserves full negative years (-000753 is not reduced to -753 or -0753)
|
||||
"%yyyy": function(){ return dateStr.slice(0, 4 + offset) },
|
||||
// zero-pad 4 digit years to length of 6 and add "+" prefix, keep negative as-is
|
||||
"%yyyyyy": function(){
|
||||
return (yr >= 0 && yr <= 9999)
|
||||
? "+" + zeropad(dateStr.slice(0, 4 + offset), 6)
|
||||
: dateStr.slice(0, 7)
|
||||
},
|
||||
"%m": function(){ return date.getUTCMonth() + 1 },
|
||||
"%mm": function(){ return dateStr.slice(5 + offset, 7 + offset) },
|
||||
"%d": function(){ return date.getUTCDate() },
|
||||
"%dd": function(){ return dateStr.slice(8 + offset, 10 + offset) },
|
||||
"%h": function(){ return date.getUTCHours() },
|
||||
"%hh": function(){ return dateStr.slice(11 + offset, 13 + offset) },
|
||||
"%i": function(){ return date.getUTCMinutes() },
|
||||
"%ii": function(){ return dateStr.slice(14 + offset, 16 + offset) },
|
||||
"%s": function(){ return date.getUTCSeconds() },
|
||||
"%ss": function(){ return dateStr.slice(17 + offset, 19 + offset) },
|
||||
"%f": function(){ return date.getUTCMilliseconds() },
|
||||
"%fff": function(){ return dateStr.slice(20 + offset, 23 + offset) },
|
||||
"%x": function(){ return AQL_DATE_DAYOFYEAR(dateStr) },
|
||||
"%xxx": function(){ return zeropad(AQL_DATE_DAYOFYEAR(dateStr), 3) },
|
||||
"%k": function(){ return AQL_DATE_ISOWEEK(dateStr) },
|
||||
"%kk": function(){ return zeropad(AQL_DATE_ISOWEEK(dateStr), 2) },
|
||||
"%l": function(){ return +AQL_DATE_LEAPYEAR(dateStr) },
|
||||
"%q": function(){ return AQL_DATE_QUARTER(dateStr) },
|
||||
"%a": function(){ return AQL_DATE_DAYS_IN_MONTH(dateStr) },
|
||||
"%mmm": function(){ return monthNames[date.getUTCMonth()].substring(0, 3) },
|
||||
"%mmmm": function(){ return monthNames[date.getUTCMonth()] },
|
||||
"%www": function(){ return weekdayNames[AQL_DATE_DAYOFWEEK(dateStr)].substring(0, 3) },
|
||||
"%wwww": function(){ return weekdayNames[AQL_DATE_DAYOFWEEK(dateStr)] },
|
||||
"%&": function(){ return "" }, // Allow for literal "m" after "%m" ("%mm" -> %m%&m)
|
||||
"%%": function(){ return "%" }, // Allow for literal "%y" using "%%y"
|
||||
"%": function(){ return "" }
|
||||
};
|
||||
var exp = new RegExp(dateMapRegExp, "gi");
|
||||
format = format.replace(exp, function(match){
|
||||
|
|
Loading…
Reference in New Issue