var reportDateStr = "2018-05-21";
var reportDate = new Date(reportDateStr);
var y = reportDate.getFullYear();
var lastDateOfReportYear = new Date(reportDate.getFullYear(), 11, 31);
console.log(lastDateOfReportYear)
Instead of getting the last day of the year 2018 which is Dec 31, 2018, I am getting Jan 31, 2019
Please, can you tell me what is wrong with the above code and why I am getting Jan 31, 2019?
To be honest, without digging deeper into what browser/node version you are using (we will get to why that matters in a moment), I am a bit uncertain as to why you are getting a date a month later (Jan 1, 2019 would make much more sense for the issue you are running into) but I will give a higher level explanation for why Jan 1, 2019 might be happening.
From the Date documentation:
Note: Where Date is called as a constructor with more than one argument, the specified arguments represent local time. If UTC is desired, use new Date(Date.UTC(...)) with the same arguments.
So because your are constructing a new date with three parameters, the date represents your local time.
const localDate = new Date(2018, 11, 31);
console.log({
localDate // in EST this will be "2018-12-31T05:00:00.000Z"
});
Notice the hours is "05" (for EST) and not "00". Using Date.UTC as recommended will make it "00" regardless of local time.
const localDate = new Date(Date.UTC(2018, 11, 31));
console.log({
localDate // This will always be "2018-12-31T00:00:00.000Z"
});
A few other things to note when creating a Date from a date string (which is not recommended):
Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
So the date generated can be different due to various JavaScript implementations. Check out this chart for a reference on this issue.
Also note that getFullYearuses the local time to get the full year value. This can impact your desired output as well.
So, to be a bit more safe you could use UTC for all of your calculations:
const reportDateStr = '2018-05-21';
const reportDate = new Date(reportDateStr); // This could still be problematic
const y = reportDate.getUTCFullYear();
const lastDateOfReportYear = new Date(Date.UTC(y, 11, 31));
console.log(lastDateOfReportYear.toUTCString());
There are also libs like moment.js that can help with the multitude of issues dealing with times and dates.
You are doing too much work in something is always going to be the same.
December ALWAYS is going to be 31 days and the last month of the year is always going to be december, so why dont you just get the year and append to it 12-31
Example:
var reportDateStr="2018-05-21";
console.log(reportDateStr.substr(0,4)+'-12-31')
Now, If you want to keep your function make sure the TimeZone where you are. Your code works fine with the Eastern Time
See the working snippet below,
I added some consoling from your code and comments to make it simple:
var reportDateStr = "2018-05-21";
var reportDate = new Date(reportDateStr);
var y = reportDate.getFullYear();
var lastDateOfReportYear = new Date(y , 11, 31);
// For me the below returns the 30th December, 11pm
console.log('Date:', lastDateOfReportYear);
// … because I've got -120 as offset!
console.log('TimezoneOffset:', new Date().getTimezoneOffset());
// You need to use this one to get rid of the Timezones:
var lastDateOfReportYear_2 = new Date(Date.UTC(y , 11, 31));
console.log('Date UTC:', lastDateOfReportYear_2);
Hope it helps.
Related
I have a JavaScript function that takes a number (1-31), creates a Date and sends it to a server via an AJAX request:
sendDate(d) {
let date = new Date(this.year, this.month, d);
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
The problem is, that JavaScript is doing some timezone correction which has the effect, that if I create a date like new Date(2022, 09, 14) I get a date Wed Sep 14 2022 00:00:00 GMT+0200 (Central European Summer Time) which when converted to ISO format becomes 2022-09-13T22:00:00.000Z, ie. the previous day.
I know I can use .toLocaleDateString(), but I would like to stick to the ISO-format and I would also like to avoid hacky solutions such as always creating the date with some specified time at the middle of the day or whatever.
Is there a simple way to create a regular date object and pass it on to a server without timezone shenanigans?
Values passed to the Date constructor are treated as local, toISOString uses UTC. Unfortunately ECMAScript doesn't have a timezone–free, date–only form.
If you want to use toISOString to format the timestamp, then one solution is to parse the values as UTC initially, e.g.
sendDate(d) {
let date = new Date(Date.UTC(this.year, this.month, d));
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
Example:
let d = new Date()
let year = d.getFullYear();
let month = d.getMonth()
let day = d.getDate();
let date = new Date(Date.UTC(year, month, day))
// Always shows the current local date as 00:00:00Z
console.log( date.toISOString() );
You should also trim the Z from the end since the timestamp really is local.
There’s a way to do that: store the date as the UNIX timestamp. I do it this way and when it’s needed, I pass the timestamp from server to client and convert it into local date.
That said, I don’t think it’s a good idea to build the date on client and pass it to the server, since it could be modified on client. I believe it’s mostly done this way (and that’s also how it’s done in my projects): on the server side, you check the current timestamp (at the time request is sent) and do with it whatever you want.
It appears that you allow your user to pick a date. It would be a good approach to convert it then to timestamp and pass it to the server.
How would you do that? If I return date.getTime() and then parse it (in python) with datetime.fromtimestamp(int(request.GET['date']) / 1000) I still get the same timezone issue...
You won't have any issues in this case - apart from the fact your server just could happen to have a different local time. A time-zone independent solution would have to use utcfromtimestamp instead of fromtimestamp.
Either way, the timestamp itself can't have any timezone problems by definition.
See RobG's Answer... using the new Date(Date.UTC(year, month, day)) formatting is much better.
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.
I'm sorry I might be flamed for this but as a newbie I would like to make this work it is on Dates. I have this code:
var date = new Date('Apr 21, 2015');
and when I alert using this code:
var date = new Date('Apr 21, 2015');
alert(date.getFullYear());
alert(date.getMonth());
alert(date.getDate ());
it displays NaN. Can someone suggest me how to do this?
The problem is here:
var date = new Date('Apr 21, 2015');
There's no support for that date/time format in the specification. If a particular JavaScript engine supports it, it's because it's going above and beyond, and you cannot count on it. So you end up with a Date instance with the "time value" NaN (the "time value" is the number of milliseconds since The Epoch — Jan 1 1970), and all of the various methods like getFullYear and such return NaN.
So:
If you need to parse that format, you'll have to write code to do it, or use a library like MomentJS or several others that have already been written.
If you just need to get that date as a Date instance, rather than using the string, you can build it from the multi-argument constructor:
var date = new Date(2015, 3, 21); // Months start at 0, so 3 = April
According to MDN. The constructor that accepts a string value only accepts IETF-compliant RFC 2822 timestamps and a version of ISO8601
This is the IETF RFC 2822
date-time = [ day-of-week "," ] date FWS time [CFWS]
day-of-week = ([FWS] day-name) / obs-day-of-week
day-name = "Mon" / "Tue" / "Wed" / "Thu" /
"Fri" / "Sat" / "Sun"
date = day month year
year = 4*DIGIT / obs-year
month = (FWS month-name FWS) / obs-month
month-name = "Jan" / "Feb" / "Mar" / "Apr" /
"May" / "Jun" / "Jul" / "Aug" /
"Sep" / "Oct" / "Nov" / "Dec"
day = ([FWS] 1*2DIGIT) / obs-day
time = time-of-day FWS zone
time-of-day = hour ":" minute [ ":" second ]
hour = 2DIGIT / obs-hour
minute = 2DIGIT / obs-minute
second = 2DIGIT / obs-second
zone = (( "+" / "-" ) 4DIGIT) / obs-zone
and the ECMA5.1 is
YYYY-MM-DDTHH:mm:ss.sssZ
YYYY
YYYY-MM
YYYY-MM-DD
Clearly your string 'Apr 21, 2015' does not fit any of the above formats so it does not work. As T.J. Crowder pointed out, if you are not using standard formats, it's very up to the engine whether or not your code works.
If you plug the following into jsfiddle, it works fine, fiving 2015, 3 and 21 (at least under FF and IE):
var date = new Date('Apr 21, 2015');
alert(date.getFullYear());
alert(date.getMonth());
alert(date.getDate ());
So your problem may well lie elsewhere. Your best bet would be to construct a complete (but as short as possible) sample that exhibits the problem, then show us that.
If that simple code does cause the problem in your environment (with minimal other code), it may be that it doesn't support that format of constructor. ECMAScript specifies that, for a one-argument constructor where the argument is a string, it's like calling Date.parse() on that string and setting the object's value to the equivalent time value.
However, it's only required to handle a simplified ISO8601 format along the lines of:
YYYY-MM-DDTHH:mm:ss.sssZ
not something more free format such as April 21, 2015.
If the constructor has two to seven arguments, it's of the form:
new Date (year,month[,date[,hours[,minutes[,seconds[,ms]]]]])
with the individual fields given separately.
Hence there is no requirement under the standard for a given implementation to accept what you've given. A good test would be to use:
var date = new Date(2015,3,21);
and see if that fixes it.
That also gives you the same results in jsfiddle as previously and it may also fix the problem in your specific environment as well.
If you need to be able to parse those date formats and you don't want to restrict yourself to environments that allow them, you may need to resort to a third-party library.
The Date-Function works as the fallowing:
new Date(year, month, day, hours, minutes, seconds, milliseconds)
So this should works for you:
var date = new Date(2015, 3, 21);
alert(date.getFullYear());
alert(date.getMonth());
alert(date.getDate ());
Try to this.
var today = new Date("Apr 21, 2015");
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10) {
dd='0'+dd
}
if(mm<10) {
mm='0'+mm
}
today = mm+'/'+dd+'/'+yyyy;
alert(today);
Your code works in jshint and js.do
The date string you use is not in proper ISO format, therefore the question if it works mainly depends on OS and browser locale environment settings.
Try to parse the string first and handover the result to the Date constructor like this:
var date = new Date(Date.parse('Apr 21, 2015'));
For the following code:
var d = new Date("2013-07-01");
console.log(d.toDateString());
It outputs Sun Jun 30 2013, which is one day less of what was input. What happened to the object? What date is actually stored?
The date is parsed as UTC date, but the toDateString() outputs what that time is in the local timezone.
Try this instead
var d = new Date(2013, 6, 1); //6 instead of 7 because the mont argument is zero-based
console.log(d.toDateString());
What date is actually stored?
2013-07-01 00:00:00 UTC
Parsing a Date from a string can yield different results depending on what browser/runtime you are using. There is a chart here that lists some of the browsers and what they support.
But in general, a string like "2013-07-01" is treated as if it were at midnight in UTC.
If you wanted to parse it in local time, you could use "2013/07/01". But that's a bit strange. You might be tempted to use "07/01/2013", but that might be interpreted as either Jan 7th or July 1st. Any of these are still implementation specific.
If you want a general purpose, "works everywhere" solution, you have a few different options:
Option 1
Don't parse it. Use the constructor that accept integers.
var d = new Date(2013,6,1); // watch out for the zero-based month
console.log(d.toDateString());
// output: "Mon Jul 01 2013"
With this code, the actual UTC time stored is going to vary depending on your own time zone. But since .toDateString() also takes that time into account, then you should be ok.
Option 2
Parse it as UTC, and display it as UTC/GMT:
var d = new Date("2013-07-01");
console.log(d.toUTCString());
// output: "Mon, 01 Jul 2013 00:00:00 GMT"
But this output probably has more than you were looking for, and it may still look different in various browsers.
Option 3
Use the moment.js library, where you can control the formatting exactly however you desire.
var m = moment("2013-07-01", "YYYY-MM-DD"); // explicit input format
console.log(m.format("ddd MMM DD YYYY")); // explicit output format
// output: "Mon Jul 01 2013"
IMHO, this is the best solution. But it does require you use a library.
Option 4
This approach works pretty good and doesn't require 3rd party libraries.
var parts ='2013-07-01'.split('-');
var mydate = new Date(Date.UTC(parts[0],parts[1]-1,parts[2])); //please put attention to the month
You can simply append your timezone before parsing as well.
var d = new Date("2013-07-01" + "T00:00:00.000-05:00");
console.log(d.toDateString());
var startDate = new Date('2013-05-13');
var date_format = d3.time.format("%m/%d");
if I do
startDate = date_format(startDate);
I get "05/12" instead of "05/13". Anyone has a clue why is this happening?
Don’t use the Date(string) constructor to parse dates; it varies from browser to browser. The most likely (but not guaranteed) interpretation of "2013-05-13" is as an ISO8601 string in UTC time. Thus, if you run your statement in the JavaScript console, you will see:
> new Date("2013-05-13")
Sun May 12 2013 17:00:00 GMT-0700 (PDT)
The string is interpreted in UTC time by the Date construct, while the returned Date object is in local time. May 13, midnight UTC is May 12 5PM PDT, so when you format it in local time using d3.time.format, you get back May 12.
You could switch to using d3.time.format.utc("%m/%d") to format your date, but then you’re still dependent on the ambiguous behavior of the Date(string) constructor. So, instead…
As #minikomi suggested, you could create a d3.time.format to parse a date string: d3.time.format("%Y-%m-%d"), then format.parse("2013-05-13"). Or you could use the multi-argument Date constructor: new Date(2013, 4, 13), but note that months start at zero rather than the usual one.
You might get more consistent results using a d3.time.format to parse your string as well:
var startDate = '2013-05-13';
var parser = d3.time.format("%Y-%m-%d");
var formatter = d3.time.format("%m/%d");
var startDateString = formatter(parser.parse(startDate));