How to get the full dates between two dates using javascript / react? - javascript

My requirement is to get the number of days between two dates.
For example, the start date is 02/20/2020 to 01/03/2020 I would like to display the results like
Feb 20 Thursday, Feb 21 Friday,....01 Mar Monday.
I went through this scenario in StackOverflow but I didn't get the expected solution for the same.
Could anyone please guide in achieving this scenario using javascript or react?

You may calculate the difference between dates, than make up desired array of dates casted to date string of necessary format:
const d1 = new Date('02/20/2020'),
d2 = new Date('03/01/2020'),
diff = (d2-d1)/864e5,
dateFormat = {weekday:'long',month:'short',day:'numeric'},
dates = Array.from(
{length: diff+1},
(_,i) => {
const date = new Date()
date.setDate(d1.getDate()+i)
const [weekdayStr, dateStr] = date.toLocaleDateString('en-US',dateFormat).split(', ')
return `${dateStr} ${weekdayStr}`
}
)
console.log(dates)
.as-console-wrapper {min-height:100%;}
Or, as long as we're having fun here :) following is React implementation:
const { render } = ReactDOM,
{ useState } = React
const DatePicker = ({min,max,onPick,role}) => (
<input
type="date"
onChange={onPick}
{...{min,max}}
/>
)
const ListOfDates = ({startDate,endDate}) => {
const d1 = new Date(startDate),
d2 = new Date(endDate),
diff = (d2-d1)/864e5,
dateFormat = {weekday:'long',month:'short',day:'numeric'},
dates = Array.from(
{length: diff+1},
(_,i) => {
const date = new Date()
date.setDate(d1.getDate()+i)
const [weekdayStr, dateStr] = date.toLocaleDateString('en-US',dateFormat).split(', ')
return `${dateStr} ${weekdayStr}`
}
)
return (
<ul>
{dates.map((date,key) => <li {...{key}}>{date}</li>)}
</ul>
)
}
const App = () => {
const [start, setStart] = useState(''),
[end, setEnd] = useState(''),
onPickStart = ({target:{value}}) => setStart(value),
onPickEnd = ({target:{value}}) => setEnd(value)
return (
<div>
<DatePicker max={end} onPick={onPickStart} />
<DatePicker min={start} onPick={onPickEnd} />
<ListOfDates startDate={start} endDate={end} />
</div>
)
}
render (
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
...and jQuery one:
$(document).ready(() => {
$('.datepick').on('change', function(){
$(this).attr('id') == 'startDate' ?
$('#endDate').attr('min', $(this).val()) :
$('#startDate').attr('max', $(this).val())
if($('#startDate').length && $('#endDate').length) {
const d1 = new Date($('#startDate').val()),
d2 = new Date($('#endDate').val()),
diff = (d2-d1)/864e5,
dateFormat = {weekday:'long',month:'short',day:'numeric'},
dates = Array.from(
{length: diff+1},
(_,i) => {
const date = new Date()
date.setDate(d1.getDate()+i)
const [weekdayStr, dateStr] = date.toLocaleDateString('en-US',dateFormat).split(', ')
return `${dateStr} ${weekdayStr}`
}
),
dateListItems = dates.map(d => `<li>${d}</li>`)
$('#dateList').html(dateListItems)
}
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label>Start Date: <input id="startDate" type="date" class="datepick"></input></label>
<label>End Date: <input id="endDate" type="date" class="datepick"></input></label>
<ul id="dateList"></ul>

you can use momentjs to get the result:
//let moment = require("moment");
let date = [];
let startDate = "02/20/2020";
let endDate = "01/03/2020";
while ( moment(startDate, "MM/DD/YYYY").valueOf() <= moment(endDate, "DD/MM/YYYY").valueOf()) {
date.push(moment(startDate, "MM/DD/YYYY").format("MMM DD dddd"));
startDate = moment(startDate, "MM/DD/YYYY").add(1, "days").format("MM/DD/YYYY");
}
console.log(date);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

You can start by first creating two date objects, one for the start date and another for the end date. Then, find out how many days are in between these dates. Finally, you can loop through this number and get the current date plus the current index in the loop and print that.
As a React component:
const App = () => {
const [dates, setDates] = React.useState([]);
React.useEffect(() => {
const start = new Date('02/20/2020');
const end = new Date('03/01/2020');
const daysBetween = (end.getTime() - start.getTime()) / (1000 * 3600 * 24);
const arr = [];
for (let i = 0; i <= daysBetween; i++) {
const temp = new Date();
temp.setDate(start.getDate() + i)
arr.push(temp);
}
setDates(arr);
}, []);
return (
<ul>
{dates.map(date => (
<li key={date}>
{date.toLocaleDateString(
"en-US",
{month: "short", day: "2-digit", weekday: "long"}
)}
</li>
))}
</ul>
);
}
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

From the date given, find the difference in days then based on the no of days, make a loop and log each increment day in between using toLocaleString()..
const startDate = "02/20/2020";
const endDate = "03/01/2020";
const diffTime = Math.abs(new Date(endDate) - new Date(startDate));
const diffDays = 0|diffTime/864e5;
for(let i = 0; i <= diffDays; i++){
const newdate = new Date(new Date(startDate).getTime()+(i*864e5));
console.log(newdate.toLocaleString('en-us', { day:'2-digit', month: 'short', weekday:'long'}))
}

Another method to get the difference between two dates in JavaScript:
const d1 = new Date("06/30/2019");
const d2 = new Date("07/30/2019");
// To calculate the time difference of two dates
const timeDiff = d2.getTime() - d1.getTime();
// To calculate the no. of days between two dates
const days = timeDiff / (1000 * 3600 * 24);
//to list the days
while (days !== 0) {
let date = new Date(d2)
date.setDate(date.getDate() - days)
console.log(date)
days--
}

Related

Getting date range based on date and hour

I am trying to get individual dates ("2022-10-10") and hours ("2022-10-10T09") between an interval in UTC. I could get the individual dates by the following -
function getDatesInRange(startDate, endDate) {
const date = new Date(startDate.getTime());
const dates = [];
while (date <= endDate) {
const day = new Date(date).toISOString().split(':')[0].split('T')[0];
dates.push(day);
date.setDate(date.getDate() + 1);
}
return dates;
}
console.log(getDatesInRange(new Date('2022-10-10T20:50:59.938Z'), new Date('2022-10-15T23:50:59.938Z')));
Hence, the above returns - ["2022-10-10", "2022-10-11", "2022-10-12", "2022-10-13", "2022-10-14", "2022-10-15"]
I also want to return the hours of the start and end date and the rest should be dates. So i want to get in return - ["2022-10-10T20", "2022-10-10T21", "2022-10-10T22", "2022-10-10T23" "2022-10-11", "2022-10-12", "2022-10-13", "2022-10-14", "2022-10-15T00", "2022-10-15T01"]
Here is what i have as of now -
function getHoursInRange(startDate, endDate) {
let startDatePlusOne = new Date(startDate);
startDatePlusOne.setDate(startDatePlusOne.getDate() + 1);
let endDateMinusOne = new Date(endDate);
endDateMinusOne.setDate(endDateMinusOne.getDate() - 1);
const date = new Date(startDate.getTime());
console.log("Start date :", date);
let dates = getDatesInRange(startDatePlusOne, endDateMinusOne);
console.log("Only days : ", dates);
startDatePlusOne.setHours(0);
while (date < startDatePlusOne) {
const day = new Date(date).toISOString().split(':')[0];
dates.push(day);
date.setHours(date.getHours() + 1);
}
endDateMinusOne.setHours(23);
const edate = endDateMinusOne.getTime();
while (edate < endDate) {
const day = new Date(edate).toISOString().split(':')[0];
dates.push(day);
date.setHours(date.getHours() + 1);
}
return dates
}
For this use case, i am getting the days back excluding the start and end dates. But for getting each hour of start and end date it gets stuck somehow. Somehow i feel there is a better way to do this. Any ideas ?
You can do it a simpler way by incrementing the timestamp by 30 minutes at a time, and keeping a note of all non-duplicate hour strings and date strings:
function getDatesInRange(startDate, endDate) {
let h = new Set(), d = new Set(), t = [];
for(let i=startDate.getTime(); i<endDate.getTime(); i+=1000*1800) t.push(i);
[...t, endDate.getTime()].forEach(i=>{
let s = new Date(i).toISOString();
[[s.split(':')[0], h], [s.split('T')[0], d]].forEach(([s,r])=>r.add(s));
});
let firstDate = [...d.values()][0], lastDate = [...d.values()].pop();
return d.size===1 ? [...h.values()] : [
...[...h.values()].filter(v=>v.startsWith(firstDate)),
...[...d.values()].filter(v=>v!==firstDate && v!==lastDate),
...[...h.values()].filter(v=>v.startsWith(lastDate))];
}
console.log(getDatesInRange(
new Date('2022-10-10T20:50:59.938Z'), new Date('2022-10-15T23:50:59.938Z')));
dateRange constructs an array of Date objects corresponding to the supplied range, inclusive.
dayToString takes a date and creates an array of strings, one for each hour of the day between the specified UTC hour range, inclusive.
dateRangeToStrings accepts an array of dates and constructs an array of strings according to the rules laid-out in the question.
const twoDigit = (n) => String(n).padStart(2, '0')
const toISODateString = (date) => `${date.getUTCFullYear()}-${twoDigit(date.getUTCMonth() + 1)}-${twoDigit(date.getUTCDate())}`
const dateRange = (start, end, curr = new Date(start)) => {
const dates = []
while (curr <= end) {
dates.push(new Date(Date.UTC(curr.getUTCFullYear(), curr.getUTCMonth(), curr.getUTCDate())))
curr.setUTCDate(curr.getUTCDate() + 1)
}
return dates
}
const dayToString = (date, startUTCHour = 0, endUTCHour = 23) =>
Object.keys([...Array(24)])
.slice(startUTCHour, endUTCHour + 1)
.map((h)=>`${toISODateString(date)}T${twoDigit(h)}`)
const dateRangeToStrings = (arr, startUTCHour, endUTCHour) => {
const beginning = dayToString(arr[0], startUTCHour)
const middle = arr.slice(1, -1).map(toISODateString)
const end = dayToString(arr[arr.length - 1], 0, endUTCHour)
return beginning.concat(middle, end)
}
const getDatesInRange = (start, end) =>
dateRangeToStrings(dateRange(start, end),
start.getUTCHours(),
end.getUTCHours())
console.log(getDatesInRange(new Date('2022-10-10T20:50:59.938Z'),
new Date('2022-10-15T23:50:59.938Z')))

Check date range with an array

I have an array, in which I have inserted some day that are holidays.
In my app I choose an interval (startDate and endDate) and I should check that this interval is not in my array. How can I do?
For example:
holidaysArray = [
"2020-04-12",
"2020-04-13",
"*-03-17",
"*-05-01",
"*-06-02"
}
I choose as
startDate: 2022-03-15T16:16:00.000Z
endDate:2022-03-18T16:12:23.103Z
What I expect
So now I should count the day between the startDate and EndDate, and the result is 4 days. But I my array there is value "*-03-17", so I should not considering a day.
How can I do?
I have a datepicker:
<DatePicker
modal
open={showStartDate}
date={startDate}
title={null}
confirmText="Ok"
cancelText="Cancel"
mode="date"
onConfirm={(date) => {
setShowStartDate(false)
onChangeStart( date)
}}
onCancel={() => setShowStartDate(false)}
/>
<DatePicker
modal
open={showEndDate}
date={endDate}
title={null}
confirmText="Ok"
cancelText="Cancel"
mode="date"
onConfirm={(date) => {
setShowEndDate(false)
onChangeStart( date)
}}
onCancel={() => setShowEndDate(false)}
/>
So my
onChangeStart = (selectedDate) => {
checkDate(selectedDate, endDate)
}
checkDate = (start, end) => {
const holidayArray = travelInfo.time.holidayArray
//
}
When you iterate over 'holidayArray' you need to check if the holiday falls between the selected date, if it does just decrement the total difference between the dates by '1' (assuming you are counting Sundays' as well).
For the case where the dates have *, you need to find the 'years' that can fall between the dates and use them to replace the * to form the appropriate date.
First Step (Find year (or years if the selection is too large, just in case))
(assuming endDate > startDate)
const findYears = (startDate, endDate) => {
let yearsArray = [];
let endYear = parseInt(endDate?.split("-")[0]);
let startYear= parseInt(startDate?.split("-")[0]);
yearsArray.push(endYear);
while(endYear !== startYear){
endYear--;
yearsArray.push(endYear);
}
return yearsArray;
}
Now complete your checkDate function
checkDate = (start, end) => {
const years = findYears(start, end)
const holidayArray = travelInfo.time.holidayArray;
var from = new Date(start);
var to = new Date(end);
var diff = 0;
holidayArray.forEach(holiday => {
if (holiday.match("\\*")) {
years.forEach(year => {
var check = new Date(holiday.replace("\\*", year));
if (check > from && check < to) {
diff--
}
})
} else {
var check = new Date(holiday);
if (check > from && check < to) {
diff--
}
}
})
const diffTime = Math.abs(start - end);
var diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24));
return diffDays + diff
}

React JS Convert date from yyyy-mm-dd to dd-mm-yyyy [duplicate]

This question already has answers here:
Convert yyyy-MM-dd to MM/dd/yyyy in javascript
(7 answers)
Closed 1 year ago.
I'd like to have my date in a dd-mm-yyyy format, so I wrote the below in order to reassemble the date I get from my date picker.
Instead of getting 17-05-2021, I'm getting 1,7-0,5-2,0,2,1
What can I do to avoid those commas?
I'm open to other suggestions on how to get this date in a more efficient way than what I wrote
const minDate = new Date().toISOString().slice(0, 10) // outputs 2021-05-17
const [text, setText] = useState('');
const [urgent, setUrgent] = useState(false);
const [date, setDate] = useState(minDate);
const formatDate = () => {
let tempDate = [...date];
let day = tempDate.slice(8);
let month = tempDate.slice(5, 7);
let year = tempDate.slice(0, 4);
let newDate = `${day}-${month}-${year}`;
return newDate;
};
const handleSubmit = () => {
let fixedDate = formatDate(date);
console.log(newDate) // outputs 1,7-0,5-2,0,2,1
if (text.length > 5) {
props.addTask(text, urgent, fixedDate);
setText('');
setUrgent(false);
setDate(minDate);
} else alert('Task name too short!');
};
The date picker
<input
type="date"
min={minDate}
value={date}
onChange={(event) => setDate(event.target.value)}
/>
const formatDate = (dateStr) => {
const [year, month, day] = dateStr.split('-');
let newDate = `${day}-${month}-${year}`;
return newDate;
};
const formattedDate = formatDate('2021-01-31');
console.log(formattedDate);
you can define the formatDate function like belows.
const formatDate = date => `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getYear()}`;
You can use split and join like this without having to change your code;
const formatDate = () => {
let tempDate = [...date];
let day = tempDate.slice(8);
let month = tempDate.slice(5, 7);
let year = tempDate.slice(0, 4);
let newDate = `${day}-${month}-${year}`;
return newDate.split(',').join(''); // Change This Line
};
this will remove comas.

moving forward and backward between each month

I currently am working on an application where I am attempting to create a calendar using javascript. Based on the current date, I can select a back button and go back as many months as I would like and fetch the days within each month. I can also select a forward button and go forward as many months as I would like. The issue I am running into is that if I go back to say October 2020, and hit the forward button, the calendar will start on January 2021 because I am cycling months based on the current date rather than the dates I am currently on. What I would like to achieve is if I am in October 2020 and hit the forward button, I like it to go to November 2020. Any and all suggestions are appreciated.
my code is as follows:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [count, setCount] = useState(1);
const [countTwo, setCountTwo] = useState(1);
const [dates, setDates]=useState(null)
const getDaysArray = async (s, e) => {
let a = [];
for (let d = new Date(s); d <= e; d.setDate(d.getDate() + 1)) {
a.push(new Date(d).toString());
}
return a;
};
const prevMonth = async () => {
setCount((state) => state + 1);
let d = new Date();
d.setMonth(d.getMonth() - count);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
const nextMonth = async () => {
setCountTwo((state) => state + 1);
let d = new Date();
d.setMonth(d.getMonth() + countTwo);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
return (
<div className="App">
<button onClick={prevMonth}>Prev Month</button>
<button onClick={nextMonth}>Next Month</button>
{dates &&
dates.map((item, i) => {
return <div key={i}>{item}</div>;
})}
</div>
);
}
here is a code pen for debugging! https://codesandbox.io/s/sweet-brook-y2n7p?file=/src/App.js:0-1413
Rather than tracking the current date, use a counter to keep track of the current month number. Then subtract or add one that that number for previous or next. And se the month using that number.
Here is a fork of your project with this solution:
https://codesandbox.io/s/clever-rgb-mryst
And the code:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [visibleMonth, setVisibleMonth] = useState(new Date().getMonth());
// const [countTwo, setCountTwo] = useState(1);
const [dates, setDates] = useState(null);
const getDaysArray = async (s, e) => {
let a = [];
for (let d = new Date(s); d <= e; d.setDate(d.getDate() + 1)) {
a.push(new Date(d).toString());
}
return a;
};
const prevMonth = async () => {
let d = new Date();
d.setMonth(visibleMonth - 1);
setVisibleMonth((state) => visibleMonth - 1);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
const nextMonth = async () => {
let d = new Date();
d.setMonth(visibleMonth + 1);
setVisibleMonth((state) => visibleMonth + 1);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
return (
<div className="App">
<button onClick={prevMonth}>Prev Month</button>
<button onClick={nextMonth}>Next Month</button>
{dates &&
dates.map((item, i) => {
return <div key={i}>{item}</div>;
})}
</div>
);
}

Fill in empty blocks for each calendar month JS

I am currently able to fetch the given days of the current month as well as previous and future months using JS. What I would like to achieve, is if say December starts on a Tuesday I would like to pass in empty objects for Sunday and Monday. December also ends on a Thursday, so I would like to pass in empty objects for Friday and Saturday.
The code I am currently using to fetch each calendar month and display them is as follows:
import React, { useEffect, useState, useCallback } from "react";
import "./styles.css";
export default function App() {
const [visibleMonth, setVisibleMonth] = useState(new Date().getMonth());
const [calData, setCalData] = useState(null);
const [dates, setDates] = useState(null);
const getDaysArray = async (s, e) => {
let a = [];
for (let d = new Date(s); d <= e; d.setDate(d.getDate() + 1)) {
a.push(new Date(d).toString());
}
return a;
};
const currentMonth = useCallback(async () => {
let d = new Date();
d.setMonth(visibleMonth);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
let calendarMonth = d.toLocaleString("en-us", {
month: "long",
year: "numeric"
});
setCalData(calendarMonth);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
}, [visibleMonth]);
useEffect(() => {
currentMonth();
}, [currentMonth]);
const prevMonth = async () => {
let d = new Date();
d.setMonth(visibleMonth - 1);
setVisibleMonth((state) => visibleMonth - 1);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
let calendarMonth = d.toLocaleString("en-us", {
month: "long",
year: "numeric"
});
setCalData(calendarMonth);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
const nextMonth = async () => {
let d = new Date();
d.setMonth(visibleMonth + 1);
setVisibleMonth((state) => visibleMonth + 1);
let firstDay = new Date(d.getFullYear(), d.getMonth(), 1);
let lastDay = new Date(firstDay.getFullYear(), firstDay.getMonth() + 1, 0);
let calendarMonth = d.toLocaleString("en-us", {
month: "long",
year: "numeric"
});
setCalData(calendarMonth);
const dates = await getDaysArray(firstDay, lastDay);
setDates(dates);
};
return (
<div className="App">
<h1>{calData}</h1>
<button onClick={prevMonth}>Prev Month</button>
<button onClick={nextMonth}>Next Month</button>
{dates &&
dates.map((item, i) => {
return <div key={i}>{item}</div>;
})}
</div>
);
}
the reason I am attempting to do so is due to the grid I have created. As it stands now, every month starts at sunday and I am not successfully pairing the correct days of the month with the days on the calendar. For example december starts on a tuesday, yet my styling shows it starts on a sunday any help would be greatly appreciated. the console logs currently show the days each month should start and end on.
Attached is a code pen for debugging! https://codesandbox.io/s/heuristic-visvesvaraya-r9lcw?file=/src/App.js
Based upon your most recent comments and updates, I recommend the following changes to the getDaysArray() method:
Create the d date outside the loop in order to use getDay() (day of week #)
Fill the a[] with empty strings with the number of day of week # in a for loop
Finally, populate the date strings into the remainder of the a[] array.
That should do it:
const getDaysArray = async (s, e) => {
let a = [];
let d = new Date(s);
let emptyCount = d.getDay();
for(let i = 0; i < emptyCount; i++) {
a.push('');
}
for (d; d <= e; d.setDate(d.getDate() + 1)) {
a.push(new Date(d).toString());
}
return a;
};

Categories