Finding max/min date in multidimensional JavaScript object - javascript

What's the easiest way to find the earliest start date and latest end date from the object below?
(Sorry - I realize there are a lot of similar questions already out there, but my JS skills are poor and I haven't been able to apply any of the solutions to my own data. So with that said, a code example would definitely help me out in any answers - thanks!!)
var ganttData = [
{
"id": 123456,
"name": "Sample Project",
"start": new Date(2010,11,6),
"end": new Date(2011,0,6),
"status": "Not Started",
"phase": [
{
"id": 123457,
"name": "Sample Phase",
"start": new Date(2010,11,6),
"end": new Date(2010,11,13),
"status": "Not Started",
"task": [
{
"id": 123458,
"name": "Sample Task",
"start": new Date(2010,11,6),
"end": new Date(2010,11,8),
"status": "Not Started"
}
]
},
{
"id": 123459,
"name": "Another Phase",
"start": new Date(2010,11,13),
"end": new Date(2011,0,20),
"status": "Not Started"
}
]
}
]

You could simply traverse the tree recursively
var max = new Date(-100000000*86400000);
var min = new Date( 100000000*86400000);
function compare(key,value) {
if (key == "start" && value < min)
min=value;
else if (key == "end" && value > max)
max=value;
}
function traverse(obj, fun) {
for (prop in obj) {
fun.apply(this,[prop, obj[prop]]);
if (typeof(obj[prop]) == "object") {
traverse(obj[prop], fun);
}
}
}
traverse(ganttData, compare);
> max
Thu Jan 20 2011 00:00:00 GMT+0100 (W. Europe Standard Time)
> min
Mon Dec 06 2010 00:00:00 GMT+0100 (W. Europe Standard Time)
The above worked until you changed start and end from being a Date to being a string. Now you have to do something like this
arr = "2010,11,13".split(",");
date = new Date(arr[0], arr[1], arr[2]);
before you compare.
I got the reversed min and max dates from the JavaScript Reference.

function getEarliestAndLatest(ganttData) {
var earliest = ganttData.start,
latest = ganttData.end,
phase,
task;
for (var i = 0, countPhases = ganttData.phase.length; i < countPhases; i++) {
phase = ganttData.phase[i];
if (phase.start < earliest) {
earliest = phase.start;
}
if (phase.end > latest) {
latest = phase.end;
}
if (typeof phase.task !== 'undefined') {
for (var j = 0, countTasks = phase.task.length; j < countTasks; j++) {
task = phase.task[j];
if (task.start < earliest) {
earliest = task.start;
}
if (task.end > latest) {
latest = task.end;
}
}
}
}
return { earliest: earliest, latest: latest };
}

Related

Create a new array based on an existing filtering

I'm writing a code that has a requirement of filtering an array of objects with a string and creating a new array based on the filtered value.
Here is my code.
var a = [{
"label": "June - 2021",
"value": "June"
}, {
"label": "May - 2021",
"value": "May"
}, {
"label": "April - 2021",
"value": "April"
}];
var b = ["June", "May"];
var healthTemp = [];
a.forEach(item => {
var idx = b.value.indexOf(item);
console.log(idx);
if (idx == 0) healthTemp.add('Previous month')
if (idx == 1) healthTemp.add('2 months ago')
if (idx == 2) healthTemp.add('3 months ago')
});
Here since there is June and May in b are in indexes 0, 1, I want healthTemp to be ['Previous month', '2 months ago']. But this gives me an error. Please let me know where am I going wrong and how can I fix this?
Thanks Chris for the suggestion, I've updated my question by replacing = with ==. Now I get the error as Uncaught TypeError: Cannot read property 'indexOf' of undefined".
I think what you want to do is this:
var a = [{
"label": "June - 2021",
"value": "June"
}, {
"label": "May - 2021",
"value": "May"
}, {
"label": "April - 2021",
"value": "April"
}];
var b = ["June", "May"];
var healthTemp = [];
healthTemp
b.forEach (month => {
a.forEach((item,idx) => {
if(item.value == month) {
console.log(idx);
if (idx == 0) healthTemp.push('Previous month')
if (idx == 1) healthTemp.push('2 months ago')
if (idx == 2) healthTemp.push('3 months ago')
}
})
})
Another version:
const a = [{
"label": "June - 2021",
"value": "June"
}, {
"label": "May - 2021",
"value": "May"
}, {
"label": "April - 2021",
"value": "April"
}];
const b = ["June", "May"];
function foo(){
const healthTemp = [];
a.forEach(item => {
const idx = b.indexOf(item.value);
if(idx >=0){
idx === 0 ? healthTemp.push('Previous month') : healthTemp.push(`${idx+1} months ago`)
}
});
return healthTemp
}
console.log(foo())
If I understand correctly your problem, I would solve it as follows:
// Given a `mont` string, find the first item of `a` whose `value` property
// equals the `month` string
// If month matches the first item of `a`, return "Previous month";
// If month matches the second item of `a`, return "2 months ago";
// If month matches the third item of `a`, return "3 months ago";
// etc...
// If month doesn't match any item of `a`, return "Never"
function howLongAgo (month) {
for (let i=0; i<a.length; i++) {
if (a[i].value === month) {
return i == 0 ? "Previous month" : `${i+1} months ago`;
}
}
return "Never";
}
const healthTemp = b.map(howLongAgo);

Reading from API And compare Date to display something

So, the this is about consuming an API that has a date/time property. The content should change every 3 hours by comparing current user Date/time with that of the API and also assigning past and upcoming hours in a separate an arrays to be displayed in other section of the page. I managed to assign past and upcoming dates to their respective arrays. I need to compare the date and to assign "current data" if the user Date/Time is equal to or within 3 hours in a property to display it for the whole duration of three hours.
this.dataService.getData().subscribe((data:any[])=>{
const now = new Date('2021-02-14 09:00:00');
for (const item of data) {
const apiDate = new Date(item.dateTime);
if(now.getTime() > apiDate.getTime()){
this.future.push('future dates')
} else if(now.getTime() < apiDate.getTime()){
this.past.push('past dates')
}else if(now.getTime() == apiDate.getTime()){
//in real time, they'll only be equal for one second
this.current = 'Show NOW'
}
}
This is the structure of API/Json Data retuned
[ { "number": 10, "dateTime": "2021-02-14 00:00:00" }, { "number": 20, "dateTime": "2021-02-14 03:00:00" }, { "number": 30, "dateTime": "2021-02-14 06:00:00" }, { "number": 40, "dateTime": "2021-02-14 09:00:00" }, { "number": 50, "dateTime": "2021-02-14 12:00:00" }]
a better approach to this would even be better.
Thanks
If your want to show time within range, then you can create an object with your time boundaries:
getTimeInterval = () => {
const from = new Date();
const to = new Date(from);
to.setHours(to.getHours() + 3)
return { from, to };
}
and then just check both boundaries of date from and to:
this.dataService.getData().subscribe((data:any[])=>{
const dateRange = this.getTimeInterval();
for (const item of data) {
const apiDate = new Date(item.dateTime);
if (dateRange.from.getTime() > apiDate.getTime()
&& dateRange.to.getTime() > apiDate.getTime())
{
this.future.push('future dates');
}
else if(dateRange.from.getTime() < apiDate.getTime())
{
this.past.push('past dates')
}
else if (dateRange.from.getTime() >= apiDate.getTime()
&& dateRange.to.getTime() <= apiDate.getTime())
{
this.current = 'Show NOW'
}
}

Find the least and max date in array using yyyy-mm-dd format

How can I get the least and max date in an array using YYYY-mm-dd format? Here is a sample of my date values.
const data = [{
"date": "2012-10-21",
"value": 60
}, {
"date": "2012-10-22",
"value": 61
}, {
"date": "2012-10-23",
"value": 69
}, {
"date": "2012-10-24",
"value": 67
}]
console.log(data);
You can use reduce and Date.parse
const data = [{"date": "2012-10-21","value": 60}, { "date": "2012-10-22","value": 61}, {"date": "2012-10-23","value": 69}, {"date": "2012-10-24","value": 67}]
let maxDate = data.reduce((op,inp)=>{
if(Date.parse(inp.date) > Date.parse(op.max)){
op.max = inp.date
}
if(Date.parse(inp.date) < Date.parse(op.max)){
op.least = inp.date
}
return op
},{least:data[0].date,max:data[0].date})
console.log(maxDate)
If you just want the dates you can use Math.min and Math.max if you map your array to dates using .map:
const data = [{
"date": "2012-10-21",
"value": 60
}, {
"date": "2012-10-22",
"value": 61
}, {
"date": "2012-10-23",
"value": 69
}, {
"date": "2012-10-24",
"value": 67
}];
const dates = data.map(({date}) => new Date(date));
const minDate = new Date(Math.min(...dates));
const maxDate = new Date(Math.max(...dates));
console.log("min", minDate.toISOString().slice(0,10));
console.log("max", maxDate.toISOString().slice(0,10));
Alternatively, you could sort the array and use the first and last elements:
const data = [{
"date": "2012-10-21",
"value": 60
}, {
"date": "2012-10-22",
"value": 61
}, {
"date": "2012-10-23",
"value": 69
}, {
"date": "2012-10-24",
"value": 67
}];
const dates = data.map(({date}) => new Date(date));
const sortedDates = dates.sort((a, b) => a - b);
const minDate = sortedDates[0];
const maxDate = sortedDates[sortedDates.length-1];
console.log("min", minDate.toISOString().slice(0,10));
console.log("max", maxDate.toISOString().slice(0,10));
You could reduce the data and take just a string comparison.
const
data = [{ date: "2012-10-21", value: 60 }, { date: "2012-10-22", value: 61 }, { date: "2012-10-23", value: 69 }, { date: "2012-10-24", value: 67 }],
result = data.reduce((r, { date }) => {
if (!r) return { min: date, max: date };
if (r.min > date) r.min = date;
if (r.max < date) r.max = date;
return r;
}, undefined);
console.log(result);
If this is the date format used, a simple .sort() on the date property will work. The earliest date is the first element the array and the last date the last element.
This is the big advantage of using a date format ( like the ISO standard ) where the lexical storting by string value is the same as the logical sorting by date.
const data = [{
"date": "2012-10-21",
"value": 60
}, {
"date": "2012-10-22",
"value": 61
}, {
"date": "2012-10-23",
"value": 69
}, {
"date": "2012-10-24",
"value": 67
}, {
"date": "2012-10-22",
"value": 102
}];
const sorted_by_date = data.sort(( a, b ) => a.date.localeCompare( b.date ));
const earliest_date = sorted_by_date[ 0 ];
const latest_date = sorted_by_date[ sorted_by_date.length - 1 ];
console.log( earliest_date );
console.log( latest_date );
function checkDate(data,condition){
if(condition == 'max'){
var max = 0
data.map((item)=>{
if(new Date(item.date)>max){
max = new Date(item.date)
}
})
return max;
}else if(condition == 'least'){
var least = new Date()
data.map((item)=>{
if(new Date(item.date)<least){
least = new Date(item.date)
}
})
return least;
}
}

How to find upcoming event in array based on current time

I have an array of events and i'd like to iterate through that array and find the next upcoming event based on its start time compared to the current start time.
Basically, say its currently 3:30pm and there are events starting at 12:00pm, 2pm, 4pm, 5pm.. I'd like to get the event that starts at 4pm.
SAMPLE DATA:
{
"cache_time": 1470678992,
"events": [
{
"title": "EVENT TITLE",
"start_time": "12:00AM",
"end_time": "12:00AM"
},
{
"title": "EVENT TITLE",
"start_time": "8:00AM",
"end_time": "10:00AM"
},
{
"title": "EVENT TITLE",
"start_time": "10:00AM",
"end_time": "12:00PM"
},
{
"title": "EVENT TITLE",
"start_time": "1:00PM",
"end_time": "2:30PM"
},
{
"title": "EVENT TITLE",
"start_time": "2:30PM",
"end_time": "3:00PM"
},
{
"title": "EVENT TITLE",
"start_time": "3:00PM",
"end_time": "4:00PM"
}
]
}
EDIT:
what i've done so far to get the CURRENT meeting but i'm having trouble getting the next meeting when the current meeting is UNKNOWN.
var _this = this;
var date = new Date();
var currentHour = date.getHours();
var currentMins = date.getMinutes();
var reqStartTime = new Date();
reqStartTime.setHours(currentHour, currentMins, 0);
var reqEndTime = new Date(reqStartTime.getTime() + 2 * 60000);
for (var e in EVENT_DATA.events) {
var start_time = EVENT_DATA.events[e].start_24time;
var end_time = EVENT_DATA.events[e].end_24time;
var startTime = new Date();
var endTime = new Date();
startTime.setHours(start_time.substring(0,2), start_time.substring(3,5), 0);
endTime.setHours(end_time.substring(0,2), end_time.substring(3,5), 0);
if ( (reqEndTime > startTime && reqEndTime < endTime) || (reqStartTime > startTime && reqStartTime < endTime) ) {
return EVENT_DATA.events[e];
}
}
Because your start_time is a non-standard format, one thing we will need to do is convert it into a usable value. We will combine it with the start_date to get our comparison value.
Since we can't assume the events are in order, we'll also be taking that into account.
(function(data) {
var currentTime = new Date();
var getStartTime = function(event) { // This function converts the time into a usable format and returns it as a Date object
try {
return new Date(event.start_date + ' ' + event.start_time.replace(/(AM|PM)/, ' $1'));
} catch(ex) { return null; }
};
var sortedEvents = jQuery(data.events).sort(function(a, b) {
return getStartTime(a) > getStartTime(b) ? 1 : -1;
}).toArray(); // Get an array of sorted events
for (var i = 0; i < sortedEvents.length; i++) {
if (getStartTime(sortedEvents[i]) < currentTime) { continue; }
return sortedEvents[i]; // Starts now or after
}
return null; // No matches
})(sample_data);
Original sample data from question:
"events": [
{
"title": "EVENT TITLE",
"start_time": "12:00AM",
"end_time": "12:00AM",
"start_24time": "00:00",
"end_24time": "00:00",
"start_date": "July 29, 2016",
"end_date": "September 03, 2016",
"display_date": "July 29 - September 03, 2016"
}, ...
]

Outputting content from JSON when you don't know the names of the first Objects

var myData = {
"result": "success",
"theBox": {
"Brands": [{
"lastPublishTime": null,
"id": "e054e3d5-143c-4eab-9fc2-7740edce7d09",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand A"
}, {
"lastPublishTime": "09:42 Tue Apr 29 2014 BST",
"id": "402f3c42-3d8d-45d6-8c50-c5d1b5025c23",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand B"
}],
"Products": [{
"lastPublishTime": null,
"id": "db35610c-3148-4b89-856c-66f907206037",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Product 1"
}],
"OtherStuff": []
}
}
var theTabsNames = (Object.getOwnPropertyNames(data.sandbox));
var arrayLength = theTabsNames.length;
for (var i = 0; i < arrayLength; i++) {
if (theTabsNames[i] != null) {
//var tabNumber = [i] + 1;
//console.log("Number:" +tabNumber);
var theTabName = theTabsNames[i];
var voiceSession = data.sandbox.theTabName;
//console.log("AAA" +voiceSession);
console.log("Name :" + voiceSession);
// var voiceSession = theTabsName[i];
var arrayLengthL = theTabName.length;
for (var j = 0; j < arrayLengthL; j++) {
if (data.sandbox.theTabName[j] != undefined) {
console.log("Name :" + data.sandbox.Brands[j].name);
console.log("lastUpdateTime :" + data.sandbox.Brands[j].lastUpdateTime);
console.log("lastPublishTime :" + data.sandbox.Brands[j].lastPublishTime);
console.log("Id :" + data.sandbox.Brands[j].id);
}
}
//Do something
}
}
I have no problem outputting this JSON but my issue is that values such as Brands, Products & OtherStuff might not be the same.
How do I find the names of the Objects then use them here? I can output the actual values but then they don't work when I try to use them to find the nodes.
console.log("Name :" +data.sandbox.Brands[j].name);
I've recently had to do something similar and ended up pushing the keys into an array then iterating over this array to get the key name. The solution for me came from this question here: Getting JavaScript object key list
I couldn't use Object.keys() because I had to support IE 7 & 8.
Here's an example:
var myData = {
"result": "success",
"theBox": {
"Brands": [{
"lastPublishTime": null,
"id": "e054e3d5-143c-4eab-9fc2-7740edce7d09",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand A"
}, {
"lastPublishTime": "09:42 Tue Apr 29 2014 BST",
"id": "402f3c42-3d8d-45d6-8c50-c5d1b5025c23",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand B"
}],
"Products": [{
"lastPublishTime": null,
"id": "db35610c-3148-4b89-856c-66f907206037",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Product 1"
}],
"OtherStuff": []
}
}
var keys = [];
for(var theKey in myData.theBox) {
keys.push(theKey);
}
for (var i=0; i < keys.length; i++) {
var arrayLength = myData.theBox[keys[i]].length;
for (var j=0; j < arrayLength; j++) {
console.log(keys[i]);
console.log("Name :" + myData.theBox[keys[i]][j].name);
console.log("lastUpdateTime :" + myData.theBox[keys[i]][j].lastUpdateTime);
console.log("lastPublishTime :" + myData.theBox[keys[i]][j].lastPublishTime);
console.log("Id :" + myData.theBox[keys[i]][j].id);
}
}
You can get the keys with the help of Object.keys(obj) function
var myData = {
"result": "success",
"theBox": {
"Brands": [{
"lastPublishTime": null,
"id": "e054e3d5-143c-4eab-9fc2-7740edce7d09",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand A"
}, {
"lastPublishTime": "09:42 Tue Apr 29 2014 BST",
"id": "402f3c42-3d8d-45d6-8c50-c5d1b5025c23",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Brand B"
}],
"Products": [{
"lastPublishTime": null,
"id": "db35610c-3148-4b89-856c-66f907206037",
"lastUpdateTime": "09:42 Sun Apr 27 2014 BST",
"name": "Product 1"
}],
"OtherStuff": []
}
}
var x = Object.keys(myData.theBox)
alert(x.toString())
You can parse through the key names and get the corresponding values with that key
UPDATE
Added the script to get the values
var x = Object.keys(myData.theBox)//Get the Keys
for (var i=0; i < x.length; i++)//Iterate through the keys
{
var nodesCount = myData.theBox[x[i]].length;//number of such nodes
for (var j=0; j < nodesCount; j++) {
alert("Name :" + myData.theBox[x[i]][j].name);//get the values
}
}
Check this fiddle

Categories

Resources