2

Please check if you can help anyone. I have been working on my weather app which I am building on React using axios with openweathermap.org and I am kind of stuck to get data the way I need it. I am using its 5day forecast. It gives you a report with every 3 hours forecast for 5 days.It gives you 40 reports for 5 days. so you get 8 reports for the 3 days in between and for current and the fifth day you get the remaining based on how much time left for current day. This is the API response for the report: report. So you will get this as the reponse:

{
  "data": {
"cod": "200",
"message": 0.0062,
"cnt": 39,
"list": [
  {
    "dt": 1540177200,
    "main": {
      "temp": 24.55,
      "temp_min": 20.88,
      "temp_max": 24.55,
      "pressure": 1008.67,
      "sea_level": 1025.96,
      "grnd_level": 1008.67,
      "humidity": 58,
      "temp_kf": 3.67
    },
    "weather": [
      {
        "id": 800,
        "main": "Clear",
        "description": "clear sky",
        "icon": "02d"
      }
    ],
    "clouds": {
      "all": 8
    },
    "wind": {
      "speed": 3.82,
      "deg": 340.5
    },
    "sys": {
      "pod": "d"
    },
    "dt_txt": "2018-10-22 03:00:00"
  },
  {
    "dt": 1540188000,
    "main": {
      ...
    },
  },
  {
    "dt": 1540198800,
    "main": {
     ...
    },
  },
  {
    "dt": 1540587600,
    "main": {
      . . .
    }
  }
]
}

I just summarised it.I just put in the whole data for the first item and for the rest I put in ... and it is a long array with 40 items. Each one has a unique date timestamp which is "dt" in the beginning of it. I need to get 5 arrays based on a specific day. for that I thought of converting the timestamp(dt) and then get all the items that result in the same "Day". Convert the timestamp like this (using forEach for all items):

 let day ='';
 day = new Date(dt *1000);
 day = day.getDate();

There are two problems when I get converted array:

  • I get one big array with 40 items again but I need 5 arrays based on the date so that I have the report of each day seperate
  • Secondly I loose the dt in timestamp. I need to keep that so that I can show the weather forecast in my application.

I want to show the info based on that timestamp for 5 days seperate.

Thanks for your help and ideas everyone.

Community
  • 1
  • 1
azad6026
  • 139
  • 1
  • 3
  • 11

5 Answers5

1

You can do this by first creating an object to hold reports for each day from the current date to 5 days in the future. Then iterate over the elements of "list" and put each (report) in the correct place in the object.

Here is an example:

Note that response in this code is equal to the data you included in your question.

const today = new Date();
const day = 60 * 60 * 24 * 1000;

const dateBins = {};
const nBins = 6; // there can be reports for up to 6 distinct dates

for (let i = 0; i < nBins; i++) {
    // set up a bin (empty array) for each date
    const date = new Date(today.getTime() + i * day);
    dateBins[date.getDate()] = [];
}

const reports = response.data.list;
for (const report of reports) {
    const reportDate = new Date(report.dt * 1000).getDate();
    dateBins[reportDate].push(report);
}

Changing the declaration of today to new Date('2018-10-21T00:00:00.000Z') will allow this code to work with the specific data you've posted.

Result of dateBins with your posted data:

{ '21':
    [ { dt: 1540177200,
       main: [Object],
       weather: [Array],
       clouds: [Object],
       wind: [Object],
       sys: [Object],
       dt_txt: '2018-10-22 03:00:00' },
     { dt: 1540188000, main: {} } ],
  '22': [ { dt: 1540198800, main: {} } ],
  '23': [],
  '24': [],
  '25': [],
  '26': [ { dt: 1540587600, main: {} } ] }
Henry Woody
  • 14,024
  • 7
  • 39
  • 56
1

I looked through lots of options and reduce was my answer. I needed to regroup my response based on one value which was the day as I have 5 days so I would have an array grouped by day holding all information for the same day. I also needed to keep my timestamp as I needed the time of the day for that report.

 // get the weather data and recreate an array 
// having day and time(hour in my case) in the new array

        const allData = [];
        Object.entries(weatherInfo).forEach(([key, value]) => {
            const dateTime = new Date(value.dt * 1000);
            const day = dateTime.getDate();
            const time = dateTime.getHours();
            // recreate objects of the array adding time anda day and 
            // keeping timestamp and the rest of the info
            const item = {
                day: day,
                time: time,
                ...value
            };
            allData.push(item);
            return allData;
        });

Then I have a new array which I can use reduce thanks to this answer and get the result that I was looking for:

// Now reduce it to an array grouped by day
    const groupedByDay = "day";
    const groupedArray = allData;
    const groupBy = (groupedArray, groupedByDay) => {
        return groupedArray.reduce((acc, obj) => {
            const key = obj[groupedByDay];
            !acc[key] ? (acc[key] = []) : acc[key].push(obj);
            return acc;
        }, {});
    };
    console.log(groupBy(groupedArray, groupedByDay));

I can simply remove those two const definitions on top and do this:

    const groupBy = (groupedArray, groupedByDay) => {
        return groupedArray.reduce((acc, obj) => {
            const key = obj[groupedByDay];
            !acc[key] ? (acc[key] = []) : acc[key].push(obj);
            return acc;
        }, {});
    };
    console.log(groupBy(allData, 'day'));
azad6026
  • 139
  • 1
  • 3
  • 11
1

I got an easy way below PS:Don't Skip seeing the code length , I have tried to explain my code in there and that's why it's looking lengthy !


   const daysArray = []; 
   app.post("/", function (req, res) {
   const cityName = req.body.cityName;
   const url =
    "https://api.openweathermap.org/data/2.5/forecast?q=" +
    cityName +
    "&appid={api_key}&units=metric";
    https.get(url, function (response) {
    response.on("data", function (data) {
      const weatherData = JSON.parse(data);

***// The main part starts from below*** 

      const time = new Date().getHours(); 
//1)We got hold of current time(24 hr - format) 
      weatherData.list.forEach(function (single) {
        var textHour = single.dt_txt.substring(11, 13);
//2)We got hold of hour from weatherData
//example "dt_txt": "2020-07-28 21:00:00" ( var textHour= '21')
        var numberHour = parseInt(textHour, 10);
//2) We converted string '21' to int 21 !
        var difference = Math.abs(time - numberHour);
//3) In order to get latest time we finded out the difference 
// i.e. The data from API comes strictly from 00:00 then 3 ,6 , ..,21,24 aka 00:00
// In order to get latest time we finded out the difference 
//example if it was 22:00 the 22(time)-21(numberHour)=1(difference)
        if (
          difference === 1 ||
          difference === 0 ||
          (time === 23 && numberHour === 21) ||
          (time === 24 && numberHour === 0) ||
          (time === 2 && numberHour === 00)
        ) 
//Here in first case 
//If it was time=22 & numberHour=21 then difference=1
//Second Case if time=21 & numberHour=21 then difference =0 
//Third Case if it was time=23 then 23-21=2 and the difference would be 2(Special Case)
//Fourth Case time=24 numberHour=0 , difference =24 (Special Case)
//Fifth Case time=2 numberHour=0:00 , difference = 2 (Special Case)
//NOW FOR ALL THE REST THE DIFFERENCE WOULD ONLY BE '0' AND '1'
{
          daysArray.push(single);
//We pushed the satisfied timings in our daysArray 
        }
      });
      console.log(daysArray);
//BOOM , In console you will be seeing the 5-day data and that too closest to //your current time !
      res.render("forecast", { daysArray: daysArray });
    });
  });
});
 

I am new in this programming world, My first helping hand ! Hope it's up to the mark , Feel free to suggest corrections :)

Raxy
  • 335
  • 1
  • 3
  • 9
0

//try your code with dt_text format it using this code below and then use that //I tried your code it gabe me undefined

console.log(formatDate("2014-07-23 09:00:00"));
function formatDate(date) {
    let d = new Date(date),
      month = '' + (d.getMonth() + 1),
      day = '' + d.getDate(),
      year = '' + d.getFullYear();
    if (month.length < 2) month = '0' + month;
    if (day.length < 2) day = '0' + day;
    return formattedDate = year + month + day;
  }
Pari Baker
  • 696
  • 4
  • 19
  • Thanks for your answer but I don't need the year and month only the date. So the conversion is not my problem. It works for me. My problem is how to create the array the way I need it based on day. – azad6026 Oct 24 '18 at 02:12
0
    //make a empty map for daily data    
    var dailyData={};

    weatherData.list.map(item => {
       const dateTime = new Date(item.dt * 1000);
       const day = dateTime.getDate();
       const time = dateTime.getHours();
       // check if dailyData map has it
       if(!dailyData[day] )
        dailyData[day]=[];
       dailyData[day].push({...item,day,time});    
    });

Found a simpler solution with 0(n) complexity.

Speedyankur
  • 152
  • 6