Javascript Parsed Date [duplicate] - javascript

This question already has an answer here:
HTML Input type datetime-local setting the wrong time-zone
(1 answer)
Closed 7 years ago.
I'm writing a MVC 5 web application. Into this, I have multiple lists that I propagate and manage through javascript and jquery (one dataset, dependent select controls, and adding ajax callbacks would complicate it unnecessarily.)
The issue I have is: I have a hidden for field formatted to ISO 8601. I run into issues when I display the date in the user's local time, I get a shifted date.
So if the date were stated as: 01-01-2009 (in iso 8601 format: 2009-01-01), the user sees: 12-31-2008.
When I parse the date I'm using:
this.date = new Date(Date.parse(originalString));
/* ^- Date.parse is giving me a number. */
To display the text of the date I am using:
admin.date.toLocaleDateString().Concat(...
Do I need to do any sort of patch-up to adjust things to the proper time-zone? The date, when using console.log(admin.date); shows the original 2009-01-01
I'm thinking there's some parameter I'm not specifying correctly in the toLocaleDateString, but my familiarity level with it is low.
Edit: The goal is to prevent the date shift. All we store is the date, the time aspect is dropped. We have multiple time-zones posting to this database, and the goal is: We use the date of the person who posted it, time dropped. Were the date May 01, 2015, I want anyone who sees that date to see May 01, 2015, the 'toLocaleDateString' is merely a means to get it to appear format correct for their region. So someone who views dates as yyyy-mm-dd will see it properly.

Based on the documentation for Date.parse:
The Date.parse() method parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
You are getting back the epoch time in UTC for your parsed date string hence why the date is off for local times. So, you would need to know the time difference between the local time and UTC which Date.getTimezoneOffset provides (in minutes) in order to set the correct date for the local time:
> var date = new Date(Date.parse('2009-01-01'));
undefined
> date;
Wed Dec 31 2008 19:00:00 GMT-0500 (EST)
> date.getTimezoneOffset();
300
> date.setMinutes(date.getTimezoneOffset());
1230786000000
> date;
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
One thing to note though is:
...the offset is positive if the local timezone is behind UTC and negative if it is ahead.
So you might need to take care for locales where the value is negative if this applies to your application. If so maybe just omitting negative values would be enough since the date should be the same if a locale's timezone is ahead of midnight UTC.
EDIT: To compensate for possible issues with daylight savings time:
> var dateVals = String.prototype.split.call('2009-01-01', '-');
undefined
> var date = new Date(dateVals[0], dateVals[1] - 1, dateVals[2]);
undefined
> date
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)

Related

Why does Javascript show me the wrong date?

Consider the following date object which is created in JavaScript.
var date = new Date("2017-09-07T16:46:06.000Z");
This date object should be equivalent to Sep 7 2017 4:46:06 PM
However, in the browser console, when I type the following:
console.log(date);
The following is returned:
Fri Sep 08 2017 02:46:06 GMT+1000 (E. Australia Standard Time)
The time is wrong. (It actually is today's date, but the time is completely wrong).
Key points of confusion:
My computer timezone is set to GMT+1000 (Australia/Brisbane)
When I created the date object, I did not specify the timezone, therefore it should conform to my systems timezone
When I log the date object to the console, it is still using GMT+1000 (Australia/Brisbane) but the date is different
When you created the date, you did specify a timezone. That Z at the end means Zulu or Greenwich Mean Time. Your computer is 10 hours off from GMT, so it adjusts to your local timezone for display.
If you want the date to be in your local time zone, remove the Z
var date = new Date("2017-09-07T16:46:06.000Z");
So it looks like the Z at the end of your date string is meant to represent UTC or Zulu time
var date = new Date("2017-09-07T16:46:06.000");
should be the correct solution

Match the dates in jQuery with different formats

I have div in which I am providing date and time like this
<div class="timing">
<div id="count-down" data-date="2016-08-31 14:21:00"> </div>
</div>
How would I match or compare with current date, because I am getting current date in this format Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)
I want to redirect a page to new location if current date is greater than provided date
var currentDate = new Date();
var providedDate = $('#count-down').attr('data-date')
if (currentDate.getDate().toString > providedDate)
{
window.location.href = 'Promo';
$('.timing').css("display", "none");
$('.website-loading').css("display", "block");
}
I have div in which I am providing date and time like this
<div id="count-down" data-date="2016-08-31 14:21:00"> </div>
The string in the data- attribute is not consistent with the format specified in ECMA-262 (the "T" separator between the date and time is missing), so you should manually parse it by either writing a parsing function or use a library and provide the format to parse.
If you use the Date constructor (or Date.parse, they are equivalent for parsing) to parse the string, you may get an invalid date (e.g. in Safari, new Date('2016-01-01 12:00:00') produces an invalid date) since parsing of non–standard strings is entirely implementation dependent.
There are many suitable libraries, some suggestions:
moment.js does parsing, formatting, timezones and arithmetic and has a CDN
fecha.js just does parsing and formatting is very much smaller than moment.js
When you create a Date object, it only has one internal value (called its time value), which is milliseconds since 1970-01-01T00:00:00Z (the javascript epoch, which is the same as the UNIX epoch). When you call the toString method, the result is an implementation dependent string that differs between implementations (in your case you see something like "Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)", a different implementation may produce something else.
How would I match or compare with current date, because I am getting
current date in this format Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)
When comparing dates, you really just want to compare the time value. If you compare using the relational operators > or <, they will coerce the dates to their time value so you can compare the dates directly, e.g.:
var providedDate = fecha.parse($('#count-down').attr('data-date'), 'YYYY-MM-DD HH:mm:ss');
if (Date.now() > providedDate) {
// providedDate is in the past
}
Note that since no time zone information is provided in the string to parse, it's treated as a "local" date and time and the host system's current settings are used to determine the offset from UTC, which is then used when calculating the time value. The same system works in reverse when generating a local date and time string from the Date using the default toString method.
Also:
currentDate.getDate()
just returns the date (i.e. the day in the month) as a number without the year and month.

Javascript epoch date incorrect

I am doing some javascript date stuff, and I executed the following:
console.log(new Date(0));
I expected to see the *nix Epoch, but I was oddly returned:
Wed Dec 31 1969 19:00:00 GMT-0500 (Eastern Standard Time)
What happened?
You are setting the internal time value, which is UTC, but seeing a string that is based on your system settings, which likely have an offset of UTC-05:00.
The ECMAScript specification explains how the Date constructor and instances work. Given:
new Date(0)
the Date constructor is called with one argument (§20.3.2.2 Date(value)) so it creates a Date instance with it's internal time value set depending on the type of argument. As the value is a number, the time value is set to that number.
The time value is an offset in milliseconds from 1970-01-01T00:00:00Z §20.3.1.1 Time Values and Time Range. Note that it's based on UTC.
The behaviour of console.log is entirely implementation dependent, so what you get from:
console.log(dateInstance);
depends on the host. However, most seem to call the object's toString method which returns an implementation dependent string based on the timezone setting for the host system (§20.3.4.41 Date.prototype.toString()). That is, a "local" time.
The timezone offset can be determined using getTimezoneOffset. It's in minutes and has the opposite sense to an ISO 8601 offset (e.g. UTC-05:00 will be +300). If you want to get a date string that represents the internal time value without an offset, use toUTCString.
I was unable to find any resources explaining it, but this 'error' is due to my timezone (as far as I can tell)
My timezone is GMT-0500, which is 5 hours behind UTC time. Add 5 hours to Wed Dec 31 1969 19:00:00 and you get the Epoch (Thurs Jan 1 1970 00:00:00)

Why does js subtract a day from a Date object with a certain format?

I get dates from the database in this format:
yyyy-mm-dd
When I create a javascript Date object using this string, it builds a day before the date.
You can test this in your console:
var d = new Date("2015-02-01");
d
You will get January 31st! I've tested many theories, but none answer the question.
The day is not zero-based, otherwise it would give Feb 00, not Jan 31
It's not performing a math equation, subtracting the day from the month and/or year
Date(2015-02-01) = Wed Dec 31 1969
Date("2015-01") = Wed Dec 31 2014
It is not confusing the day for the month
Date("2015-08-02") = Sat Aug 01 2015
If this were true the date would be Feb 08 2015
If you create a Date using a different format, it works fine
Date("02/01/2015") = Feb 1st, 2015
My conclusion is that js does this purposefully. I have tried researching 'why' but can't find an explanation. Why does js build dates this way, but only with this format? Is there a way around it, or do I have to build the Date, then set it to the next day?
PS: "How to change the format of the date from the db" is not what I'm asking, and that is why I'm not putting any db info here.
Some browsers parse a partial date string as UTC and some as a local time,
so when you read it the localized time may differ from one browser to another
by the time zone offset.
You can force the Date to be UTC and add the local offset if you
want the time to be guaranteed local:
1. set UTC time:
var D= new Date("2015-02-01"+'T00:00:00Z');
2. adjust for local:
D.setMinutes(D.getMinutes()+D.getTimezoneOffset());
value of D: (local Date)
Sun Feb 01 2015 00:00:00 GMT-0500 (Eastern Standard Time)
Offset will be whatever is local time.
Some differences between browsers when time zone is not specified in a parsed string:
(tested on Eastern Standard Time location)
(new Date("2015-02-01T00:00:00")).toUTCString();
Firefox 35: Sun, 01 Feb 2015 05:00:00 GMT
Chrome 40: Sun, 01 Feb 2015 00:00:00 GMT
Opera 27: Sun, 01 Feb 2015 00:00:00 GMT
IE 11: Sun, 01 Feb 2015 05:00:00 GMT
IE and Firefox set the Date as if it was local, Chrome and Opera as if it was UTC.
In javascript, Date objects are internally represented as the number of milliseconds since Jan 1st 1970 00:00:00 UTC. So instead of thinking of it as a "date" in the normal sense, try thinking of a Date object as a "point in time" represented by an integer number (without timezone).
When constructing your Date object using a string, you are actually just calling the parse function. Most date time formats (including ISO 8601) allow you to reduce the precision of a date string.
For reduced precision, any number of values may be dropped from any
of the date and time representations, but in the order from the least
to the most significant.
e.g. 2015-02-01 would represent the day February 1st 2015.
This causes a dilemma for javascript because a Date object is always accurate to the millisecond. Javascript cannot store a reduced accuracy date since it is just an integer of milliseconds since 1st Jan 1970. So it does the next best thing which is to assume a time of midnight (00:00:00) if not specified, and a timezone of UTC if not specified.
All valid javascript implementations should give the same result for this:
var d = new Date("2015-02-01");
alert(d.getTime());
1422748800000
The out-by-1-day issue comes when outputting the date either to some (often unclear) debugger or using the getter methods because the local timezone is used. In a browser, that will be your operating systems timezone. Anyone "west" of Greenwich Mean Time may see this problem because they have a negative UTC offset. Please note there are UTC equivalent functions too which use the UTC timezone, if you are really just interested in representing a date rather than a point in time.

Stop javascript Date function from changing timezone offset

So I have iso date time that need to be converted from a string to date object. How do I keep date from converting it to local browser timezone.
new Date('2013-07-18T17:00:00-05:00')
Thu Jul 18 2013 18:00:00 GMT-0400 (EDT)
I want to get
Thu Jul 18 2013 17:00:00 GMT-0500 (XX)
While MomentJS is a great library, it may not provide a solution for every use case. For example, my server provides dates in UTC, and when the time portion of the date is not saved in the db (because it's irrelevant), the client receives a string that has a default time of all zeros - midnight - and ends with an offset of +0000. The browser then automatically adjusts for my local time zone and pulls the time back by a few hours, resulting in the previous day.
This is true with MomentJs as well.
One solution is to slice off the time portion of the string, and then use MomentJS as described in the other answers.
But what happens if MomentJS is not a viable option, i.e. I already have many places that use a JS Date and don't want to update so many lines of code? The question is how to stop the browser from converting dates based on local time zone in the first place. And the answer is, when the date is in ISO format, you cannot.
However, there is no rule that says the string you pass to JavaScript's Date constructor must be in ISO format. If you simply replace the - that separates the year, month, and day with a /, your browser will not perform any conversion.
In my case, I simply changed the format of the Dates server-side, and the problem was solved without having to update all the client-side JS dates with MomentJS.
Note that the MDN docs for JavaScript's Date class warn about unpredictable browser-behavior when parsing a string to create a Date instance.
You cannot change this behavior of Javascript because it is the only simple way for Javascript to work. What happens is simply that Javascript looks at the time shift, computes the matching timestamp, and then asks the OS for the representation of this timestamp in the local time zone. What is key to understand here is that -05:00 is not an indication of time zone but simply a shift from UTC.
Time zones are complex beasts that are just arbitrary political decisions. The OS provides a service to display time in the local time zone, but not in other time zones. To do that you have to take in account things like DST that are pretty much a hell.
As always with time management, the only decent way to tackle this problem is to use a dedicated library. In Javascript, you'll find Moment.js and Moment.Timezone.js very helpful.
Example http://codepen.io/Xowap/pen/XKpKZb?editors=0010
document.write(moment('2013-07-18T17:00:00-05:00').tz('America/New_York').format('LLL'));
As a bonus, you get a ton of formatting/parsing features from Moment.js.
Please also note that as long as you use the ISO 8601, your date can be pinpointed to a precise moment, and thus be displayed in any timezone of your liking. In other words, JS "converting" your date doesn't matter.
You can use a library such as Moment.js to do this.
See the String + Format parsing.
http://momentjs.com/docs/#/parsing/string-format/
The following should parse your date you provided, but you may need to modify it for your needs.
var dateString = "2013-07-18T17:00:00-05:00";
var dateObject = moment(dateString, "YYYY-MM-DDTHH:mm:ssZ").toDate();
Alternatively, see Moment's String parser, which looks like it is in the format you provided, with the exception of a space between the seconds of the time and the time zone.
http://momentjs.com/docs/#/parsing/string/
This is an old question that recently got linked in an answer to a newer question, but none of the existing answers seem to fully address the original question.
In many cases the easiest way to format and display a datetime string in the time zone that it is received, is not to convert the string to a Date object at all. Instead, just parse the datetime string and recombine the parts into the desired format. For example, if you can live without the day of the week in the output requested in the question, you could do something like the following to handle the requested input and output format (including the day of the week adds enough complexity that it might be worth using a library at that point). Of course, this approach requires modification based on the format of the datetime strings you are receiving on the client side.
const months = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'};
const format = (datetime) => {
const [date, time] = datetime.split('T');
const [y, m, d] = date.match(/\d+/g);
const [t, tz] = time.split(/(?=[+-])/);
return `${months[Number(m)]} ${d} ${y} ${t} GMT${tz}`;
};
const dt = format('2013-07-18T17:00:00-05:00');
console.log(dt);
// Jul 18 2013 17:00:00 GMT-05:00
There are JavaScript and other library methods that will allow you to convert your datetime string to a Date instance and then display it in a specific time zone if you are consistently receiving datetime strings from one or a few specific time zones that are easily identified on the client side. Following are a couple of examples.
toLocaleString enables you to display a date in a specific time zone but the options parameters required to set the time zone are not supported across all browsers (as of the date of this answer). For example (note that parsing of date strings with the Date constructor is still discouraged, but most modern browsers will handle an ISO 8601 format string like the one below):
const dt = new Date('2013-07-18T17:00:00-05:00');
const ny = dt.toLocaleString('en-US', { timeZone: 'America/New_York' });
console.log(`Local: ${dt}`);
console.log(`New York: ${ny}`);
You could also use Moment.js with Moment Timezone to display a date in a specific time zone. For example:
const ny = moment('2013-07-18T17:00:00-05:00').tz('America/New_York').format();
console.log(`New York: ${ny}`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>
It is important to note the following when working with datetime strings and time zones in JavaScript. The JavaScript Date constructor DOES NOT change the time zone offset. When you create a date from a string using ISO 8601 format as in the question example, Date does the following:
Creates a JavaScript Date instance that represents a single moment in
time. Date objects use a Unix Time Stamp, an integer value that is the
number of milliseconds since 1 January 1970 UTC.
In other words, JavaScript Date instances do not store (or change) time zone offsets. The reason you often see output from a JavaScript Date in your local time zone is that toString is the default method called when you log a Date instance to the console (or use various other approaches to output your date). In most browser implementations, this method relies on the browser's local time zone to convert the number of milliseconds since 1 January 1970 UTC into a string representation of the date.
Wonder if this would help:
function goAheadMakeMyDate(s){
var d = new Date(s);
// override Date.toString()
d.toString = function(){ return ''+s; };
return d;
}
var example = goAheadMakeMyDate("Fri 19 July 2013 12:00:00 GMT");
example.toString() // returns string actually used to construct the date
'Fri 19 July 2013 12:00:00 GMT'
example.toLocaleString()
'Fri Jul 19 2013 08:00:00 GMT-0400 (EDT)'
1*example // gives seconds since epoch
1374235200000
With your input:
example = goAheadMakeMyDate('2013-07-18T17:00:00-05:00')
{ Thu, 18 Jul 2013 22:00:00 GMT toString: [Function] }
> example.toString()
'2013-07-18T17:00:00-05:00'
> example.toLocaleString() // I live in GMT-4
'Thu Jul 18 2013 18:00:00 GMT-0400 (EDT)'
> 1*example // convert to integer date
1374184800000
However, if you start modifying this date, the toString will not change and will bite you.
I have a scenario where date time stamp needs to update only once. In detail I have button in my application and when clicked on it will generate a PDF along with timestamp footer and when refreshed it should not change date time.
For the above scenario I have used localStorage.setItem('','') and getItems. In precise.... when clicked on generate button I have used localStorage.setItem('','') and in the generating footer logic I have used localStorage.getItem('') dats it....
Explanation for above logic:
Whenever we are generating I am setting current date time and when generating am calling getItem which will pick the set date time from local storage.
This will reset again when clicked on Generate button.
Hope this helps someone in need..... :-)

Categories

Resources