JS Check Date is Within 6 Months of Today - javascript

I am using Bootstrap Datepicker, and based on the date selection I need to display a message to the user.
I have never used the Date Constructor before so it's very new to me.
What I need to do is the following;
allow user to select a date
display a message / alert based of the logic below
If their selected date is within the last 6 months of today, they quality for discount.
If their selected date doesn't fall within the last 6 months of today, they don't.
Although it's not working correctly have created a fiddle here.
Any help would be appreciated. Code also below;
HTML
<input type="text" class="form-control" id="datepicker" placeholder="Year Graduated" value="" data-date-format="dd/mm/yyyy">
<p id="rate"></p>
JS
function compareDate() {
// get date from datepicker
var dateEntered = $("#datepicker").datepicker("getDate");
dateEntered = new Date(dateEntered).getTime();
//alert("date entered: " + dateEntered);
// set todays date
var now = new Date();
// set date six months before today
var sixMonthBeforeNow = new Date(now).setTime(now.getTime() - 3 * 28 * 24 * 60 * 60);
//alert("six months before: " + sixMonthBeforeNow);
// if date entered is within six months from today
if (dateEntered > sixMonthBeforeNow) {
alert("You qualify for the discount rate.");
$("#rate").html('discount rate');
}
// if date entered is over six months from today
if (dateEntered < sixMonthBeforeNow) {
alert("you graduated more than six months ago");
$("#rate").html('no discount');
}
}
$("#datepicker").datepicker({
weekStart: 1,
daysOfWeekHighlighted: "6,0",
autoclose: true,
todayHighlight: true
});
$("#datepicker").change(function() {
compareDate();
});
Note: I'd prefer not to use any other 3rd party JS library / plugin.

Just change your sixMonthBeforeNow with the below code, that should work.
var sixMonthBeforeNow = new Date(now).setMonth(now.getMonth() - 6);

You need to be careful with date arithmetic because it's not symmetric due to the uneven length of months, so you need rules to deal with it. E.g. what date is exactly 6 months before 31 August?
Before answering, consider:
28 February plus 6 months is 28 August
1 March plus 6 months is 1 September.
So what date is 6 months before 29, 30 and 31 August? Is it 28 February or 1 March?
Similar issues arise for any last day of a month where the month 6 months previous doesn't have 31 days. Should the limit be the 30th of the month or the 1st of the following month? When you've answered that question, then you can devise an algorithm to deliver the right answer and then the code to implement it.
If you want such cases to set the date to the end of the month 6 months before, then you can check the month resulting from subtracting 6 months and if it's not 6, set it to the last day of the previous month, e.g.
function sixMonthsPrior(date) {
// Copy date so don't affect original
var d = new Date(date);
// Get the current month number
var m = d.getMonth();
// Subtract 6 months
d.setMonth(d.getMonth() - 6);
// If the new month number isn't m - 6, set to last day of previous month
// Allow for cases where m < 6
var diff = (m + 12 - d.getMonth()) % 12;
if (diff < 6) d.setDate(0)
return d;
}
// Helper to format the date
function formatDate(d) {
return d.toLocaleString(undefined, {day:'2-digit', month:'short', year:'numeric'});
}
// Tests
[ new Date(2018, 7,31), // 31 Aug 2018
new Date(2018, 8, 1), // 1 Sep 2018
new Date(2018,11,31), // 31 Dec 2018
new Date(2019, 2,31) // 31 Mar 2019
].forEach( d => console.log(formatDate(d) + ' => ' + formatDate(sixMonthsPrior(d))));
If that is't the logic you wish to apply, you need to say what is.
PS. You can also implement the above logic by just comparing the start and end dates (day number). If they're different, it must have rolled over a month so set to 0.

Related

When you know what week it is, how to find out the start date of the week

Through the 'date-fns' module, I am receiving numbers of how many weeks the date is this year.
const current = '2022-03-10'
const weekNumber = getWeek(current, 1) // 11
On the contrary, if you only know the numbers, you want to know how to do the first date of the week number.
The way I want to know.
const weekNumber = 11;
const weekOfstartDate = anyFunc(weekNumber) // '2022-03-07'
Do you know the answer to this solution?
You can use the I token:
var dateFns = require("date-fns");
console.log(dateFns.parse('10','I', new Date()));
At npm.runkit.com that returns a date for Mon 7 Mar 2022. It seems date-fns assumes the year of the current week. I have no idea how to specify the year, attempting:
console.log(dateFns.parse('2022-10','YYYY-II', new Date(),{
useAdditionalWeekYearTokens: true
}));
Throws a range error: The format string mustn't contain YYYY and II at the same time. Similarly for "2022W10" and tokens "YYYY'W'II", it says Y and I tokens can't be in the same format string.
A function to do the same thing is:
// Returns the first day (Monday) of the specified week
// Year defaults to the current local calendar year
function getISOWeek(w, y = new Date().getFullYear()) {
let d = new Date(y, 0, 4);
d.setDate(d.getDate() - (d.getDay() || 7) + 1 + 7*(w - 1));
return d;
}
// Mon Mar 14 2022
console.log(getISOWeek(11).toString());
// Mon Jan 02 2023
console.log(getISOWeek(1,2023).toString());
// Mon Dec 28 2026
console.log(getISOWeek(53,2026).toString());
A robust function should validate the input such that the week number is 1 to 53 and that 53 is only permitted for years that have 53 weeks.
I wanted a solution only using date-fns functions. This is how i combined it:
const result = setWeek(nextMonday(new Date(year, 0, 4)), week, {
weekStartsOn: 1,
firstWeekContainsDate: 4,
});

Javascript, counting years and days since 1970-01-01 until today

I'm trying to count the numbers of years and the days(that remains after the years is counted). So it shows how long its gone in years+days since 1970-01-01. Right now I'm only able to get the years right, and I'm not sure if the days are correct. They are both separated, I need them to in some way make var diffDays and diffYear. A calculation so the computer gets that after counting years, to do minus numbers of years in days and show how many days thats left, since today.
<head>
<script>
var today = new Date();
var dd = today.getDate();
document.write(today);
function myFunction() {
var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
var firstDate = new Date(1970,01,01);
var secondDate = new Date();
var diffYear = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)/365));
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
document.getElementById("antalYear").innerHTML = diffYear;
document.getElementById("antalDagar").innerHTML = diffDays;
}
</script>
</head>
<body onload="myFunction()">
<p>
Numbers of years and days:
<h3>
<span id="antalYear"></span>
years and
<span id="antalDagar"></span>
days
</h3> Since: 1970,01,01.
</p>
</body>
If you're okay with using a library I would recommend moment.js
It's the go to for handling almost anything related to dates.
var oldDate = moment("1970-01-01", "YYYY-MM-DD")
var today = moment()
console.log(today.diff(oldDate, "years"));
console.log(today.diff(oldDate, "days"));
$(".years").append(today.diff(oldDate, "years"))
$(".days").append(today.diff(oldDate, "days"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Years:<div class="years"></div>
</br>
Days:<div class="days"></div>
For the number of years since 1970, just subtract it from the current year:
date.getFullYear() - 1970
For the number of days since the beginning of the year, you can subtract a date for 1 Jan in the current year from the current date to get milliseconds, then divide by ms per day. However, that doesn't allow for daylight saving changeovers which might affect the result. If you want to round up, so that any time on 1 January is 1 day, etc. then you can set the time to 12 noon, divide by ms/day and round up (or round down and add one). That gives you the day number of the year.
E.g.
function dayOfYear(date) {
// Copy date so don't affect original
var d = new Date(date);
// Get time value for start of 1 Jan in date year
var yearStart = new Date(d.getFullYear(), 0);
// Get number of days, rounded up
return Math.ceil((d.setHours(12,0,0,0) - yearStart) / 8.64e7);
}
// Day of year for current date
console.log('Current day number: ' + dayOfYear(new Date()));
// Day of year for 31 Dec 2016
console.log('Day number for 31 Dec 2016: ' + dayOfYear(new Date(2016, 11, 31))); // 366
If you want the number of completed days (so 1 Jan is 0, 2 Jan is 1, etc.) just subtract 1 from the result (or use Math.floor instead of Math.ceil).

How to translate this line of code to human language?

Hi I'm trying to change this calendar's starting weekday from Sunday to Monday.
But I don't understand what's going on in the var k = ... line. What is this line of code trying to say in human language?
https://codepen.io/xmark/pen/WQaXdv?editors=1010
// June 2018
var k = lastDay_of_LastMonth - firstDay_of_Month+1;
27
//_____________________________________________________________________
// TEST
var lastDay_of_LastMonth = new Date(2018, 5, 0); // May 31st 2018
document.write('Today is: ' + lastDay_of_LastMonth.toLocaleString());
// Today is: 5/31/2018, 12:00:00 AM
var firstDay_of_Month = new Date(2018, 5, 1); // June 1st 2018
firstDay_of_Month."getDay()";
5
// June 2018
var k = lastDay_of_LastMonth - firstDay_of_Month+1;
lastDay_of_LastMonth.setDate(lastDay_of_LastMonth.getDate() - 6);
document.write('<br>X days ago was: ' + lastDay_of_LastMonth.toLocaleString());
// X days ago was: 5/25/2018, 12:00:00 AM
//_____________________________________________________________________
// June 2018
27 = 31 - 5+1;
I see from this thread that this code is calculating (Date - Days), counting days backwards. But I can't understand what it is doing in human language for the calendar code. Shouldn't the math 31-(5+1) = 25 meaning it's going 6 days back in time why do I get the value 27 back?
Subtract days from a date in JavaScript
From the codepen that you attached, the developer is using k to get the days outside of the current month that should come up in the calendar (i.e. if our month is starting on Tuesday then Sunday & Monday are in the previous month, but we need to get the "day of the month numbers" of these days), now they are using k in two occasions:
1: to get the days from the previous month var k = lastDayOfLastMonth - firstDayOfMonth+1;
2: to get the days from the next month:
else if ( i == lastDateOfMonth ) {
var k=1;
for(dow; dow < 6; dow++) {
html += '<td class="not-current">' + k + '</td>';
k++;
}
}
In the first occasion, they are calculating the difference between the last day of the last month and the first day of this month, the +1 here is because you're working with indexes.
In the second occasion, it's safe to say that every month has 1-6, so they loop up to 6 to fill up the last week in the calendar.
Order of operations in this language gives equal precedence to the addition and subtraction operators.
In other words, it uses PEMDAS.
So it'll do 31-5: 26
Then 26 + 1: 27

How to reliably implement 'next' / 'previous' month

This has been asked (badly) before - I don't think the answer in that post really addressed the issue, and then it went stale. I'm going to attempt to ask it again with a clearer demonstration of the issue.
The implementation of Javascript Date.setMonth() appears not to follow the principle of least surprise. Try this in a browser console:
d = new Date('2017-08-31') // Set to last day of August
d.getMonth() // 7 - months are zero-based
d.setMonth(8) // Try to set the month to 8 (September)
d.getMonth() // 9 - October. WTF Javascript?
Similarly:
d = new Date('2017-10-31')
d.getMonth() // 9
d.setMonth(8)
d.getMonth() // 9 (still?)
Firefox on Linux appears even worse - sometimes returning a date in October, and a result from getMonth() which doesn't match that month!
My question (and I think that of the OP from that linked question) is how to consistently implement a 'next' / 'prev' month function in, e.g. a datepicker? Is there a well known way of doing this which doesn't surprise the user by, for example, skipping September when they start on August 31st and click 'next'? Going from January 31st is even more unpredictable currently - you will end up on either March 2nd or March 3rd, depending on whether it's a leap year or not!
My personal view is that the least surprise would be to move to the last day of the next / previous month. But that requires the setMonth() implementation to care about the number of days in the months in question, not just add / subtract a fixed duration. According to this thread, the moment.js approach is to add / subtract the number of milliseconds in 30 days, which suggests that library would be prone to the same inconsistencies.
It's all simple and logic. Lets take your example and go see what id does.
So the first line
d = new Date('2017-08-31') // Set to last day of August
console.log(d); // "2017-08-31T00:00:00.000Z"
console.log(d.getMonth()); // 7 - months are zero-based
So all good so far. Next step: Your comment says it: // Try to set the month to 8 (September) So it's not done with trying. You either set it to september or you don't. In your example you set it to October. Explanation further down.
d = new Date('2017-08-31') // Set to last day of August
console.log(d); // "2017-08-31T00:00:00.000Z"
console.log(d.getMonth()); // 7 - months are zero-based
d.setMonth(8) // Try to set the month to 8 (September)
console.log(d); // but now I see I was wrong it is (October)
So the good question is WHY? From MDN
Note: Where Date is called as a constructor with more than one
argument, if values are greater than their logical range (e.g. 13 is
provided as the month value or 70 for the minute value), the adjacent
value will be adjusted. E.g. new Date(2013, 13, 1) is equivalent to
new Date(2014, 1, 1), both create a date for 2014-02-01 (note that the
month is 0-based). Similarly for other values: new Date(2013, 2, 1, 0,
70) is equivalent to new Date(2013, 2, 1, 1, 10) which both create a
date for 2013-03-01T01:10:00.
So that sayd September has only 30 Days but the Date Object has 31. This is why it gives you October and not September.
The simplest will be to take the date you have and set it to first day of month. Something like so:
var d = new Date('2017-08-31') // Set to last day of August
// simplest fix take the date you have and set it to first day of month
d = new Date(d.getFullYear(), d.getMonth(), 1);
console.log(d); // "2017-08-31T00:00:00.000Z"
console.log(d.getMonth()); // 7 - months are zero-based
d.setMonth(8) // Set the month to 8 (September)
console.log(d.getMonth()); // get 8 it is (September)
If setMonth is used when adding and subtracting months, then if the date of the start month doesn't exist in the end month, the extra days cause the date to "roll over" to the next month, so 31 March minus 1 month gives 2 or 3 March.
A simple algorithm is to test the start date and end date and if they differ, set the end date to 0 so it goes to the last day of the previous month.
One issue with this is that subtracting 1 month twice may not give the same result as subtracting 2 months once. 31 March 2017 minus one month gives 28 Feb, minus another month gives 28 Jan. Subtract 2 months from 31 March and you get 31 Jan.
C'est la vie.
function addMonths(date, num) {
var d = date.getDate();
date.setMonth(date.getMonth() + num);
if (date.getDate() != d) date.setDate(0);
return date;
}
// Subtract one month from 31 March
var a = new Date(2017,2,31);
console.log(addMonths(a, -1).toString()); // 28 Feb
// Add one month to 31 January
var b = new Date(2017,0,31);
console.log(addMonths(b, 1).toString()); // 28 Feb
// 29 Feb plus 12 months
var c = new Date(2016,1,29)
console.log(addMonths(c, 12).toString()); // 28 Feb
// 29 Feb minus 12 months
var c = new Date(2016,1,29)
console.log(addMonths(c, -12).toString()); // 28 Feb
// 31 Jul minus 1 month
var d = new Date(2016,6,31)
console.log(addMonths(d, -1).toString()); // 30 Jun
Since getMonth() returns an integer number, you can simply implement a generator over the date object, that sets the month + 1 or - 1 so long as your not at month 11 or month 0 respectively.
function nextMonth(dateObj) {
var month = dateObj.getMonth();
if(month != 11) dateObj.setMonth(month + 1);
return dateObj;
}
function prevMonth(dateObj) {
var month = dateObj.getMonth();
if(month != 0) dateObj.setMonth(month - 1);
return dateObj;
}
If you want to match the days in the previous month you can use an object lookup table.
Now, for your last day of the month problem:
function getLastDayofMonth(month) {
var lookUp = {
0:31,
1:28,
2:30,
3:31
};
return lookUp[month];
}
//and then a revised version
function nextMonth(dateObj) {
var month = dateObj.getMonth();
var day = dateObj.getDate();
if(month != 12) dateObj.setMonth(month + 1);
if(getLastDayofMonth(month)<day)dateObj.setDate(getLastDayofMonth(month));
return dateObj;
}
This should work for incrementing the month, you can use a similar strategy to decrement.
// isLeapYear :: Number -> Boolean
const isLeapYear = ((err) => {
return yr => {
// check for the special years, see https://www.wwu.edu/skywise/leapyear.html
if (yr === 0) {
throw err;
}
// after 8 AD, follows 'normal' leap year rules
let passed = true;
// not technically true as there were 13 LY BCE, but hey.
if (yr === 4 || yr < 0 || (yr % 4)) {
passed = false;
} else {
if (yr % 400) {
if (!(yr % 100)) {
passed = false;
}
}
}
return passed;
};
})(new Error('Year zero does not exist, refers to 1 BCE'));
const daysInMonth = [
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
];
// isLastDay :: Number, Number -> Boolean
const isLastDay = (d, m, y) => {
let dm = isLeapYear(y) && m === 1 ? 29 : daysInMonth(m);
return dm === d;
};
// getLastDay :: Number, Number -> Number
const getLastDay = (m, y) => isLeapYear(y) && m === 1 ? 29 : daysInMonth[m];
// incMonth :: Date -> Date
const incMonth = d => {
let dd = new Date(d.getTime());
let day = dd.getDate();
let month = dd.getMonth() + 1;
dd.setDate(5); // should avoid edge-case shenanigans
dd.setMonth(month);
let year = dd.getFullYear();
if (isLastDay(day, month, year)) day = getLastDay(month, year);
dd.setDate(day);
return dd;
};
This was the solution I came up with, which seems small and reliable as far as I can tell. It doesn't need any extra data structures, and relies on setDate(0) to select the last day of the month in the edge cases. Otherwise it leaves the date alone, which is the behaviour I wanted. It also handles wrapping round from one year to the next (in either direction):
function reallySetMonth(dateObj, targetMonth) {
const newDate = new Date(dateObj.setMonth(targetMonth))
if (newDate.getMonth() !== ((targetMonth % 12) + 12) % 12) { // Get the target month modulo 12 (see https://stackoverflow.com/a/4467559/1454454 for details about modulo in Javascript)
newDate.setDate(0)
}
return newDate
}
Note I've only tested this with targetMonth being either one higher or lower than the current month, since I'm using it with 'next' / 'back' buttons. It would need testing further user with arbitrary months.

Javascript repeating days counter

I need a JavaScript function that returns the number of days remaining from a particular date of every year.
I found the following code, but how can I make it repeatable for every year, instead of changing the year in the function manually?
function daysUntil(year, month, day) {
var now = new Date(),
dateEnd = new Date(year, month - 1, day), // months are zero-based
days = (dateEnd - now) / 1000/60/60/24; // convert milliseconds to days
return Math.round(days);
}
daysUntil(2013, 10, 26);
I think my question above is not clear enough, i need to show days remaining in 26th October. So this starts again every year on 27th October. I don't need a loop for that.
"how can i make it repeatable for every year, instead of changing the year in function manually?"
Well you can't do literally every year to infinity, but you can easily add a loop to get a specific range of years:
var d;
for (var y = 2013; y < 2099; y++) {
d = daysUntil(y, 10, 26);
// do something with d, e.g.,
console.log(d);
}
UPDATE: You added this detail to your question:
"I think my question above is not clear enough, i need to show days remaining in 26th October. So this starts again every year on 27th October. I don't need a loop for that."
OK, that's still not very clear, but I think you're saying that your input would be just the day and month and you want to calculate the number of days until the next time that day/month rolls around, e.g., the number of days until your next birthday. If so, perhaps something like this:
function daysUntil(month, day) {
var now = new Date(),
currentYear = now.getFullYear(),
dateEnd = new Date(currentYear, month - 1, day); // months are zero-based
if (dateEnd - now < 0) // have we already passed that date this year?
dateEnd.setFullYear(currentYear + 1);
return Math.ceil((dateEnd - now) / 1000/60/60/24);
}
console.log(daysUntil(10,11)); // 365 - results from today, Oct 11
console.log(daysUntil(10,26)); // 15
console.log(daysUntil(7,7)); // 269

Categories