new Date(...) adds a month forward - javascript

I'm developing with node.js, and I'm trying to create a date object on the server.
when coding:
var birthyear = 2000;
var birthmonth = 7;
var birthday = 24;
var date = new Date(birthyear, birthmonth, birthday);
console.log(date);
OUTPUT:
Thu Aug 24 2000 00:00:00 GMT+0300 (Jerusalem Daylight Time)
As you can see, I'm getting August instead of July.
How can I fix that issue ?

The month argument in the Date() constructor doesn't start at 1 for January, but instead at 0. Therefore, supplying the month value of 7 gives you the eight month, which is August.
From MDN:
month: Integer value representing the month, beginning with 0 for January to 11 for December.

Months in JS start at 0
so it's a quite an easy fix:
var date = new Date(birthyear, birthmonth-1, birthday);
DEMO

Months in the JavaScript Date() constructor are 0-indexed, meaning that month 7 actually is August. Use the value 6 for July.
Annoyingly enough, Date is rather inconsistent about which fields are 0-indexed and which are 1-indexed, and in fact the same field can be either one depending on the context. You should always refer to documentation when you have to use dates.

Yea, that's weird, but months should be counted starting with
0

Related

Javascript dates: a nightmare

I understand that dealing with dates, in any environment, could be quite confusing, but I'm in a nightmare with a function that should be a trivial job.
I want to manipulate in different ways some dates, but I get errors or wrong results.
I report hereafter a very simple example made to test the execution; the goal here is to get the current month beginning date, just to show what happens:
function DateAdjust() {
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate = newdate.setDate(1); //2: 1543698020099
newdate=Date(newdate); //3: Wed Dec 12 2018 21:01:43 GMT+0000 (Ora standard dell’Europa occidentale)
var d = newdate.getDate(); //4: newdate.getDate is not a function
}
4 lines, 3 unexpected results (as shown by Firefox's debugger):
1. the starting date has no day-of-week and no timezone
2. setting the day, result is transformed in milliseconds (why?); I do not know if it is correct.
3. reconverting in string gives the original date, unmodified (why?) but with week day and timezone
4. trying to get the day value an error is thrown (why?)
My environment:
Win 7 32bits SP1
Firefox 63.0.3 (32 bit)
jquery-2.2.4.min.js
I know these questions are boring, but hope someone will find few minutes to clear my mind.
Regarding line 1, the Z at the end is the timezone designation for UTC in ISO 8601 (see Wikipedia).
If the time is in UTC, add a Z directly after the time without a space. Z is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".
Regarding line 2 see the MDN article on setDate (emphasis mine):
The number of milliseconds between 1 January 1970 00:00:00 UTC and the given date (the Date object is also changed in place).
So you can see the 'correct' behavior you probably expect simply by ignoring the return value:
var newdate = new Date(); //1: 2018-12-12T21:00:20.099Z
newdate.setDate(1); //2: 1543698020099
console.log(newdate); //3: 2018-12-01T21:00:20.099Z
Regarding line 3, see MDN article on Date (emphasis mine):
Note: JavaScript Date objects can only be instantiated by calling
JavaScript Date as a constructor: calling it as a regular function
(i.e. without the new operator) will return a string rather than a
Date object; unlike other JavaScript object types, JavaScript Date
objects have no literal syntax.
Regarding line 4, the above also explains this error, since newdate is now a string rather than a Date object.
For what it's worth, I agree with the other commenters. JavaScript's date functions are pretty messy compared to many other modern languages. I strongly recommend using a library like moment, luxon, or date-fns. It'll make your life much easier.
I do recommend using moment.js
But there are 2 problems with your code:
1-
newdate = newdate.setDate(1);
setDate mutates newDate in place, and return it in miliseconds, not a new Date object. If you just want to set the date, do this instead:
newdate.setDate(1);
2-
newdate=Date(newdate);
Not realy sure why you are trying to get a new Date object, but you need the new, otherwise it will just be a string
newdate= new Date(newdate);
Fixing problem 1 should eliminate the need for the code of problem 2
var newdate = new Date(); // 1
console.log(typeof newdate, newdate); // object Wed Dec 12 2018 23:00:44 GMT+0200 (Eastern European Standard Time)
newdate = newdate.setDate(1); // 2
console.log(typeof newdate, newdate); //number 1543698085383
newdate=Date(newdate); //3
console.log(typeof newdate, newdate); //string Wed Dec 12 2018 23:04:44 GMT+0200 (Eastern European Standard Time)
var d = newdate.getDate(); // 4
console.log(typeof d, d); //
Date type is assigned to the object.
number is assigned to newdate. which is ticks
returns string
string.getDate() is not defined, so undefined.
hope it helps.

How does minus integer work in Date?

How does javascript Date interpret the milisecond integers?
var d = new Date(-1724115600000); //this gives me a date in the past, which I want
console.log(d);
var d = new Date(1724115600000);
console.log(d);
(we had a bug where the - sign was not getting through. But I dont understand the significance of the -)
The Date object constructor can take a variety of inputs, but when called in this fashion it's using the integer value one:
Integer value representing the number of milliseconds since 1 January 1970 00:00:00 UTC (Unix Epoch).
Negative values will give dates before the Unix Epoch, positive values are dates after the Epoch.
0 would be 1. January 1970. The delta is given as an unsigned number representing milliseconds. If you want dates before that you need to use negative values in milliseconds.
The negative number you provided will give a number in the past, the other one in the future:
Date 1915-05-14T23:00:00.000Z
Date 2024-08-20T01:00:00.000Z
If you got one in the past with the second number it may have been missing the last digit when your tried. In that case it would give:
Date 1975-06-19T12:06:00.000Z
var d = new Date(-1724115600000); //this gives me a date in the past, which I want
document.write(d + "<br>");
var d = new Date(1724115600000); //This gives me a date in the past too.
document.write(d + "<br>");
var d = new Date(172411560000); //missing last digit
document.write(d);
//negative sign give you the date before 1970. in your example
var d = new Date(-1425223942000);// this gives date in the past
document.write(d) //Sun Nov 02 1924 03:27:38 GMT-0500 (Eastern Standard Time)
document.write('<br/>')
var d = new Date(1425223942000); //This gives date in th future.
document.write(d); // Sun Mar 01 2015 10:32:22 GMT-0500 (Eastern Standard Time)
//Unfortunately i cannot post the screenshots yet

JavaScript date returns wrong month if day is 01

I am trying to get correct month from the date string, this works fine as long as the day isn't the first of the month (01). If the day is the first, it returns the previous month:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to display the month.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
var str="2014-12-01"
var d = new Date(str);
var m = d.getMonth()+1;
document.getElementById("demo").innerHTML = m;
}
</script>
</body>
</html>
Returns: 11
Should return: 12
If the date string was 2013-8-01 then 7 would be returned, when it should be 8. Without the +1 after the getMonth() then 6 would be returned, instead of 7.
The actual problem lies within the timezone of your computer.
Suppose that your computer is in Eastern Time (GMT-5):
var foo = new Date('2014-12-01');
foo.toUTCString(); // "Mon, 01 Dec 2014 00:00:00 GMT"
foo.toISOString(); // "2014-12-01T00:00:00.000Z"
foo.toString(); // "Sun Nov 30 2014 19:00:00 GMT-0500 (Eastern Standard Time)"
Notice that the date is actually in November because it's a few hours behind, and therefore the zero-indexed month would be 10. JavaScript automatically assumes UTC when you do not provide a time string.
The getMonth() method returns the month in the specified date according to local time, as a zero-based value (where zero indicates the first month of the year.
In local time, this Date object represents November 30 at 19h00 (7pm), so getMonth() returns 10:
foo.getMonth(); // 10
foo.getUTCMonth(); // 11
If you are not concerned about time zones and are just dealing with dates, perhaps look into using the getUTC* methods.
You can read more about the Date object here. Hope this helps.
JavaScript is doing what it should do. In the day value it interprets the 01 as 0, and a zero value for the day is interpreted as the last day of the previous month. It's like asking for day 32 in a month with 31 days. That would return a date of the first of the next month.
getMonth() returns a value from 0 to 11: http://www.w3schools.com/jsref/jsref_getmonth.asp
January is 0, February is 1, and so on.
So to get the 'right' month, you should do +1.

Why is Date("2014-04-07") parsed to Sat Apr 05 2014 17:26:15 GMT-0500 (CEST)?

I'm creating dates like this:
var StartDate = new Date(data.feed.entry[i].gd$when[j].startTime);
When a date string is received specifying date and time in the form:
"2014-04-12T20:00:00.000-05:00"
Date() interprets this perfectly fine returning:
Sat Apr 12 2014 19:00:00 GMT-0500 (CDT)
However, when the date string is received with no time information in the form:
"2014-04-07"
then Date() is interpreting it as:
Sat Apr 05 2014 19:00:00 GMT-0500 (CDT)
Looks like Date() is taking the -07 as the time and I have no clue where is it getting the date as 05. Any idea what might be the problem?
Could it be, somehow, Date() is interpreting a different time zone because in the first string the time zone is determined at the very end but in the "all day" event there is no indication of the time zone.
Has anybody found this issue? If yes, how did you solve it?
UPDATE: After researching a little bit more this parsing issue I noticed something very weird:
The following statement:
new Date("2014-4-07")
would return Mon Apr 07 2014 00:00:00 GMT-0500 (CDT) which is correct, but the following one:
new Date("2014-04-07")
returns Sun Apr 06 2014 19:00:00 GMT-0500 (CDT) which is the wrong one. So, for whatever reason, seems like the padding zeros affect the way the date is parsed!
You're using the Date() function wrong.
It only accepts parameters in the following formats.
//No parameters
var today = new Date();
//Date and time, no time-zone
var birthday = new Date("December 17, 1995 03:24:00");
//Date and time, no time-zone
var birthday = new Date("1995-12-17T03:24:00");
//Only date as integer values
var birthday = new Date(1995,11,17);
//Date and time as integer values, no time-zone
var birthday = new Date(1995,11,17,3,24,0);
Source: MDN.
The Date() function does not accept timezone as a parameter. The reason why you think the time-zone parameter works is because its showing the same time-zone that you entered, but that's because you're in the same time-zone.
The reason why you get Sat Apr 05 2014 19:00:00 GMT-0500 (CDT) as your output for Date("2014-04-07" ) is simply because you used it in a different way.
new Date(parameters) will give the output according to the parameters passed in it.
Date(parameters) will give the output as the current date and time no matter what parameter you pass in it.
Prior to ES5, parsing of date strings was entirely implementation dependent. ES5 specifies a version of ISO 8601 that is supported by may browsers, but not all. The specified format only supports the Z timezone (UTC) and assumes UTC if the timezone is missing. Support where the timezone is missing is inconsistent, some implementations will treat the string as UTC and some as local.
To be certain, you should parse the string yourself, e.g.
/* Parse an ISO string with or without an offset
** e.g. '2014-04-02T20:00:00-0600'
** '2014-04-02T20:00:00Z'
**
** Allows decimal seconds if supplied
** e.g. '2014-04-02T20:00:00.123-0600'
**
** If no offset is supplied (or it's Z), treat as UTC (per ECMA-262)
**
** If date only, e.g. '2014-04-02', treat as UTC date (per ECMA-262)
*/
function parseISOString(s) {
var t = s.split(/\D+/g);
var hasOffset = /\d{2}[-+]\d{4}$/.test(s);
// Whether decimal seconds are present changes the offset field and ms value
var hasDecimalSeconds = /T\d{2}:\d{2}:\d{2}\.\d+/i.test(s);
var offset = hasDecimalSeconds? t[7] : t[6];
var ms = hasDecimalSeconds? t[6] : 0;
var offMin, offSign, min;
// If there's an offset, apply it to minutes to get a UTC time value
if (hasOffset) {
offMin = 60 * offset / 100 + offset % 100;
offSign = /-\d{4}$/.test(s)? -1 : 1;
}
min = hasOffset? +t[4] - offMin * offSign : (t[4] || 0);
// Return a date object based on UTC values
return new Date(Date.UTC(t[0], --t[1], t[2], t[3]||0, min, t[5]||0, ms));
}
An ISO 8601 date string should be treated as UTC (per ECMA-262), so if you are UTC-0500, then:
new Date('2014-04-07'); // 2014-04-06T19:00:00-0500
The behaviour described in the OP shows the host is not compliant with ECMA-262. Further encouragement to parse the string yourself. If you want the date to be treated as local, then:
// Expect string in ISO 8601 format
// Offset is ignored, Date is created as local time
function parseLocalISODate(s) {
s = s.split(/\D+/g);
return new Date(s[0], --s[1], s[2],0,0,0,0);
}
In your function you can do something like:
var ds = data.feed.entry[i].gd$when[j].startTime;
var startDate = ds.length == 10? parseLocalISODate(ds) : parseISOString(ds);
Also note that variables starting with a capital letter are, by convention, reserved for constructors, hence startDate, not StartDate.
(I would add a comment but i don't have 50 rep yet)
See what
new Date().getTimezoneOffset()
returns, I would expect a big negative value, that would be the only reasonable explanation to your problem.
I have had some trouble with date conversions in the past, in particular with daytime saving timezones, and as work around i always set the time explicitly to midday (12:00am). Since I think you were using knockout, you could just make a computed observable that appends a "T20:00:00.000-05:00" or the appropiate time zone to all "day only" dates

date object returns random date for invalid months/day

This code:
var dt = new Date('82/66/2005');
...gives a value for dt as Wed Nov 25 1992 00:00:00 GMT+0530 (IST) on Firefox.
How?
Fiddle - http://jsfiddle.net/4jyT3/1/
That date is not in a format that is specified to be supported by the Date constructor. I'm not surprised to find that most engines call it invalid, but apparently Firefox is attempting to make a date out of that. Even though it's not specified, most engines support month/day/year and all, last I checked, support year/month/day. Firefox appears to be applying year/month/day to the input, where most browsers see the invalid values and go with "invalid."
So Firefox is seeing 82 for year (and assuming 1982), 66 for month, and 2005 for day. JavaScript is usually very forgiving about out-of-bound values on dates, moving to the next month and such as necessary. And that's what's happening here: If you take January 1st 1982 and add a further 65 months and 2004 days, you end up on Nov 25 1992.
This code will reliably give you the date you mentioned:
var dt = new Date(1982, 65, 2005);
(65 instead of 66 because in the number form, months start with 0, but in string form, they start with 1.)
I can't re-produce this in Chrome, but I'll explain how FireFox arrives here.
new Date('82-66-2005');
Invalid date, let's guess what you wanted based on what we know about dates.
hyphen - format is usually yyyy-mm-dd
yy is short for 19yy
there are 12 months, so month 13 is Januaray of next year
similarly for days
So using this knowledge lets estimate it, assuming 365.25 days per year and 30.5 days per month.
// input
var year = 1982, // 19yy
bigMonth = 66,
bigDay = 2005;
// adjust day for years
var day = bigDay % 365.25;
year = year + (bigDay - day) / 365.25;
// adjust day for months
bigDay = day;
day = bigDay % 30.5;
bigMonth = bigMonth + (bigDay - day) / 30.5;
// adjust month for years
var month = bigMonth % 12;
year = year + (bigMonth - month) / 12;
console.log(year, month, day); // 1992 11 26.25
So it would be about the Nov 26th, 1992, which is pretty close to how your browser calculated it (it didn't need to estimate).

Categories

Resources