jQuery.param() - doesn't serialize javascript Date objects? - javascript

jQuery.param({foo: 1}); // => "foo=1" - SUCCESS!
jQuery.param({bar: new Date()}); // => "" - OUCH!
There is no problem with encodeURIComponent(new Date()), which is what I would have thought param is calling for each member.
Also, explicitly using "traditional" param (e.g. jQuery.param(xxx, true)) DOES serialize the date, but alas, that isn't of much help since my data structure isn't flat.
Is this because typeof(Date) == "object" and param tries to descend into it to find scalar values?
How might one realistically serialize an object that happens to have Date's in it for $.post() etc.?

You're probably going to want the date transformed into a string, since that's what it's going to have to be on the wire anyway.
$.param({bar: new Date().toString()});
Now you may want it formatted in some particular way so that your server gets something it can parse. I think that the datejs library has support for formatting, or you could roll your own by picking out pieces of the date with getDate(), getMonth(), getYear() etc.

If you work with Microsoft products on the server side you should take in consideration, that Microsoft serialize Date as a number of milliseconds since UTC, so as a number. To be more exact, the serialization string look like /Date(utcDate)/, where utcDate date is this number. Because JSON supports the backslash as an escape character you should use code like following to serialize a Date object myDate:
"\/Date(" + Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(),
myDate.getUTCDate(), myDate.getUTCHours(),
myDate.getUTCMinutes(), myDate.getUTCSeconds(),
myDate.getUTCMilliseconds()) + ")\/"

I think this is a jQuery bug in the following context:
jQuery 1.4.2 (1.3.2 works)
new methods added into Date.prototype

Related

Firestore can not write date as collection name

I'm trying to write to Firestore all the prices from different stocks. Structure should look something like this (although this might not be the best fitted for it, still thinking of it as in SQL) :
const d1 = new Date();
const result = d1.getTime();
console.log('Epochtime',result);
database.collection("stock1").doc("exchange1").collection(date).doc('prices').set({"price":"price_value"})
Now the problem is that I can't create a collection with a name that's a variable that contains date. I tried all the different types of it and I presumed that epoch time should work, as this is a number like: 1636213439908. I always get the error: Value for argument "collectionPath" is not a valid resource path. Path must be a non-empty string. Although the exact same variable can be written as a value in a collection. So not sure what am I doing wrong here.
Document IDs in Firestore must be strings, so you'll have to convert the data to a string. While date.toString() will work, I highly recommend using a ISO-8601 format for the dates, such as date.toISOString(). These formats are designed to be both humanly readable and machine sortable.

Insert field with $currentDate to MongoDB collection in Meteor

Not sure how to use $currentDate when inserting a document into a MongoDB collection in Meteor.
Can this only be used in an update, not an insert? Would seem strange, but I don't see an alternative (other than using new Date instead).
Example
Stuff.insert({
owner: Meteor.userId(),
createdAt: ..., // how to create this field with $currentDate ?
theStuff: "Some of the good stuff"
})
Notes / Thoughts / TL,DR
Fields can't start with $ operators or, as far as I know, curly braces {}.
What's the point of having an operator that only works with updates, if that's indeed the case?
Why/when is $currentDate better than new Date?
One nice thing, if using Moment.js esp, is that $currentDate is entered in ISO 8601 format.
Is the answer to do some kind of upsert from the start? If so, could this have unintended consequences?
What's the point of having an operator that only works with updates, if that's indeed the case?
$currentDate is an update operator thus you can't use it with the collection.insert method. But when upsert is true it will create a new document when no document matches the query criteria. MongoDB operators tend to follow the Unix philosophy
Do One Thing and Do It Well
So each operator should perform only one task.
Why/when is $currentDate better than new Date?
First I would like to mention that new Date is a JavaScript Date instance.
$currentDate and new Date can be used when you want to update the value of a field to current date but with new Date you need to use another update operator for it to work. For example:
Using new Date
db.collection.update({ "name": "bar" }, { "$set": { "date": new Date() }})
Using $currentDate
db.collection.update({ "name": "bar"},
{ "$currentDate": { "date": { "$type": date }}}
)
Unlike $currentDate, new Date can be use with the insert method and value can be set to a particular if Date is call with more than on argument.
You can retrieve timestamp from autogenerated "_id" that is created within insert operation.
http://api.mongodb.com/java/current/org/bson/types/ObjectId.html
Just use the method : ObjectId.getTimestamp().
Timestamp granularity is in seconds.
It will become more simple if you will use autoValue in collection model
createdAt:
type: Date
autoValue: ->
if this.isInsert
return new Date
else if this.isUpsert
return $setOnInsert: new Date
else
this.unset()
It will automatically set date while insert or update the data into it
$currentDate when used in the $update construct can be used to insert fields if they do not pre-exist in the document.
Quoting documentation for Mongodb 3.4:
Behavior
If the field does not exist, $currentDate adds the field to a document.
Although I do totally appreciate that this design makes perfect sense, there is an argument, perhaps a bad one, that you want to set the updated_at field to something sensible when you insert a document. One reason that you might want to do this is to avoid always needing to query on two fields to get the last updated time. Like I say, this might be bad juju, but well there you go.
Anyway the best hack that I could come up with to do this is to perform an upsert that filters on not the empty filter. That guarantees that the upsert is always an insert.
Just a small comment on this to the MongoDB Devs. As someone who has been working with databases for more years than they care to remember, getting my head around how one is supposed to do timestamps correctly in MongoDB:
created_at => _id.Timestamp
updated_at => $currentDate()
has taken me far too long. Maybe that's my fault, it probably is, but it's something that I think most people probably want / need to do and as a concept it could be explained better. If you search around you will find a lot of bad / wrong information, because I'm pretty sure that this is the way to do it and ... well the internet is far from at consensus on this (although I am now).
I don't know, maybe it's a test. Maybe this is the first thing you ask someone when you are hiring a MongoDB developer: how do you do timestamps? Well, that's what I'd ask anyway because if you know you've probably learned most of the API by that stage.

Efficient way to convert UTC dates within JSON array returned by MongoDB in Nodejs to Local Time

I am using Node.js to query MongoDB and have a field that is a Date (ISODate). In Node.js after querying the Date format that is returned looks like this
DT : 2014-10-02T02:36:23.354Z
What I am trying to figure out is how based on the code i have below, can efficiently convert the DT field from UTC to Local Time ISOString. In other words if local time is EDT then something like this
DT : 2014-10-02T23:36:23.354Z
I don't think there is anything I can do in the query itself from Mongo. Should I traverse the Array result set and manually change the dates? Is there a better approach here? I am sending the response to an HTTP client.
collection.find(query,options).toArray(function (err, items) {
if (err) {
logAndSendDebugError(500, "Error issuing find against mongo Employees Collection -" + type, res);
} else {
var response = {
'type': type,
'employees': items
};
res.jsonp(response);
}
});
In ES5, Date.parse should be able to parse that format, however it isn't reliable. Manually parsing it isn't hard:
// Parse ISO 8601 UTC string like 2014-10-02T23:36:23.354Z
function parseISOUTC(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
}
The date instance that is created will have a local timezone offset calculated from system settings. To get a UTC ISO 8601 string from a local date you can use toISOString:
var date = new Date();
console.log(date.toISOString());
Note that toISOString is ES5 so may need a polyfill if this is used in older browsers. See MDN Date.prototype.toISOString().
I would have thought the most efficient way to handle dates between the client and server would be to use the EJSON package. This covers a few things that are skirted around in other discussion here and the importance is placed on maintaining "type fidelity" when handling JSON conversion.
So what you are getting right now is the result of a "string" which is called from the "Date" object in response to a JSON.stringify call. Whatever the method being used, this is essentially what is happening where the .toJSON() method is being called from the "Date" prototype.
Rather than muck around with the prototypes or other manual processing of coversions, the EJSON package allows you to call EJSON.stringify instead which has some built in behavior to preserve types, where specifically the generated JSON string would look like this for a Date element:
{ "myCreatedDate": { "$date": 1412227831060 } }
The value there is an epoch timestamp, essentially obtained from the .valueOf() prototype method, but the field is given a special structure automagically as it were. The same is true for types other than dates as well.
The corresponding "client" processing which you can add with simple includes to your web application in the browser, e.g:
<script src="components/ejson/base64.js"></script>
<script src="components/ejson/ejson.js"></script>
This allows a same EJSON object to be present where you can process the received JSON with EJSON.parse. The resulting JavaScript Object is maintained as a "Date" type when the de-serialize is done.
var obj = EJSON.parse( "{ \"myCreatedDate\": { \"$date\": 1412227831060 } }" );
{
myCreatedDate: /* Actually a Date Object here */
}
So now in your client browser, you have a real Date object without any other processing. Any .toString() method called on that object is going to result in a value represented in a way that matches the current locale settings for that client.
So if you use this to pass the values around between server and client in a way that is going to maintain an actual "Date" object, then the correct Object values are maintained on either client and server and needs no further conversion.
Very simple to include in your project and it takes a lot of the heavy lifting of maintaining "timezone" conversions off your hands. Give it a try.
Probably worth noting that the "core" of this comes from a MongoDB specification for Extended JSON Syntax. So aside from this (partial) implementation in the EJSON package, the same "type identifiers" are supported in several MongoDB tools as well as within several driver implementations with a custom JSON parser that will automatically convert the types. Notably the Java and C# drivers have this capability shipped with the driver libraries.
It's fairly easy to follow the convention outlined in that link, and it is intended to "map" to the BSON type specifications as well. At the worst, you can always "inspect" the results from a standard JSON parser and implement custom routines to "re-instantiate" the "types". But as noted, the software is already in place with several libraries.

jQuery.jgrid.parseDate date formatting

I have searched for this but couldn't find anyone trying to do what i am doing with jqGrid formatters.
I have a date which I am trying to parse which is not in a jqGrid table, but I am using jqGrid on the site elsewhere and am hoping to parse this date using jqGrid's date parser instead of having to write a seperate method.
I have been messing around with the jGrid object but I need a little help with this.
My date format is ISO8601Long i.e. 2013-11-17T09:00:00
First, I am ensuring the date formats in the formatter are the ones i wish to use:
jQuery.jgrid.formatter.date.srcformat = 'Y-m-d H:i:s';
jQuery.jgrid.formatter.date.newformat = 'j/m/Y g.ia';
Next, I call the jQuery.jgrid.parseDate method in an attempt to parse the date.
jQuery.jgrid.parseDate(0, 0, '2013-11-17T09:00:00');
I am not sure what the first two arguments are, but they look like they might accept a srcformat and newformat. Either way, they don't format as I would expect. There is a fourth too, but this seems to only accept an object.
This leaves me with 2013-11-17GMT09:00:00. While this is a bit easier to understand, it is not in the format I would be expecting. I presume I have missed a step or somehow need to call the formatter after this.
Any pointers would be great.
Thanks,
Dale
The correct usage of parseDate would be the following:
var parsedData = $.jgrid.parseDate("Y-m-d H:i:s", "2013-11-17T09:00:00", "j/m/Y g.ia");
or
var parsedData = $.jgrid.parseDate("ISO8601Long", "2013-11-17T09:00:00", "j/m/Y g.ia");
You can use alternatively Globalize jQuery Plugin.

date.format is not working

I am trying to use the date.format and getting an error that format is not a recognized method. I tried to use thesame in new solution, and I'm getting a correct result. Any idea why .format method is not working? These both are in Javascript.
Assuming you are talking about Date type...
It is clear why format method is not working - because there is no such method on Date object.
It is less clear why/when it would work - most likely you are using some script library that modifies Date object to have format method.
But if you are talking about some other type - format function may be present (or added) to any object and it is not possible to suggest anything without code...
I.e. custom object with format function:
var date = { format:function() {alert("Hi");}};
date.format();

Categories