// server6189 - Support date operators with dates before 1970 c = db.c; function test(date, testSynthetics) { print("testing " + date); c.drop(); c.save( {date: date} ); var ISOfmt = (date.getUTCMilliseconds() == 0) ? 'ISODate("%Y-%m-%dT%H:%M:%SZ")' : 'ISODate("%Y-%m-%dT%H:%M:%S.%LZ")'; // Can't use aggregate helper or assertErrorCode because we need to handle multiple error types var res = c.runCommand('aggregate', {pipeline: [ {$project: { _id: 0 , year:{ $year: '$date' } , month:{ $month: '$date' } , dayOfMonth:{ $dayOfMonth: '$date' } , hour:{ $hour: '$date' } , minute:{ $minute: '$date' } , second:{ $second: '$date' } // server-6666 , millisecond:{ $millisecond: '$date' } // server-9289 , millisecondPlusTen:{ $millisecond: {$add: ['$date', 10]}} // $substr will call coerceToString , string: {$substr: ['$date', 0,1000]} // server-11118 , format: {$dateToString: { format: ISOfmt , date: '$date'}} }}]}); if (date.valueOf() < 0 && _isWindows() && res.code == 16422) { // some versions of windows (but not all) fail with dates before 1970 print("skipping test of " + date.tojson() + " because system doesn't support old dates"); return; } if (date.valueOf()/1000 < -2*1024*1024*1024 && res.code == 16421) { // we correctly detected that we are outside of the range of a 32-bit time_t print("skipping test of " + date.tojson() + " because it is outside of time_t range"); return; } assert.commandWorked(res); assert.eq(res.result[0], { year: date.getUTCFullYear() , month: date.getUTCMonth() + 1 // jan == 1 , dayOfMonth: date.getUTCDate() , hour: date.getUTCHours() , minute: date.getUTCMinutes() , second: date.getUTCSeconds() , millisecond: date.getUTCMilliseconds() , millisecondPlusTen: ((date.getUTCMilliseconds() + 10) % 1000) , string: date.tojson().slice(9,28) , format: date.tojson() } ); if (testSynthetics) { // Tests with this set all have the same value for these fields res = c.aggregate( { $project:{ _id: 0 , week:{ $week: '$date' } , dayOfWeek:{ $dayOfWeek: '$date' } , dayOfYear:{ $dayOfYear: '$date' } , format: { $dateToString: { format: '%U-%w-%j' , date: '$date' } } } } ); assert.eq(res.toArray()[0], { week: 0 , dayOfWeek: 7 , dayOfYear: 2 , format: '00-7-002' } ); } } // Basic test test(ISODate('1960-01-02 03:04:05.006Z'), true); // Testing special rounding rules for seconds test(ISODate('1960-01-02 03:04:04.999Z'), false); // second = 4 test(ISODate('1960-01-02 03:04:05.000Z'), true); // second = 5 test(ISODate('1960-01-02 03:04:05.001Z'), true); // second = 5 test(ISODate('1960-01-02 03:04:05.999Z'), true); // second = 5 // Test date before 1900 (negative tm_year values from gmtime) test(ISODate('1860-01-02 03:04:05.006Z'), false); // Test with time_t == -1 and 0 test(new Date(-1000), false); test(new Date(0), false); // Testing dates between 1970 and 2000 test(ISODate('1970-01-01 00:00:00.000Z'), false); test(ISODate('1970-01-01 00:00:00.999Z'), false); test(ISODate('1980-05-20 12:53:64.834Z'), false); test(ISODate('1999-12-31 00:00:00.000Z'), false); test(ISODate('1999-12-31 23:59:59.999Z'), false); // Test date > 2000 for completeness (using now) test(new Date(), false);