mirror of https://github.com/mongodb/mongo
298 lines
11 KiB
JavaScript
298 lines
11 KiB
JavaScript
/**
|
|
* Tests for $dateAdd and $dateSubtract expressions.
|
|
* @tags: [
|
|
* ]
|
|
*/
|
|
|
|
import "jstests/libs/query/sbe_assert_error_override.js";
|
|
|
|
import {executeAggregationTestCase} from "jstests/libs/query/aggregation_pipeline_utils.js";
|
|
|
|
// TODO(SERVER-103530) : Remove multiversion check when 9.0 becomes last-lts
|
|
const isMultiversion =
|
|
Boolean(jsTest.options().useRandomBinVersionsWithinReplicaSet) || Boolean(TestData.multiversionBinVersion);
|
|
|
|
const coll = db.date_add_subtract;
|
|
coll.drop();
|
|
|
|
function runAndAssert(date, result) {
|
|
runTest({dateArithmeticsSpec: date, expectedResult: result});
|
|
}
|
|
|
|
function runAndAssertErrorCode(date, errorCode) {
|
|
runTest({dateArithmeticsSpec: date, expectedErrorCode: errorCode});
|
|
}
|
|
|
|
function runAndAssertResultOrErrorCode(date, result, errorCode) {
|
|
runTest({dateArithmeticsSpec: date, expectedErrorCode: errorCode, expectedResult: result});
|
|
}
|
|
|
|
function runTest({dateArithmeticsSpec, expectedResult, expectedErrorCode}) {
|
|
executeAggregationTestCase(coll, {
|
|
pipeline: [{$project: {_id: 0, newDate: dateArithmeticsSpec}}],
|
|
inputDocuments: [{_id: 1, date: ISODate("2020-12-31T12:10:05"), unit: "month", timezone: "Europe/Paris"}],
|
|
expectedErrorCode: expectedErrorCode,
|
|
expectedResults: expectedResult,
|
|
});
|
|
}
|
|
|
|
(function testDateAddWithValidInputs() {
|
|
runAndAssert({$dateAdd: {startDate: ISODate("2020-11-30T12:10:05.872Z"), unit: "day", amount: 1}}, [
|
|
{newDate: ISODate("2020-12-01T12:10:05.872Z")},
|
|
]);
|
|
|
|
if (!isMultiversion) {
|
|
runAndAssert({$dateAdd: {startDate: ISODate("1950-11-30T12:10:05.872Z"), unit: "day", amount: 1}}, [
|
|
{newDate: ISODate("1950-12-01T12:10:05.872Z")},
|
|
]);
|
|
|
|
runAndAssert(
|
|
{
|
|
$dateAdd: {
|
|
startDate: ISODate("1950-12-01T03:00:00.872Z"),
|
|
unit: "month",
|
|
amount: 2,
|
|
timezone: "America/New_York",
|
|
},
|
|
},
|
|
[{newDate: ISODate("1951-01-31T03:00:00.872Z")}],
|
|
);
|
|
}
|
|
|
|
// Test that adding with a null argument (non-existing field) results in null.
|
|
runAndAssert({$dateAdd: {startDate: "$dateSent", unit: "day", amount: 1}}, [{newDate: null}]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "$timeunit", amount: 1}}, [{newDate: null}]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "day", amount: null}}, [{newDate: null}]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "$unit", amount: 1, timezone: null}}, [{newDate: null}]);
|
|
|
|
// Test combination of null and invalid arguments.
|
|
runAndAssertResultOrErrorCode(
|
|
{$dateAdd: {startDate: "$dateSent", unit: "workday", amount: 1}},
|
|
[{newDate: null}],
|
|
ErrorCodes.FailedToParse,
|
|
);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "New year day", unit: "$timeunit", amount: 1}}, [{newDate: null}]);
|
|
|
|
runAndAssertResultOrErrorCode(
|
|
{$dateAdd: {startDate: "$date", unit: "workday", amount: "$amount", timezone: "Unknown"}},
|
|
[{newDate: null}],
|
|
ErrorCodes.FailedToParse,
|
|
);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "$unit", amount: 1.5, timezone: null}}, [{newDate: null}]);
|
|
|
|
// Tests when startDate and result date cross the DST time change in a timezone.
|
|
runAndAssert(
|
|
{
|
|
$dateAdd: {
|
|
startDate: ISODate("2020-10-24T18:10:00Z"),
|
|
unit: "hour",
|
|
amount: 24,
|
|
timezone: "Europe/Paris",
|
|
},
|
|
},
|
|
[{newDate: ISODate("2020-10-25T18:10:00Z")}],
|
|
);
|
|
|
|
// When adding units of day both the startDate and the result represent 20:10:00 in
|
|
// Europe/Paris. The two dates have different offsets from UTC due to the change in daylight
|
|
// savings time.
|
|
runAndAssert(
|
|
{
|
|
$dateAdd: {
|
|
startDate: ISODate("2020-10-24T18:10:00Z"),
|
|
unit: "day",
|
|
amount: 1,
|
|
timezone: "Europe/Paris",
|
|
},
|
|
},
|
|
[{newDate: ISODate("2020-10-25T19:10:00Z")}],
|
|
);
|
|
|
|
// The following tests use start date from the document field and all valid values for the
|
|
// 'unit' argument.
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "year", amount: -1}}, [
|
|
{newDate: ISODate("2019-12-31T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "quarter", amount: 1}}, [
|
|
{newDate: ISODate("2021-03-31T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "month", amount: 2}}, [
|
|
{newDate: ISODate("2021-02-28T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "week", amount: 1}}, [
|
|
{newDate: ISODate("2021-01-07T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "day", amount: 1}}, [
|
|
{newDate: ISODate("2021-01-01T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "hour", amount: 2}}, [
|
|
{newDate: ISODate("2020-12-31T14:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "minute", amount: -20}}, [
|
|
{newDate: ISODate("2020-12-31T11:50:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "millisecond", amount: 1050}}, [
|
|
{newDate: ISODate("2020-12-31T12:10:06.05Z")},
|
|
]);
|
|
|
|
// Tests using the document fields for unit and timezone arguments.
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "$unit", amount: 1}}, [
|
|
{newDate: ISODate("2021-01-31T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateAdd: {startDate: "$date", unit: "month", amount: 2, timezone: "$timezone"}}, [
|
|
{newDate: ISODate("2021-02-28T12:10:05Z")},
|
|
]);
|
|
})();
|
|
|
|
(function testDateSubtractWithValidInputs() {
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "year", amount: 2}}, [
|
|
{newDate: ISODate("2018-12-31T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "quarter", amount: 2}}, [
|
|
{newDate: ISODate("2020-06-30T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "day", amount: 15}}, [
|
|
{newDate: ISODate("2020-12-16T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "hour", amount: 48}}, [
|
|
{newDate: ISODate("2020-12-29T12:10:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "minute", amount: 15}}, [
|
|
{newDate: ISODate("2020-12-31T11:55:05Z")},
|
|
]);
|
|
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "second", amount: 125}}, [
|
|
{newDate: ISODate("2020-12-31T12:08:00Z")},
|
|
]);
|
|
|
|
// Test last day adjustment in UTC.
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "$unit", amount: 3}}, [
|
|
{newDate: ISODate("2020-09-30T12:10:05Z")},
|
|
]);
|
|
|
|
// Test last day adjustment and crossing DST time change in a timezone.
|
|
runAndAssert({$dateSubtract: {startDate: "$date", unit: "$unit", amount: 3, timezone: "$timezone"}}, [
|
|
{newDate: ISODate("2020-09-30T11:10:05Z")},
|
|
]);
|
|
|
|
// Test last day adjustment in the New York timezone.
|
|
runAndAssert(
|
|
{
|
|
$dateSubtract: {
|
|
startDate: ISODate("2021-01-31T03:00:00.872Z"),
|
|
unit: "month",
|
|
amount: 2,
|
|
timezone: "America/New_York",
|
|
},
|
|
},
|
|
[{newDate: ISODate("2020-12-01T03:00:00.872Z")}],
|
|
);
|
|
|
|
if (!isMultiversion) {
|
|
runAndAssert({$dateSubtract: {startDate: ISODate("1950-12-01T12:10:05.872Z"), unit: "day", amount: 1}}, [
|
|
{newDate: ISODate("1950-11-30T12:10:05.872Z")},
|
|
]);
|
|
|
|
runAndAssert(
|
|
{
|
|
$dateSubtract: {
|
|
startDate: ISODate("1951-01-31T03:00:00.872Z"),
|
|
unit: "month",
|
|
amount: 2,
|
|
timezone: "America/New_York",
|
|
},
|
|
},
|
|
[{newDate: ISODate("1950-12-01T03:00:00.872Z")}],
|
|
);
|
|
}
|
|
})();
|
|
|
|
// Test combinations of $dateAdd and $dateSubtract.
|
|
(function testDateArithmetics() {
|
|
runAndAssert(
|
|
{
|
|
$dateSubtract: {
|
|
startDate: {$dateAdd: {startDate: "$date", unit: "hour", amount: 2}},
|
|
unit: "hour",
|
|
amount: 2,
|
|
},
|
|
},
|
|
[{newDate: ISODate("2020-12-31T12:10:05Z")}],
|
|
);
|
|
|
|
assert.eq(
|
|
coll
|
|
.aggregate([
|
|
{
|
|
$project: {newDate: {$dateSubtract: {startDate: "$date", unit: "month", amount: 1}}},
|
|
},
|
|
])
|
|
.toArray(),
|
|
coll
|
|
.aggregate([
|
|
{
|
|
$project: {
|
|
newDate: {
|
|
$dateAdd: {startDate: ISODate("2020-11-30T12:10:00Z"), unit: "second", amount: 5},
|
|
},
|
|
},
|
|
},
|
|
])
|
|
.toArray(),
|
|
);
|
|
})();
|
|
|
|
// Tests for error codes.
|
|
(function testDateArithmeticsErrorCodes() {
|
|
// Missing required argument startDate.
|
|
runAndAssertErrorCode({$dateAdd: {unit: "second", amount: 120}}, 5166402);
|
|
|
|
// Missing required argument unit.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", amount: 1}}, 5166402);
|
|
|
|
// Unrecognized argument 'units'.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", units: "day", amount: 1}}, 5166401);
|
|
|
|
// Invalid string type of startDate argument.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "myBirthDate", unit: "year", amount: 10}}, 5166403);
|
|
|
|
// Invalid numeric type of unit argument.
|
|
runAndAssertErrorCode({$dateAdd: {startDate: "$date", unit: 1, amount: 10}}, 5166404);
|
|
|
|
// Invalid value of unit argument.
|
|
runAndAssertErrorCode({$dateAdd: {startDate: "$date", unit: "epoch", amount: 10}}, ErrorCodes.FailedToParse);
|
|
|
|
// Invalid double type of amount argument.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", unit: "year", amount: 1.001}}, 5166405);
|
|
|
|
// Overflow error of dateAdd operation due to large amount.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", unit: "month", amount: 12 * 300000000}}, 5166406);
|
|
|
|
// Invalid 'amount' parameter error of dateAdd operation due to large amount.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", unit: "month", amount: -30000000000}}, 5976500);
|
|
|
|
// Invalid 'amount' parameter error of dateSubtract operation: long long min value cannot be
|
|
// negated.
|
|
runAndAssertErrorCode({$dateSubtract: {startDate: "$date", unit: "day", amount: -9223372036854775808}}, 6045000);
|
|
|
|
// Invalid value of timezone argument.
|
|
runAndAssertErrorCode({$dateAdd: {startDate: "$date", unit: "year", amount: 1, timezone: "Unknown"}}, 40485);
|
|
})();
|