I'm reading through a jquery plugin, and find this interesting syntax:
'sth'+ +new Date
It creates a numeric string which the author used for a unique id: sth1237004731731
I'm curious what kind of syntax it is, and if there's some reading materials about it? Thanks!
It's using some side effects of JavaScript's type coercion to build a unique identifier (probably for an element). The confusing part is the +new Date. Here, new Date (or new Date()) returns a Date object. But putting a + or a - in front of this forces the JS interpreter to coerce this value to a Number object, and the way JS does Date > Number is by returning the timestamp (or getTime()).
So this code could be expressed differently like this:
var date = new Date(), // "Mon May 14 2012 10:03:58 GMT-0400 (EST)"
timestamp = date.getTime(), // 1337004238612
identifierString = "sth" + timestamp.toString();
You might reasonably claim that there's no need to be so verbose, so I personally would probably have written this as:
var identifier = "sth" + (new Date()).getTime();
However, please avoid coding things like your example if you ever expect someone might have to maintain your code. If it stopped you in your tracks, it probably will stop a lot of people. Coding style is not merely about expressing intent to the interpreter, but expressing intent to human developers. If the code works in the browser but fails with a syntax error in most experienced developers' heads, you've done it wrong, plain and simple.
This is an interesting use of the unary + operator. Basically, you can break down this expression into three separate parts, splitting at the binary + operator:
"sth", then +, then +new Date.
The first operand of the binary + is just a generic string literal. The second operand uses the unary + operator, which, as the linked standard states, converts its operand to a Number.
Because the new operator has the highest precedence, it "binds tighter" than the unary +, which means new Date will be evaluated first. So the operand of the unary + is, in turn, the result of the expression new Date. Of course, new Date simply creates a blank Date object. As per § 15.9.3.3 new Date():
The [[PrimitiveValue]] internal property of the newly constructed
object is set to the time value (UTC) identifying the current time.
In other words, a new Date will just be a Date object representing the current time. And, in turn, +new Date will convert a blank Date object to a number.
The Short Answer
The specification is long and hard to follow. In short, +new Date returns the UNIX timestamp associated with the current time.
The Long Answer: Following the Spec
The long answer, following the specification, is that the unary + calls ToNumber(GetValue(expr)) where expr is the evaluated operand. GetValue(dateObj) will simply return dateObj, so the expression then becomes ToNumber(dateObj).
The result of ToNumber depends on what the type of the argument is. In the case of an object, it returns ToNumber(ToPrimitive(input argument, hint Number)).
ToPrimitive will, in turn, call the valueOf property of the Date object. That returns a Number, which is the time value associated with the Date object: finally, what we were looking for! Then it goes back up the chain: ToNumber(num) simply returns num.
Of course, from there, the string "sth" and the result of +new Date are concatenated (you can find that in the spec if you so wish), which gives you the result you were looking for.
Related
I got a code like this:
var date = new Date(new Date() + dateAdjust*3600*1000 );
However, the result came out weird. But if I change the plus sign to a minus sign, and make the dateAdjust become negative, it results right. I think it considers dateAdjust36001000 as a string. How do I fix that? I heard some people say to use parseInt(), but it doesn't work either.
var date = new Date(new Date() + parseInt(dateAdjust*3600*1000) );
Please bear in mind that JavaScript operators doesn't work exactly as Google Sheets operators (mentioned because the question includes the google-sheets tag).
The fix might be to use new Date().getTime() or new Date().toValue(). This will return the date-time in milliseconds since January 1, 1970 00:00:00 UTC. Assuming that dateAjust has assigned a number, then the final code might be:
var date = new Date(new Date().getTime() + dateAdjust * 3600 * 1000 );
Explanation
In JavaScript, when using + having a Date object to the left, due to JavaScript rules, it's converted into a string. This happens because in JavaScript the + could make two possible operations, mathematical addition and string concatenation while - operator is only able to do a mathematical subtraction. This is a operation called type coercion.
Having a string to the left of +, makes the right operand to be converted into a string too.
Related
How to add days to Date?
What exactly is Type Coercion in Javascript?
Why does Date return a date instead of the object's reference when referenced?
This question already has answers here:
Integer addition/subtraction issues with the Date object
(2 answers)
Closed 4 years ago.
When I subtract two Date-objects like this:
const startTime = new Date();
await someAsyncStuff();
const endTime = new Date();
const elapsedTime = endTime - startTime;
console.log(`The async stuff took ${elapsedTime} ms`);
Why does the Date objects end up being cast to milliseconds, which are then subtracted? I understand that they do, but I can't figure out what the actual sequence of events is that lead to this.
In general, JavaScript objects can define methods to convert the object to a String or a number (which you can customize by defining toString and valueOf methods). JavaScript will use those methods in numerical contexts (like 2 * a) or string contexts (like '' + a) to convert the object to the appropriate primitive.
In a context where it's ambiguous whether to use numerical or string conversion (like a + b), there's a default behavior, depending on the type of the object. Interestingly, Date are singled out among the default ECMAScript objects to convert to a String, instead of a number. Via the spec:
Date objects, are unique among built-in ECMAScript object in that they
treat "default" as being equivalent to "string", All other built-in
ECMAScript objects treat "default" as being equivalent to "number".
In the particular case of Date objects, the numerical conversion (the valueOf method) converts the time to epoch milliseconds, while the string conversion (the toString method) converts the object to a human-readable string. As #baao mentions in his answer, this can cause some issues when doing "arithmetic" with objects, due to automatic conversions of type.
In summary, Date (unlike most other objects) defaults to string conversion, but since subtraction requires two numbers for it to make sense, it converts the dates to numbers.
It's generally a good idea to explicitly define the behavior, in this case using valueOf, getTime or toString to make the code less ambiguous.
For more information of whether JavaScript chooses to use toString vs valueOf, see this question, the overall spec for addition (and subtraction), and the specific spec for Dates (mdn link), and #baao's answer for a more in depth look.
See Also:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf
It's how javascript does automatic type conversion - just like arithmetic operations (that you are performing here). You were lucky that you subtracted, if you've added them you'd end up with a string holding two date strings in a row because of how toPrimitive (that gets called implicitly) works for Dates. Consider the following
// automatic casting
console.log("1" - "1"); // 0
// but
console.log("1" + "1"); // 11
// now with dates
// automatic casting
console.log(new Date() - new Date()); 0
console.log(new Date() + new Date()); // Mon Jun 11 2018 10:10:36 GMT+0200 (Mitteleuropäische Sommerzeit)Mon Jun 11 2018 10:10:36 GMT+0200 (Mitteleuropäische Sommerzeit)
The specification on the additional operator has the following hint that explains this further
All native ECMAScript objects except Date objects handle the absence of a hint as if the hint Number were given; Date objects handle the absence of a hint as if the hint String were given.
JavaScript converts your value to a primitive when using arithmetic opererators, the method that gets called here is
Date.prototype [ ##toPrimitive ] ( hint )
Date.prototype [ ##toPrimitive ] ( hint )
This function is called by ECMAScript language operators to convert a Date object to a primitive value. The allowed values for hint are "default", "number", and "string". Date objects, are unique among built-in ECMAScript object in that they treat "default" as being equivalent to "string", All other built-in ECMAScript objects treat "default" as being equivalent to "number".
That said. The reason why your code works how it works is the later auto conversion performed by the subtraction, which gives hint to toPrimitive to return a number.
It equals endTime.getTime() - startTime.getTime()
As you say, they cast to millisecond and that exactly shows the difference.
This is happening because JS asks for the primitive of the Date's object when performing such operation, through the method valueOf. The Date's object overrides valueOf methods, so that the value used is basically the same of getTime.
You can also try by yourself:
const o = { valueOf: () => 10 };
console.log(o + 1) // 11
Given
var fromDatetime = "10/21/2014 08:00:00";
var toDatetime = "10/21/2014 07:59:59";
Target
Need to compare this two given datetime to check if this is a valid datetime inputs.
Im thinking that I could use this solution. .
var fromDatetime = new date("10/21/2014 08:00:00");
var toDatetime = new date("10/21/2014 07:59:59");
then compare each segment
fromDatetime.getFullYear() to toDatetime.getFullYear(),
fromDatetime.getMonth() to toDatetime.getMonth(),
so on so forth until I get a non equal comparison, then return.
My question is. . Is that the best case in comparing datetime in Javascript?
Any suggested solutions other than this will be much appreciated. .
Thank you in advance.
If you only need to know if one date is before or after another, you can use normal comparison operators:
if (dateA > dateB) { ... }
(Note that to instantiate Date objects, it is new Date(myDateString), not new date() as in your example.)
This works because the Date objects will be coerced to the underlying epoch values, which are just numbers representing the count of milliseconds that have passed since Jan 1, 1970, GMT. (Relational comparison uses the result of the operands’ ##toPrimitive or valueOf() functions if available.) As a result, this will be sensitive down to the millisecond, which may or may not be desired. You can control the granularity of the comparison either by making sure the input only includes values up to the hour/minute/whatever OR by doing piecemeal comparisons like you described in your question.
For more advanced date comparison operations, I highly recommend using a library like Moment.js, because natively there is not much to work with. For example Moment provides methods like
moment(myDateString).startOf('hour')
which can be very helpful if you need to make comparisons only at a particular level of specificity. But none of the datetime libraries are terribly lightweight, so only use them if you are either doing serverside code or you expect to rely on them extensively. If you only need to do this one comparison, it will be wiser to roll your own solution.
I read this code on amazon's home page.
Looks like it's trying to get the current time, However what's the meaning of using operator ||+ ?
var ue_t0=ue_t0||+new Date();
That's short-circuiting evaluation (||) followed by conversion to number (+).
That code is roughly equivalent to:
var ue_t0;
if (!ue_t0) {
ue_t0 = Number(new Date());
}
Note that converting a date to a number returns the number of milliseconds between the epoch (January 1st, 1970, 00:00:00 UTC) and that date.
It is saying :
evaluate ue_t0 and if it has value, then use it, else assign it
integer form of Date instance.
It says let ue_t0 be the value of ue_t0 or, if it is undefined, the value of the expression (new Date).
There is no ||+ operator in JavaScript, it is +new Date() which gives you a date representation in UNIX format
There is no ||+ operator.
+new Date() is a common shortcut to get the time as a timestamp. The + operator implicitly calls the valueOf method.
The || operator is another common shortcut to set a default value (+new Date()) if a variable (ue_t0) is not defined (or equal to anything that evaluates to false : null, 0 ...).
I'm building a Windows 8 Metro app (aka "Modern UI Style" or "Windows Store app") in HTML5/JavaScript consuming JSON Web Services and I'm bumping into the following issue: in which format should my JSON Web Services serialize dates for the Windows 8 Metro JSON.parse method to deserialize those in a date type?
I tried:
sending dates using the ISO-8601 format, (JSON.parse returns a string),
sending dates such as "/Date(1198908717056)/" as explained here (same result).
I'm starting to doubt that Windows 8's JSON.parse method supports dates as even when parsing the output of its own JSON.stringify method does not return a date type.
Example:
var d = new Date(); // => a new date
var str = JSON.stringify(d); // str is a string => "\"2012-07-10T14:44:00.000Z\""
var date2 = JSON.parse(str); // date2 is a string => "2012-07-10T14:44:00.000Z"
Here's how I got this working in a generic way (though it I'd rather find a format supported out-of-the-box by Windows 8's JSON.parse method):
On the server, I'm serializing my strings using:
date1.ToString("s");
This uses the ISO 8601 date format which is always the same, regardless of the culture used or the format provider supplied (see here for more information).
On the client-side, I specified a "reviver" callback to JSON.parse which looks for dates using a regexp and converts them into a date object automatically.
In the end, the deserialized object will contain actual JavaScript date types and not strings.
Here's a code sample:
var responseResult = JSON.parse(request.responseText, function dateReviver(key, value) {
if (typeof value === 'string') {
var re = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)$/
var result = re.exec(value);
if (result) {
return new Date(Date.UTC(+result[1], +result[2] - 1, +result[3], +result[4],+result[5], +result[6]));
}
});
Hope this helps,
Carl
This is not something that's unique to Windows 8's JSON.parse – it's the by-design behavior of the ECMA standard JSON parser. Therefore, there is (and can be) no "out-of-the-box support" for dates.
Per spec, JSON values can only be a String, Number, Boolean, Array, Object, or null. Dates are not supported. (IMO, this is an oversight on the part of the spec, but it's what we have to live with.)
Since there is no date type, your app has to work out how to handle dates on its own. The best way to handle this is to send dates as ISO 8601 strings (yyyy-MM-dd'T'HH:mm:ss'Z') or as milliseconds since the epoch (Jan 1 1970 00:00:00 UTC). The important part here is to make sure time is in UTC.
If performance is important, I would not use a reviver callback with JSON.parse. I did a lot of testing, and the overhead involved with invoking a function for every single property in your object cuts performance in half.
On the other hand, I was honestly surprised with how well testing a regex against every string value stood up against only parsing known property names. Just make sure you define the regex once, outside the loop!
Obviously, the absolute fastest ways to turn JSON values into Dates is if you know exactly what properties need to be parsed for dates. However, given the surprisingly good performance of the regex-based search methods, I don't think it's worth the extra complexity unless you really need the extra performance.
A note on using ISO strings vs milliseconds since epoch: tested independently, milliseconds wins. In IE, there's no difference, but Firefox really seems to struggle with ISO strings. Also note that the Date constructor takes milliseconds in all browsers. It also takes a the ISO string, but not in IE ≤ 8.