React compare or match two dates - javascript

I am facing an issue in React JS. I want to do compare or match the start_date with header date
Rest API
[
{
"id": "1",
"staff_name": "Jill",
"custom_service_name": "Jone",
"start_date": "2020-05-06 11:30:00",
"end_date": "2020-05-06 11:45:00",
},
{
"id": "2",
"staff_name": "james",
"custom_service_name": "smith",
"start_date": "2020-05-06 11:00:00",
"end_date": "2020-05-06 11:15:00",
}
]
console.log data:
1:00 AM //start_date
["9:43:36 AM", "9:13:36 AM", "10:13:36 AM"] //header_date
12:00 PM
["9:43:36 AM", "9:13:36 AM", "10:13:36 AM"] //header_date
2:15 AM
["9:43:36 AM", "9:13:36 AM", "10:13:36 AM"] //header_date
My Code:
var currentdate = new Date(); //header_date logic
var prevdate = new Date();
var firstdate = new Date();
prevdate.setTime(currentdate.getTime() - (30 * 60 * 1000));
firstdate.setTime(currentdate.getTime() + (30 * 60 * 1000));
var current = currentdate.toLocaleTimeString();
var previous = prevdate.toLocaleTimeString();
var first = firstdate.toLocaleTimeString();
var headerdate = [previous ,current, first];
this.state = {
headerdate:headerdate,
appointmentdata:[]
}
componentDidMount() { //get start_date
axios.get(`http://localhost/route/v1/appointment`)
.then(res => {
const appointmentdata = res.data;
console.log(appointmentdata);
this.setState({ appointmentdata });
})
}
I try , but this logic is not working
render() { return (
<div>
{this.state.appointmentdata.map(data =>
{ const dateTime = moment(data.start_date.toString());
if (dateTime.format("h:mm A") === this.state.headerdate)
{
return <p>{dateTime.format("h:mm A")}</p>; } //return the match date
else { return null; } })}
Demo:
https://codesandbox.io/s/quizzical-browser-9e3g4
What should i do?
Can anyone help me

I see you're using Moment. So you can use isSame built-in helper from them to achieve this.
Docs: https://momentjs.com/docs/#/query/is-same/
Example code:
const isSameDate = (start_date, header_date) => {
const startDate = moment(start_date);
const headerDate = moment(header_date);
return startDate.isSame(headerDate, 'day');
}
One small tip, you should move the date checking outside the render method, that would makes your code easier to read and maintainable

Related

Loop through array of objects and display them in react component

I have an array of object as follows. The data is based on created_date for e.g. ("2021-09-12")
As you can see, i have got last 5 days of data. i.e. 12th Sep, 11th Sep, 10th Sep, 9th Sep and 8th Sep. The response does not have any data for 11th sept and 8th Sept.
const buildData = [
{
"project_id": "1H16SET9829",
"created_date": "2021-09-12",
"status": "P"
},
{
"project_id": "1J01SET10974",
"created_date": "2021-09-10",
"status": "F"
},
{
"project_id": "1J01SET10971",
"created_date": "2021-09-09",
"status": "P"
},
{
"project_id": "1J01SET10969",
"created_date": "2021-09-09",
"status": "F"
}
]
Based on this above information, i have to display data in UI using react functional component as follows
Sep 12, 2021 | Sep 11,2021 | Sep 10, 2021 | Sep 09, 2021 | Sep 08, 2021
1H16SET9829 (P) | | 1J01SET10974 (F) | 1J01SET10971 (P) |
| | | 1J01SET10971 (F) |
Can someone please let me know how to achieve this. I tried the following but it doesnot display the correct data. I am not getting how to display correct project_id below its date. Also some dates have 2 project_ids in it. for e.g. Sep 09,2021 has 2 project_ids and both need to be displayed one below the other and then proceed with next date.
const renderProjects = (props) => {
const items = buildData.map( (t, idx) => (
<>
<div>{ t.created_date }</div>
<div>{t.project_id</div>
</>
))
return (
<div className="project-list">
{ items }
</div>
)
}
You can do something like this (see inline comments):
const buildData = [
{
project_id: '1H16SET9829',
created_date: '2021-09-12',
status: 'P',
},
{
project_id: '1J01SET10974',
created_date: '2021-09-10',
status: 'F',
},
{
project_id: '1J01SET10971',
created_date: '2021-09-09',
status: 'P',
},
{
project_id: '1J01SET10969',
created_date: '2021-09-09',
status: 'F',
},
];
export const RenderProjects = (props) => {
// convert the buildData into a map from date -> list of `{project_id, status}`s
const buildDataByDate = buildData.reduce((map, project) => {
const projectInfo = {
project_id: project.project_id,
status: project.status,
};
if (!map[project.created_date]) {
map[project.created_date] = [projectInfo];
} else {
map[project.created_date].push(projectInfo);
}
return map;
}, {});
// find the first and last dates
const minDate = Object.keys(buildDataByDate).sort()[0];
const maxDate = Object.keys(buildDataByDate).sort().reverse()[0];
// find how many days are between them
const daysBetween =
(Date.parse(maxDate) - Date.parse(minDate)) / (24 * 60 * 60 * 1000);
// add in the missing dates
[...Array(daysBetween).keys()].forEach((increment) => {
const dateToAdd = new Date(
Date.parse(minDate) + increment * 24 * 60 * 60 * 1000,
)
.toISOString()
.substring(0, 10);
if (!buildDataByDate[dateToAdd]) {
buildDataByDate[dateToAdd] = [];
}
});
// render something for each entry in that map
const items = Object.entries(buildDataByDate)
.sort((a, b) => {
return Date.parse(b[0]) - Date.parse(a[0]);
})
.map(([date, projects]) => {
return (
<React.Fragment key={date}>
<div>{date}</div>
{projects.map((project) => {
return (
<div
key={project.project_id}
>{`${project.project_id} (${project.status})`}</div>
);
})}
</React.Fragment>
);
});
return <div className='project-list'>{items}</div>;
};

How to prevent object properties from being overwritten

I'm building a function that creates a nested object with dynamic properties which has the year and month as keys.
const sixMonthSummary = {};
// This will get data for the latest 6 months
for (let i = 0; i <= 6; i++) {
const currentDate = new Date();
const [, month, year] = new Date(
currentDate.setMonth(currentDate.getMonth() - i)
)
.toLocaleDateString("en-SG")
.split("/");
sixMonthSummary[year] = {
[month]: {
rent: "",
income: "",
expenses: "",
},
};
}
console.log(sixMonthSummary)
The output only captures the last index and the first index instead
"2020": {
"07": {
"rent": "",
"income": "",
"expenses": ""
}
},
"2021": {
"01": {
"rent": "",
"income": "",
"expenses": ""
}
}
How do I make sure that the other months are not missed out?
You are overwriting the complete object-key at
sixMonthSummary[year] = {}
try to insert the existing object with a spread-operator to include all prev months.
const sixMonthSummary = {};
// This will get data for the latest 6 months
for (let i = 0; i <= 6; i++) {
const currentDate = new Date();
const [, month, year] = new Date(
currentDate.setMonth(currentDate.getMonth() - i)
)
.toLocaleDateString("en-SG")
.split("/");
sixMonthSummary[year] = {
...sixMonthSummary[year],
[month]: {
rent: "",
income: "",
expenses: "",
},
};
}
console.log(sixMonthSummary)
It's because you're resetting the year key each iteration of the loop. Try something like
if(!sixMonthSummary[year]) {
sixMonthSummary[year] = {};
}
sixMonthSummary[year][month] = {
rent: "",
income: "",
expenses: "",
};

Get items for today and yesterday based off timestamp

I have a json object which is generated using lowdb. Each json entry has a timestamp. I wan't to get all the entry for yesterday, and today based on the timestamp.
The items variable here is just a json object. Here is a sample
{
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
}
I want to get the items from yesterday, and today in this functuin
export async function report(){
try {
const items = db.get('items').value();
return items;
} catch (error) {
console.log(error);
}
}
You can compare with time values for the start of "today" and "yesterday", e.g.
// Return time value for the start of given date, default is today
function getToday(d = new Date()) {
return new Date(+d).setHours(0,0,0,0);
}
// Return time value for the start of day prior to given day, default is today
function getYesterday(d = new Date()) {
let e = new Date(getToday(d));
return e.setDate(e.getDate() - 1);
}
let data = {
"items": [
{"date": 1596085802005, // 30 Jul 2020
"item": "1"
},
{"date": 1596131220030, // 31 Jul 2020
"item": "2"
},
{"date": 1596232321030, // 1 Aug 2020
"item": "3"
}
]
}
// Run as for 1 Aug 2020
let yesterday = getYesterday(new Date(2020,7,1));
let result = data.items.filter(item => item.date >= yesterday);
console.log(result);
Results may vary based on the host timezone offset as the above uses local date values.
You need to parse the date, and compare the difference as follows:
let obj = {
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
};
let list = [];
let items = obj.items;
let today = new Date();
for(let i = 0; i < items.length; i++){
var d = new Date(items[i].date);
var diff = Math.floor((d - today) / (1000 * 60 * 60 * 24));
if(diff == 0 || diff == -1)
list.push(items[i].item);
}
console.log(list);

How to calculate the current streak (consecutive days in a row starting at the current date)?

const arr = [
{
"date": "2019-09-18"
},
{
"date": "2019-09-19"
},
{
"date": "2019-09-21"
},
{
"date": "2019-09-22"
},
{
"date": "2019-09-23"
}
]
function currentStreak(arr) {
let count = 0
arr.reverse().forEach((el, i) => {
if (new Date() - new Date(el.date) === i * 86400000) count++
})
return count
}
I'm having a hard time getting this to work. Assuming the current date is "2019-09-23", why is the above code returning 0 when it should return 3?
You are passing the current Date i.e today's date - 5th Nov Tue so the calculation done is on the basis of today's date, you must pass the value of date object
For example :-
const arr = [
{
"date": "2019-09-18"
},
{
"date": "2019-09-19"
},
{
"date": "2019-09-21"
},
{
"date": "2019-09-22"
},
{
"date": "2019-09-23"
}
]
function currentStreak(arr) {
let count = 0
arr.reverse().forEach((el, i) => {
if (new Date('2019-09-23') - new Date(el.date) === i * 86400000) count++
})
return count;
}
console.log(currentStreak(arr))
Since, new Date() gives you date + current time, hence it cannot compare correctly with the New Date(YYYY-MM-DD) which gives time at midnight hours.
If you modify your date to midnight hours, then it will compare correctly. So your code will look like.
function currentStreak(arr) {
let count = 0
arr.reverse().forEach((el, i) => {
if ((new Date().setUTCHours(0,0,0,0) - new Date(el.date).setUTCHours(0,0,0,0)) === i * 86400000) count++
})
return count
}
new Date() returns this - Tue Nov 05 2019 15:16:22 GMT+0800 (Singapore Standard Time)
So in your if condition it will not increment. Change the format of the new Date() and compare it to your array.
const arr = [
{
"date": "2019-09-18"
},
{
"date": "2019-09-19"
},
{
"date": "2019-09-21"
},
{
"date": "2019-09-22"
},
{
"date": "2019-09-23"
}
]
function currentStreak(arr) {
let count = 0
arr.reverse().forEach((el, i) => {
if ((new Date() - new Date(el.date) >= i * 86400000) && (new Date() - new Date(el.date) < (i+1) * 86400000)) count++
})
return count
}
console.log(currentStreak(arr));
It doesn't work because you didn't include minutes, hours, seconds and milliseconds.

How to create an hours + minutes array with moment.js and ES6?

I'm trying to create an array of hours in a day with 30 minute intervals with moment.js and ES6.
Example:
let hours = ["12:00 AM", "12:30 AM", "1:00 AM", "1:30 AM", ..., "11:30 PM"]
I already have this for function:
someFunction () {
const items = []
for (let hour = 0; hour < 24; hour++) {
items.push(moment({ hour }).format('h:mm A'))
items.push(moment({ hour, minute: 30 }).format('h:mm A'))
}
return items
}
But I would like to make it more ES6-like.
I have gotten this far:
someFunction () {
let timeSlots = new Array(24).fill().map((acc, index) => {
let items = []
items.push(moment( index ).format('h:mm A'))
items.push(moment({ index, minute: 30 }).format('h:mm A'))
})
return timeSlots
}
But it outputs:
["1:00 AM", "12:30 AM", "1:00 AM", "12:30 AM", "1:00 AM", "12:30 AM", "1:00 AM", "12:30 AM", "1:00 AM", "12:30 AM", "1:00 AM", "12:30 AM", ...]
function someFunction () {
const items = [];
new Array(24).fill().forEach((acc, index) => {
items.push(moment( {hour: index} ).format('h:mm A'));
items.push(moment({ hour: index, minute: 30 }).format('h:mm A'));
})
return items;
}
You can use array#from with array#reduce to generate 30 minutes interval time.
let someFunction = () => {
return Array.from({length: 24}, (_,i) => i).reduce((r,hour) => {
r.push(moment({hour, minute: 0}).format('h:mm A'));
r.push(moment({hour, minute: 30}).format('h:mm A'));
return r;
}, []);
}
console.log(someFunction());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
here is working code:
someFunction = () => {
var items = []
var currentDate = moment('12');
new Array(48).fill().map((acc, index) => {
items.push(currentDate.format('h:mm A'))
currenDate = currentDate.add(30, 'minutes');
})
return items
}
console.log(someFunction());
Working fiddle: http://jsfiddle.net/ekqxhwf4/1/
You could use Array.from method to generate 2d array and then concat with spread syntax to create 1d array.
function create () {
return [].concat(...Array.from(Array(24), (_, hour) => ([
moment({hour}).format('h:mm A'),
moment({ hour, minute: 30 }).format('h:mm A')
])))
}
console.log(create())
<script src="http://momentjs.com/downloads/moment.js"></script>
I know momentJS was a requirement, but could also be easily solved with ordinary JavaScript Date objects:
function everyXMilliseconds(x) {
if (x === void 0) {
x = 86400000;
}
var base = new Date(86400000);
var currentDate = new Date(86400000);
var dates = [];
while (currentDate.getUTCDate() === base.getUTCDate()) {
dates.push(new Date(currentDate.getTime()));
currentDate.setTime(currentDate.getTime() + x);
}
return dates;
}
function everyXSeconds(x) {
if (x === void 0) {
x = 86400;
}
return everyXMilliseconds(x * 1000);
}
function everyXMinutes(x) {
if (x === void 0) {
x = 1440;
}
return everyXSeconds(x * 60);
}
function everyXHours(x) {
if (x === void 0) {
x = 24;
}
return everyXMinutes(x * 60);
}
//Offsets date with its own timezone difference
function toLocalTime(date) {
date.setUTCHours(date.getUTCHours() + date.getTimezoneOffset() / 60);
return date;
}
//TEST
//get dates
var dates = everyXHours(0.5);
// dates to time
console.log('UTC times', dates.map(function(d) {
return d.toLocaleTimeString("uk");
}));
// dates to time localized
console.log('Local times', dates.map(toLocalTime).map(function(d) {
return d.toLocaleTimeString("uk");
}));
My snippet above is bit overly complicated, but it illustrates that you can make really flexible system without need to import libraries.
you can get the value with the label.
function someFunction () {
const items = [];
new Array(24).fill().forEach((acc, index) => {
items.push({"value": moment( {hour: index} ).format('HH:mm'), "label": moment( {hour: index} ).format('h:mm A')});
items.push({"value": moment({ hour: index, minute: 30 }).format('HH:mm'), "label": moment({ hour: index, minute: 30 }).format('h:mm A')});
})
return items;
}
An even shorter version would be:
const someFunction = () =>
Array(48)
.fill()
.map((_, index) =>
moment({
hour: Math.floor(0.5 * index),
minute: 30 * (index % 2)
})
.format("h:mm A"));

Categories