Closed Bug 810973 Opened 12 years ago Closed 9 years ago

Date constructor rounds off milliseconds when passed a Date object

Categories

(Core :: JavaScript Engine, defect)

x86
macOS
defect
Not set
normal

Tracking

()

RESOLVED DUPLICATE of bug 1187233

People

(Reporter: alice.lieutier, Unassigned)

References

Details

Attachments

(1 file)

      No description provided.
Attached file testCase
new Date(new Date()) does not return the same as new Date()

Example :
new Date().getTime() : 1352740221589
new Date(new Date()).getTime() : 1352740221000

Those instructions return the same result in Chrome, Safari, Opera.
Version: unspecified → Trunk
Summary: new Date() → new Date() does not take an object as a parameter
Note that the behavior in Firefox matches the behavior specified in ECMA-262, section 15.9.3.2. When "new Date(Value)" is called, ToPrimitive() is called on the argument, which converts the argument Date object to the specified string representation. The string representation does not include milliseconds. The specification then says to parse that string back, and to use that as the time for the new Date object.

That said, this behavior is pretty silly, and it would not be obviously incorrect to skip the stringify and parse phases when a Date object is passed in.

Also note that old versions of Firefox did not have the rounding behavior.
Summary: new Date() does not take an object as a parameter → Date constructor rounds off milliseconds when passed a Date object
Should toPrimitive convert to string in this case, or to a number?
(In reply to Sean Stangl from comment #3)
> Note that the behavior in Firefox matches the behavior specified in
> ECMA-262, section 15.9.3.2. When "new Date(Value)" is called, ToPrimitive()
> is called on the argument, which converts the argument Date object to the
> specified string representation. The string representation does not include
> milliseconds.

Shouldn't the string representation include the milliseconds, though?
According to ECMA-262, section 15.9.1.15:
"ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 Extended Format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ"
This includes the milliseconds. However, I see that milliseconds are not included. Is there an other spec that says what should be included in the string?
(In reply to Boris Zbarsky (:bz) from comment #4)
> Should toPrimitive convert to string in this case, or to a number?

From what I read, I think it should be a number:

ECMA-262, section 15.9.3.2 new Date (value)

"The [[PrimitiveValue]] internal property of the newly constructed object is set as follows:
1. Let v be ToPrimitive(value).
2. If Type(v) is String, then
a. Parse v as a date, in exactly the same manner as for the parse method (15.9.4.2); let V be the time value for this date.
3. Else, let V be ToNumber(v).
4. Set the [[PrimitiveValue]] internal property of the newly constructed object to TimeClip(V) and return."

ECMA-262, section 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."
> Is there an other spec that says what should be included in the string?

The relevant spec to toString on Dates is 15.9.5.2, which says:

  This function returns a String value. The contents of the String are implementation-
  dependent, but are intended to represent the Date in the current time zone in a
  convenient, human-readable form.

As for whether it should be a number, the relevant spec bit is 9.1, which says that [[DefaultValue]] is called, passing in the hint from ToPrimitive (in this case none).  And section 8.12.8 says that:

  When the [[DefaultValue]] internal method of O is called with no hint, then it behaves
  as if the hint were Number, unless O is a Date object (see 15.9.6), in which case it
  behaves as if the hint were String.

So converting to string is correct as the spec currently stands.
Yay for midairing on writing comments, but I had this written, so might as well not waste it completely...

(In reply to Boris Zbarsky (:bz) from comment #4)
> Should toPrimitive convert to string in this case, or to a number?

The spec (15.9.3.2) says to call ToPrimitive(value), passing no optional hint.  ToPrimitive on an object (9.1) calls |object.[[DefaultValue]]| passing any specified hint.  None was specified, so you get to this hideous language in the basic [[DefaultValue]] algorithm definition (8.12.8):

  When the [[DefaultValue]] internal method of O is called with no
  hint, then it behaves as if the hint were Number, unless O is a
  Date object (see 15.9.6), in which case it behaves as if the
  hint were String.

For a Date, that continues on to call the toString property on the object.  The [[PrimitiveValue]] internal property on Dates is a red herring here, except to the extent it's examined by the toString/valueOf functions, if either is called.

So, yes, when you have |new Date(dateObject)|, ToPrimitive will convert with hint String.  Which doesn't actually guarantee you'll get a string at all, just that it'll try toString first and valueOf second, because you could overwrite Date.prototype.toString or even add a toString property to dateObject, but....  So much ipsedixitism.  :-(

Anyway.  Date.prototype.toString (15.9.5.2) returns an implementation-dependent string value.  Unless we make that include milliseconds, which it doesn't now, we can't fix this while complying with the spec.  I'm betting lots of sites use the toString output in UI, in places where displaying milliseconds would be totally obnoxious.  So we can't add milliseconds to toString, and our behavior now is correct, and really can't be changed under the current spec.

At best this seems like something we could get a spec erratum for, to make new Date(value) special-case when value is a Date object.  If IE does what all the other browsers do, it seems fairly likely it could be pushed through TC39.
(In reply to Jeff Walden [:Waldo] (remove +bmo to email) from comment #8)

> At best this seems like something we could get a spec erratum for, to make
> new Date(value) special-case when value is a Date object.  If IE does what
> all the other browsers do, it seems fairly likely it could be pushed through
> TC39.

I finally got an IE to test on, and it seems that IE9 has the same behavior as Firefox.
As another data point: Chrome, Opera, and Safari all preserve milliseconds for this use case.

Haven't tested it on IE, but this behavior makes the "copy constructor" much, much slower on Firefox than on most other major browsers:

http://jsperf.com/date-copy-constructor

A simple workaround is:

  new Date(originalDate.valueOf())

which, though more verbose, indicates unambiguously that the Number value is to be used.

Spec aside, this is surprising behavior by the standards of most programming languages, and it is unfortunate that this workaround is needed :(
> Haven't tested it on IE

See comment 9.
Assignee: general → nobody
I just encountered this bug while working on a project. A quick test shows Firefox is currently the only browser with this behaviour; Chrome 44, Opera 32 and Edge 20 (plus a load of older versions and mobile browsers, too) all preserve the milliseconds.

However (correct me if I'm wrong), the latest version of the spec (EMCA 2015) seemed to have changed in this regard (section 20.3.3.2). For the Date constructor it's now using the [[DateValue]] internal slot when passed an object. Once implemented this should resolve the issue, and also no longer cause the performance penalty by string conversion and interpretation.

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-date-value
See also bug 1187233. There was some activity there a while ago, hopefully we can reland the patch there soon.
Duping forward to bug 1187233, because that bug has a patch.
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: