Date in PHP and Javascript are not match - javascript

As title, although I set with only value.
In Javascript:
var n = (new Date("2015 Oct 17")).getTime()/1000;
console.log(n);
// result: 1445014800
And PHP:
$unix = date('d-m-Y', 1445014800);
echo $unix;
// result: 16-10-2015
Please leave some explanations.
Thanks a lot!

In your JavaScript:
var n = (new Date("2015 Oct 17")).getTime()/1000;
console.log(n);
// result: 1445014800
The operation /1000 is coercing your value to a numeric type, so the answer is correct!

In javascript, parsing of a string like "2015 Oct 17" is entirely implementation dependant. If it works at all, it is likely to be converted to a Date object representing the date at 00:00:00 at the start of the day in the time zone of the host system.
For a system whose time zone offset is, say, UTC+1000, and that parses the string as a local time, the time value in seconds will be 1445004000.
However, such a system might decide that the string is a bit like an ISO 8601 string, and it might decide that since such strings without a time zone were treated as UTC in ES5, that it will treat it as a UTC time. In that case, the time value in seconds will be 1445040000 (i.e. equivalent to 2015-10-17T00:00:00Z).
To reliably transfer dates between systems, it is often considered best to transfer time values in either seconds or milliseconds since the UNIX (and ECMAScript) epoch of 1070-01-01T00:00:00Z.
To create such a time value for 2015-Oct-17 you can use:
var timeValue = Date.UTC(2015, 9, 17);
To convert the UNIX time value 1445014800 to an ECMAScript date, you can do (noting that UNIX time values are in seconds and ECMAScript in milliseconds):
console.log(new Date(1445014800*1000).toISOString()); // 2015-10-16T17:00:00.000Z
So I'll assume that the PHP host is in a timezone that is UTC-05:00 and that 2015-Oct-17 has been treated as UTC.

I have checked it, and this JS function returns
1445036400
which in 'human time' is
Fri, 16 Oct 2015 23:00:00 GMT
https://jsbin.com/wuvawupede/edit?js,console,output
http://www.epochconverter.com/

Related

Why is JavaScript guessing two different timezones based on strings that are identical in structure?

I am providing dates two to my script in this format: 2016-05-25 12:30:02. However, JavaScript is setting the each date to a different GMT offset. I formatted the dates to match the suggested answer here and added the function provided, but I got the same results as shown below so I reverted back to my original script shown below.
var response = JSON.parse(jsonResponse);
var lastExportedOrderData = response.lastExportedOrder;
/* currentDateTime = '2016-05-25 12:30:02'; */
var currentDateTime = new Date(response.scriptExecutionTime);
/* lastOrderExportedAt = '2016-01-12 16:53:56'; */
var lastOrderExportedAt = new Date(lastExportedOrderData.exported_at);
currentDateTime Results: 2016-05-25 12:30:02 -> Wed May 25 2016 12:30:02 GMT-0400 (EDT)
lastOrderExportedAt Results: 2016-01-12 16:53:56 > Tue Jan 12 2016 16:53:56 GMT-0500 (EST)
I don't really care about the timezone so long as the dates are in the same timezone.
Update
My dates are now being input using the ISO-8601 Standard format but my the problem remains. 2016-05-25T14:04:00-05:00 results as GMT-0400 where 2016-01-12T16:53:56-05:00 results as GMT -0500
They're in the same timezone (U.S. Eastern). The difference is that the one in May is during Daylight Savings Time and thus is Eastern Daylight Time (EDT), and the one in January isn't, and thus is in Eastern Standard Time.
It's important to note that their underlying time values (e.g., as from dt.getTime()) are unaffected by timezone, and as both dates have been parsed (in your example) as local time, they can reliably be compared. You'd only run into an issue comparing them if one were parsed as local time and the other as UTC.
Side note: You're relying on new Date to parse those strings, which means you're relying on unspecified behavior that may vary from JavaScript engine to JavaScript engine. The only string format engines are required to support is a simplified version of ISO-8601, which those strings are not in. In particular, it's entirely possible that one browser's JavaScript engine will decide to parse them as though they were in UTC and another engine's browser will decide (as yours seems to have done) to parse them as local time.
You haven't said what timezone the strings are meant to be interpreted in, but if (for instance) they were meant to be UTC, you can fairly easily change them to be in ISO-8601 format by replacing the space between the date and time with a T, and adding a Z to the end:
str = str.replace(" ", "T") + "Z";
The resulting string, for instance "2016-05-25T12:30:02Z", is valid for new Date on any modern JavaScript engine (so, not IE8).
Alternately, if you know what timezone offset they should be interpreted in (say, GMT-05:00), you can replace the space with T and add a timezone offset to the end:
str = str.replace(" ", "T") + "-05:00";
That string (for instance, "2016-05-25T12:30:02-05:00") is also valid for new Date.
Alternately, get the parts of them:
var parts = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(str);
...and build the date/time yourself
// As local time
var dt = new Date(
+parts[1], // Year
+parts[2] - 1, // Month (0 = January)
+parts[3], // Day
+parts[4], // Hour
+parts[5], // Minute
+parts[6] // Second
);
or
// As UTC
var dt = new Date(Date.UTC(
+parts[1], // Year
+parts[2] - 1, // Month (0 = January)
+parts[3], // Day
+parts[4], // Hour
+parts[5], // Minute
+parts[6] // Second
));
The unary + on the above coerces from string to number. (It isn't strictly necessary, though, both new Date and Date.UTC do it for you.)
Just to add to TJ's answer, in implementations consistent with ES5 and later, the string 2016-05-25T14:04:00 will be parsed as a "local" time as it doesn't have a time zone offset. (In an ES2015-compliant browser. Sadly in the previous specification, they got that wrong and made it default to UTC, and currently Chrome implements the ES5 spec [UTC] but Firefox implements the ES2015 spec [local time].) But don't rely on that, parse the string per TJ's answer.
When creating a local time value, the host time zone settings are taking in to consideration. It seems that the host system is set for EST/EDT.
EDT starts at 02:00 on the second Sunday in March, so on 2016-01-12 US Eastern Standard Time (EST) applies which has an offset of -0500. For 2016-05-25, US Eastern Daylight Time (EDT) is used which has an offset of -0400.
Note that the actual time value of the Date created for 2016-05-25T12:30:02-0400 is for 2016-05-25T16:30:02Z (i.e. the equivalent UTC time). When displayed, the date's toString method is called which applies the host system offset for that time and date to adjust the displayed value to "local" time.
Date's use UTC internally so that they can be displayed in any time zone and still represent the same instant in time.

Why isn't "2016-02-16" equal to "2016-02-16 00:00"?

I'm trying to pass both date strings to new Date(t).
I expect both strings represent the same time, after all, if I omit the time, shouldn't it be midnight of that day?
But while,
new Date("2016-02-16 00:00")
returns 2016-02-16, midnight, local time as expected,
new Date("2016-02-16")
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
I would understand it if they would both have the same behavior, whether it is to return the time as local time, or as UTC, but it seems very inconsistent why they return different things like this.
As a workaround, whenever I encounter a date that has no corresponding timestamp I can append " 00:00" to get consistent behavior, but it seems like this is rather fragile.
I am getting this value from an INPUT element, of type 'datetime-local' so it seems especially inconsistent that I have to work around a value returned by a page element.
Am I doing something wrong, or should I be doing something differently?
It's what the ES5.1 specification says to do:
The value of an absent time zone offset is “Z”.
It also says:
The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
Since the format requires a T separator between date and time, the valid times go to UTC:
> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
...while in node.js, an invalid time (without the T separator) seems to go to the implementation specific localtime:
> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)
Note that ES6 changed this, in the same part of the documentation it changes to:
If the time zone offset is absent, the date-time is interpreted as a local time.
The joy of breaking changes.
Edit
According to TC39, the specification is meant to be interpreted as date and time strings without a time zone (e.g. "2016-02-16T00:00:00") are treated as local (per ISO 8601), but date only strings (e.g. "2016-02-16") as UTC (which is inconsistent with ISO 8601).
According to the specifications:
The function first attempts to parse the format of the String
according to the rules called out in Date Time String Format
(15.9.1.15). If the String does not conform to that format the
function may fall back to any implementation-specific heuristics or
implementation-specific date formats.
And Date Time String Formats accept 2016-02-16 as a valid date
This format includes date-only forms:
YYYY
YYYY-MM
YYYY-MM-DD
[...] If the HH, mm, or ss fields are absent “00” is used as the value
and the value of an absent sss field is “000”. The value of an absent
time zone offset is “Z”.
Thus 2016-02-16 translates to 2016-02-16T00:00:00.000Z.
The other date 2016-02-16 00:00 does not conform to the format and therefore its parsing is implementation specific. Apparently, such dates are treated as having local time zone and your example date will return different values depending on time zone:
/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z
Summary:
For conforming date time formats the behavior is well defined — in the absence of time zone offset the date string is treated as UTC (ES5) or local (ES6).
For non-conforming date time formats the behavior is implementation specific — in the absence of time zone offset the usual behavior is to treat the date as local.
As a matter of fact, the implementation could choose to return NaN instead of trying to parse non-conforming dates. Just test your code in Internet Explorer 11 ;)
You are perhaps running into a differences between ES5, ES6 implementations and your expected result. Per Date.parse at MDN, "especially across different ECMAScript implementations where strings like "2015-10-12 12:00:00" may be parsed to as NaN, UTC or local timezone" is significant.
Additional testing in Firefox 44 and IE 11 revealed they both return a date object for new Date("2016-02-16 00:00"), which object returns NaN when atttempting to get a date component value, and whose toString value is
"Invalid Date" (not "NaN"). Hence appending " 00:00 to get consistent behavior" can easily break in different browsers.
As noted in other answers new Date("2016-02-16") uses a timezone offset of zero by default, producing midnight UTC instead of local.
Per DateParser::Parse() of V8 source codes for Chrome.
ES5 ISO 8601 dates:
[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]
An unsigned number followed by ':' is a time value, and is added to the TimeComposer.
timezone defaults to Z if missing
> new Date("2016-02-16 00:00")
Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)
A string that matches both formats (e.g. 1970-01-01) will be parsed as an ES5 date-time string - which means it will default to UTC time-zone. That's unavoidable if following the ES5 specification.
> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
It adds the timezone offset to the 00:00
new Date("2016-02-16") outputs Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)
My timezone being IST with an offset value (in minutes) +330, so it added 330 minutes to 00:00.
As per ecma-262, section 20.3.3.2 Date.parse ( string )
If ToString results in an abrupt completion the Completion Record is
immediately returned. Otherwise, parse interprets the resulting String
as a date and time; it returns a Number, the UTC time value
corresponding to the date and time. The String may be interpreted as a
local time, a UTC time, or a time in some other time zone, depending
on the contents of the String.
When you explicitly set the time-units new Date("2016-02-16 00:00") it wll use set that as hours and minutes,
Otherwise as stated here in 20.3.1.16
If the time zone offset is absent, the date-time is interpreted as a
local time.

Prevent JavaScript from changing the time to GMT

The following outputs a time that is 4 hours less than what was input:
X = new Date('2015-07-09T14:18:12.430')
$('body').append(X)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
When you do no specify the timezone:
ECMAScript-5 compliant browsers will assume UTC timezone:
The value of an absent time zone offset is "Z".
ECMAScript-6 compliant browsers will assume local timezone:
If the time zone offset is absent, the date-time is interpreted as a
local time.
Use the long Date constructor which assumes local timezone:
var X = new Date(2015, 7 - 1, 9, 14, 18, 12, 430);
alert(X);
When you omit the timezone information on the end of an ISO 8601 formatted date-time the majority of computer implementations default to +0000, this means Date interprets 2015-07-09T14:18:12.430 the same as 2015-07-09T14:18:12.430+0000 or 2015-07-09T14:18:12.430Z
It looks like you were expecting it to be interpreted as your local time rather than in UTC, you have 3 options
Append your local timezone offset to the end
Write it differently so it will parse as you expect
Create a second Date using the details from the UTC fields of the first Date
function myParser(iso_style) {
var d = new Date(iso_style);
return new Date(
d.getUTCFullYear(),
d.getUTCMonth(),
d.getUTCDate(),
d.getUTCHours(),
d.getUTCMinutes(),
d.getUTCSeconds(),
d.getUTCMilliseconds()
);
}
You can't simply adjust by your local offset as you would experience unexpected behaviour if the time crosses a date that would change that offset e.g. a daylight savings boundry
As Salman A's answer points out the current ES 6 Draft defines that an omitted timezone should be interpreted as meaning the client's local timezone. This will make the behaviour inconsistent as different JavaScript implementations change over so I strongly recommend you always use a timezone when writing ISO 8601.
A quick and dirty workaround:
X = new Date('2015-07-09T14:18:12.430');
$('body').append( X.toString().split('GMT')[0] );
It works by turning the date object into a string, then splitting it into an array around the pattern GMT. So you would have 2 elements in the array: Thu Jul 09 2015 10:18:12 and 0400 (EDT). Since you want to drop everything after the GMT, you just use the element in the 0 index of the array
I misunderstood the question. If you use X.toUTCString(), it may fix your issue.

JavaScript Date formatting and conversion issue

I'm located in PST timezone and I want to be able to take the string "2014-01-01" and convert it into Unix time without "2014-01-01" getting converted to PST.
Here's what I'm doing:
Date.parse(new Date("2014-01-01"))
I'm getting the value 1388534400000 which is equivalent to Tue Dec 31 2013 16:00:00 GMT-0800 (Pacific Standard Time)
I want to take the date as "2014-01-01" and not convert it into PST before converting it into Unix time.
A few things:
The Date constructor returns a Date object, not a string. You shouldn't wrap it in a call to Date.parse.
If you want a unix timestamp, just call getTime().
var ts = new Date("2014-01-01").getTime();
Alternatively, you can parse the date string without creating a Date object at all.
var ts = Date.parse("2014-01-01");
The behavior of date parsing in JavaScript is implementation dependent. Most browsers will already interpret a yyyy-mm-dd string to be in UTC, due to the dashes (-). If you replace with with slashes (/), you'll see the string get interpreted as local time instead.
I think you're confused about the output. You said the timestamp was equivalent to PST, but that's just one representation. It's also equivalent to the UTC value you passed in. It's not getting converted in the input, it's being converted when you are converting the timestamp back to local time.
You can use a library like moment.js, which gives you full control of the input and output. This is usually the best option, but has the overhead of including a library in your application.
Another way to convert the specified date string to Unix time is as follows:
var str = "2014-01-01";
var parts = str.split('-');
parts[1] -= 1; // js numeric mos are 0-11
var ms = Date.UTC( parts[0], parts[1], parts[2] ); // parts: YYYY, MM, DD
var unix_time = ms/1000; // Unix time uses seconds
console.log("Unix time: " + unix_time);
Date.UTC() returns the number of milliseconds occurring since January 1, 1970 midnight up to the instant of the specified date, irrespective of any timezone. The script transforms the result into Unix time, i.e. seconds, by dividing the number of milliseconds by 1000.
After splitting the string into an array, the code adjusts the element containing the month, lest JavaScript mistake its value for March; JavaScript comprehends numeric months as ranging from 0-11, not 1-12. Next, the script passes the elements sequentially in accordance with the year, month, day parameters that Date.UTC requires. Although UTC() expects numbers for parameters, it accepts the numerical strings.
Note: if you first create a new date object and expect to use a UTC method -- that results in an error because it is a static method of JavaScript's Date Object.
You may check the validity of the UTC() return value, using the aforementioned variables ms and str, as follows:
console.log( new Date( str ).toUTCString( ms ));
The output: Wed, 01 Jan 2014 00:00:00 GMT
See live demo here)
Passing a date string to the Date constructor instead of the numerical parameters it expects affords an unexpected benefit; the date string is treated as if it's timezone is UTC, i.e. zero by the local date object. Once created, the local date object executes its toUTCString() method to attain the above-indicated result. The toString() method would also yield the same output, but it appends local timezone information.

json and Utc datetime

I'm storing Utc datetime on the server and requesting data via json to display on client.
The problem is that the server returns the time by its timezone which is different to a client.
How could I get the local dateTime to display on client without hardcoding the offset?
I'm using asp.net mvc and stroring date and time in SQL Server 2008 database as 'datetime'. DateTime format in database is 2013-03-29 08:00:00.000.
You don't say how the UTC time is represented. It's common to use a UNIX time value that is seconds since 1970-01-01T00:00:00Z. If that is what you are using, you can create a date object on the client by multiplying by 1,000 and giving it to the Date constructor:
var unixTimeValue = '1364694508';
var clientDateObject = new Date(unixTimeValue * 1000);
If you are using say .NET, the value may already be in milliseconds so you don't need to multiply by 1,000. You need to check with the source to see what value is passed and what epoch is used if it's a time value.
Javascript date objects are based on a time value that is the same epoch as UNIX, but uses milliseconds. The standard Date methods (getFullYear, getMonth, getDate, etc.) will return values in the local timezone based on system settings. The UTC methods (getUTCFullYear, getUTCMonth, getUTCDate, etc.) return UTC values for the same time.
So if you are passing a time value, use it to create a date object on the client and read the values using standard methods and you have local equivalents of the UTC time value.
If you are passing a datetime string like 2013-03-31T14:32:22Z, you can convert that to a date object using Date.UTC to convert the string to a time value, then give that to the date constructor:
function dateFromUTCString(s) {
s = s.split(/[-T:Z]/ig);
return new Date(Date.UTC(s[0], --s[1], s[2], s[3], s[4], s[5]));
}
var s = '2013-03-31T14:32:22Z';
alert(dateFromUTCString(s)); // Mon Apr 01 2013 00:32:22 GMT+1000 (EST)
If your input string is a different format, you may need to adjust the split pattern and order of parameters passed to Date.UTC.
Edit
If the string format is 2013-03-29 08:00:00.000 (assuming UTC), you can use:
function dateFromUTCString(s) {
s = s.split(/[\D]/ig);
return new Date(Date.UTC(s[0], --s[1], s[2], s[3], s[4], s[5], s[6]||0));
}
var s = '2013-03-29 08:00:00.000';
alert(dateFromUTCString(s)); // Fri Mar 29 2013 18:00:00 GMT+1000 (EST)
But be careful of additional spaces. You might want to trim any leading or trailing spaces and ensure there is only one separating the date and time components.
Edit 2
Don't use Date.parse. Until ES5 it was completely implementation dependent. Now it's partially standardised if the string complies with the ISO8601–like format specified by ES5. But that isn't supported by all browsers in use, so not reliable and is otherwise still implementation dependent. The best solution (i.e. one that will work everywhere) is to manually parse the value you are given.
If the format is like: "1364835180000-0700", then you can fairly easily deal with that using a function that subtracts the offset to get UTC time value, the gives that to the date constructor. I'm assuming that -0700 means 7hrs west of Greenwich (javascript timezone offsets have an opposite sense, west of Greenwich is +ve).
Edit 3
Sorry, must have posted the wrong snipped, rushing to a meeting.
// Where s is a time value with offset
function toDate(s) {
// Include factor to convert mins to ms in sign
var sign = s.indexOf('-') > -1? 6e4 : -6e4;
s = s.split(/[\+\-]/);
var l = s[1].length;
// Convert offset in milliseconds
var offset = sign*s[1].substring(l-2,l) + sign*s[1].substring(l-4, l-2)*60;
// Add offset to time value to get UTC and create date object
return new Date(+s[0] + offset);
}
var s = "1364835180000-0700"
alert(toDate(s)); // Tue Apr 02 2013 09:53:00 GMT+1000 (EST)
Return the DateTime as UTC and convert it on the client using .toLocaleString():
#ViewBag.Time = Model.Time.ToUniversalTime().Ticks / TimeSpan.TicksPerMillisecond
<script>
var time = new Date(#ViewBag.Time);
var localTimeString = time.toLocaleString();
alert(localTimeString);
</script>

Categories