As per MongoDB official docs, it states that:
ObjectId values consists of 12-bytes, where the first four bytes are a
timestamp that reflect the ObjectId’s creation, specifically:
a 4-byte value representing the seconds since the Unix epoch,
a 3-byte machine identifier,
a 2-byte process id, and
a 3-byte counter, starting with a random value.
I'm just wondering what's gonna happen on Tue, 19 Jan 2038 03:14:08 GMT when the unix time will be equal to 2147483648 which doesn't fit the 4-byte timestamp in ObjectId *philosoraptor meme*
Unsigned 2,147,483,648 perfectly fits into 4 bytes. 4 bytes is enough to hold values up to 4,294,967,295, which is a unix epoch for Sunday, 7 February 2106 06:28:16 GMT.
If ObjectID's survive without changes till then, the timestamp part will start from 0, if you care:
> new Date();
ISODate("2106-02-08T12:41:20.450Z")
> db.t.insert({welcome:"from the future"});
WriteResult({ "nInserted" : 1 })
> db.t.find().pretty();
{
"_id" : ObjectId("0001a7b306c389186a3a9323"),
"welcome" : "from the future"
}
> db.t.find()[0]._id.getTimestamp();
ISODate("1970-01-02T06:07:47Z")
Related
I have identified recently date fields in my mongod 4.0 with such a content:
"last_update" : ISODate("-229-05-06T07:23:23Z")
"last_update" : ISODate("50170-12-13T06:03:34Z")
"last_update" : ISODate("0000-07-23T05:19:55Z")
So my question:
Is mongodb allowing such freedom for date fields ( signed 64bit integer of type date ) ?
According to this :
https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#conversion-table
It seems like the format is OK?
Datetime [year before 1970 or after 9999] {"$date": {"$numberLong": <64-bit signed integer giving millisecs relative to the epoch, as a string>}}
Attempts to insert it from mongo shell ISO date helper as expected did not allowed me:
MongoDB Enterprise mongos> db.test.insert({ "created" : ISODate("-229-05-06T07:23:23Z") })
2021-01-29T11:47:53.484+0100 E QUERY [js] Error: invalid ISO date: -229-05-06T07:23:23Z :
ISODate#src/mongo/shell/types.js:65:1
#(shell):1:31
MongoDB Enterprise mongos>
But at the same time insert affected fields from the original document in another collection was not having issues:
MongoDB Enterprise mongos> var x = db.theAffectedCollection.findOne({_id:ObjectId("5c6e8c6ce0ebbb309ce0dc06")},
{created:1,last_update:1})
MongoDB Enterprise mongos> use test
MongoDB Enterprise mongos> db.test.insert(x)
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise mongos> db.test.find()
{ "_id" : ObjectId("5c6e8c6ce0ebbb309ce0dc06"), "created" : ISODate("-229-05-06T07:23:23Z"), "last_update" : ISODate("-229-05-06T07:23:23Z") }
mongoexport result:
"created":{"$date":"-0229-05-06T07:23:23.000Z"}
Luckily the document _id timestamp show the exact creation date:
ObjectId("5c6e8c6ce0ebbb309ce0dc06").getTimestamp()
ISODate("2019-02-21T11:33:00Z")
So I could easily fix it ...
Issue clarified , in the extended json format supported by mongoDB the date field in shell mode ( not strict mode ) can support dates outside the range 0000-9999 and it is understood by mongodb like signed 64bit integer in the form:
mongos> new Date(1313124124122341)
ISODate("43581-03-31T21:08:42.341Z")
mongos>
mongos> new Date(-121213232233222)
ISODate("-1872-11-27T01:42:46.778Z")
mongos>
In Strict mode, is an ISO-8601 date format with a mandatory time zone field following the template YYYY-MM-DDTHH:mm:ss.mmm<+/-Offset>.
In Shell mode, is the JSON representation of a 64-bit signed integer giving the number of milliseconds since epoch UTC.
Strict Mode:
{ "$date": "<date>" }
mongo Shell Mode:
new Date ( <date> )
https://docs.mongodb.com/manual/reference/mongodb-extended-json-v1/
Internally, Date objects are stored as a signed 64-bit integer representing the number of milliseconds since the Unix epoch (Jan 1, 1970).
Not all database operations and drivers support the full 64-bit range. You may safely work with dates with years within the inclusive range 0 through 9999.
So thanks alot #Alex & #Wernfried to provide the hints !
This is a sample data
[{ date: '2020-05-21T14:02:00.0123 }, { date: '2020-05-22T14:02:00.0123 }, { date: '2020-05-23T14:02:00.0123 }]
I want to filter records of 22-May or earlier, here is my expected:
[{ date: '2020-05-21T14:02:00.0123 }, { date: '2020-05-22T14:02:00.0123 }]
I tried with this query:
{ date: { $lte: new Date('2020-05-22') }}
But it returns only data earlier 22-May. I think problem is { date: { $lte: new Date('2020-05-22') }} will data.date lte 2020-05-22T00:00:00.000
How I can exclude time ?
You need to match type of input with type of date field in document, either both should be Date's or strings. I would highly suggest maintain dates as dates in DB. Also you need to know that dates in MongoDB are of format ISODate() and holds UTC date.
If your DB date field is of type date :
I want to filter records of 22-May or earlier
As you wanted to get documents <= 22-May, then sending new Date('2020-05-22') doesn't work. Cause :
when you do new Date('2020-05-22'), it will give you Fri May 22 2020 00:00:00 GMT only if you belong to UTC, for example if you're in New York America which is 4 hours behind UTC then it would result in Thu May 21 2020 20:00:00 GMT-0400 (Eastern Daylight Time) which represents EDT, basically it's your system/app server time i.e; local date time.
So if your region is behind UTC then you'll get a back date Thu May 21 2020 otherwise if it's ahead of UTC then there is no issue you'll see Fri May 22 2020.
Ok, now that we've fixed date issues, but we need to look into hours now :
Since you want docs <= 22-May then Fri May 22 2020 00:00:00 GMT doesn't work you need to have either <= Fri May 22 2020 23:59:59 GMT or Sat May 23 2020 00:00:00 GMT. In order to get that :
let date = new Date('2020-05-22')
date.setDate(date.getUTCDate()); // Setting utc date, Only useful if you're region is behind UTC
date = new Date(date.setHours(23,59,59,999)) // This overrides hours generated with 23:59:59 - which is what exactly needed here.
/** Now do your query */
{ date: { $lte: date }}
If your DB date field is of type string :
Then you don't need to convert string to date, instead you can send input date in string format :
let date = new Date('2020-05-22').toISOString() // 2020-05-22T00:00:00.000Z
/** Above would get you an ISO string no matter which region you're in,
* now since we need `2020-05-22T23:59:59.000Z` which is not easy on ISO string
* We would just do +1 on date like `new Date('2020-05-23').toISOString()` - // 2020-05-23T00:00:00.000Z */
let date = new Date('2020-05-23').toISOString(); // like this
date = date.slice(0, -1) // removing `Z` from date string as your `date` field doesn't have this.
// Now your query is just `$lt`
{ date: { $lt: date }}
Test : mongoplayground
When I'm doing:
db.events.ensureIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 })
What timezone the expiresAt is comparing to ??
MongoDB dates are UTC dates. Therefore, the only values you can st the "expiresAt" field would be UTC times. And the expiry is going to be at after your set expiryAfterSeconds (in your case 0) passed since your expiresAt in UTC time.
I try to understand why
print(pd.Timestamp("2015-01-01") - pd.DateOffset(day=1))
does not result in
pd.Timestamp("2014-12-31")
I am using Pandas 0.18. I run within the CET timezone.
You can check pandas.tseries.offsets.DateOffset:
*kwds
Temporal parameter that add to or replace the offset value.
Parameters that add to the offset (like Timedelta):
years
months
weeks
days
hours
minutes
seconds
microseconds
nanoseconds
Parameters that replace the offset value:
year
month
day
weekday
hour
minute
second
microsecond
nanosecond
print(pd.Timestamp("2015-01-01") - pd.DateOffset(days=1))
2014-12-31 00:00:00
Another solution:
print(pd.Timestamp("2015-01-01") - pd.offsets.Day(1))
2014-12-31 00:00:00
Also it is possible to subtract Timedelta:
print(pd.Timestamp("2015-01-01") - pd.Timedelta(1, unit='d'))
pd.DateOffset(day=1) works (ie no error is raised) because "day" is a valid parameter, as is "days".
Look at the below one: "day" resets the actual day, "days" adds to the original day.
pd.Timestamp("2019-12-25") + pd.DateOffset(day=1)
Timestamp('2019-12-01 00:00:00')
pd.Timestamp("2019-12-25") + pd.DateOffset(days=1)
Timestamp('2019-12-26 00:00:00')
Day(d) and DateOffset(days=d) do not behave exactly the same when used on timestamps with timezone information (at least on pandas 0.18.0). It looks like DateOffset add 1 day while keeping the hour information while Day adds just 24 hours of elapsed time.
>>> # 30/10/2016 02:00+02:00 is the hour before the DST change
>>> print(pd.Timestamp("2016-10-30 02:00+02:00", tz="Europe/Brussels") + pd.offsets.Day(1))
2016-10-31 01:00:00+01:00
>>> print(pd.Timestamp("2016-10-30 02:00+02:00", tz="Europe/Brussels") + pd.DateOffset(days=1))
2016-10-31 02:00:00+01:00
I have a Person object. and this person object has the following attributes;
Name
StartDate
EndDate
I am saving this Person objects to an array. This array might contain more than 100 person objects.All of the above attributes are Strings.
The following is an example of person objects in that array;
John, Tue Feb 22, Thr Mar 30
Jack, Wed Mar 09, Fri Apr 21
Jack, Thu Mar 19, Fri Dec 20
Jack, Tue Jan 08, Fri Apr 26 etc..
Now i need to will supply a date, say for example Wed 29 Mar, and i need to check if it's in the range of StartDate and EndDate in the array of persons object. I have a pseudo-code for the scenario.
The date i am going to check against the StartDate and EndDate are Strings too.
Pseudo-code:
if Startdate >= providedDate && EndDate <= providedDate {
// Add to an Array
else
//Do not add to an array
Since, the StartData, EndDate and ProvidedDate are all Strings how can i check if its Greater than or lesser than the provided date ?
Note: I need an approach that doesn't use NSPredicate
In order to compare values you need values that are comparable. You could use NSDate objects, you could cast dates into sortable character/numeric form (eg 20120425), or you could use custom objects that implement their own compare:options: methods.
Or you could write a separate compareString:string1 toString:string2 method and use the strings as you have them.
You just have to make up your mind which you want to do.
What are you being tested on here? It'd odd to have a date stored as a string. Are you meant to parse the string dates in order to compare them to the provided date? If so, I'll stay away from any kinds of date classes.
If so, I'd just split it into 3 strings -- day of the week, month, day. You don't care about day of the week.
You don't have a year so you can't do any logic about that... I guess just assume it's all in the same year. (You could do something crazy like calculate 'which recent year did this day fall on this day of the week', but come on...)
Associate each month with an integer. Let's say, using a hash map. As in Months.put('January',1), etc.
Get the number out of each date -- just convert from a string to an integer.
Then the logic for whether something is before or after a date is (if -1 is myMonth is before, 0 is they're the same, and 1 is myMonth is after)
if (Months.get(myMonth) < Months.get(providedMonth)) return -1
else if (Months.get(myMonth) > Months.get(providedMonth)) return 1
else
if (myDate < providedDate) return -1;
else if (myDate > providedDate) return 1;
else return 0;