I'm using the openweathermap API to get weather forecast data. I want to make sure that the forecast values are at minimum 2 hours in the future. The API is providing the forecast in 3 hour steps, so I need to make sure that the weather data are in the future.
Here is an example response provided by openweathermap API:
{"city":{"id":1851632,"name":"Shuzenji", "coord":{"lon":138.933334,"lat":34.966671}, "country":"JP", "cod":"200", "message":0.0045, "cnt":38, "list":[{ "dt":1406106000, "main":{ "temp":298.77, "temp_min":298.77, "temp_max":298.774, "pressure":1005.93, "sea_level":1018.18, "grnd_level":1005.93, "humidity":87 "temp_kf":0.26}, "weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}], "clouds":{"all":88}, "wind":{"speed":5.71,"deg":229.501}, "sys":{"pod":"d"}, "dt_txt":"2014-07-23 09:00:00"} ]}
I'm using JSON. The list
property has the value dt_txt
in this format: year-month-day 09:00:00
. Now I need to check if this DateTime is minimum 2 hours in the future and if not I simply take the item at index 1
of the list.
I wrote following code:
// look for next prediction
var weatherList = parsed.list;
// Check which time is relevant
// Get only time without description or/and date
// 2017年03月17日 21:00:00
// ~~~~~~~~~~~~~^
var columnIndex = weatherList[0]["dt_txt"].indexOf(":") - 2;
// 2017年03月17日 21:00:00
// ~~~~~~~~~~~^
var apiHoursString = weatherList[0]["dt_txt"].substring(columnIndex, columnIndex + 2);
// server time:
var hours = String((new Date()).getHours());
if(hours.length < 2){
hours = "0" + hours;
}
var apiHoursInt = parseInt(apiHoursString);
var hoursInt = parseInt(hours);
if((apiHoursInt - hoursInt) < 2){
indexToUse = 1
}
I know this code is bad - what is the proper way to do that on Node.js?
1 Answer 1
I would not parse the dt_txt
field. You would have to make too many assumptions including the format of the date (Is it yyyy-mm-dd or the American mm-dd-yyyy) and the time zone. Instead create a date object from the dt
field:
var apiHours = (new Date(weatherList[0].dt * 1000)).getHours();
All those operations to add 0
and do hours to string to integer conversions are redundant. The following should be sufficient:
let weatherList = parsed.list;
let apiHours = (new Date(weatherList[0].dt * 1000).getHours();
let serverHours = (new Date()).getHours();
let indexToUse = (apiHours - serverHours < 2) ? 1 : 0;
Update 1
David is right, I had missed that point. A better solution would be:
// All values in milliseconds
const oneHour = 60 * 60 * 1000;
let apiTime = weatherList[0].dt * 1000;
let serverTime = (new Date()).valueOf();
let indexToUse = (apiTime - serverTime < 2 * oneHour) ? 1 : 0;
-
\$\begingroup\$ What is that line:
(new Date(weatherList[0].dt * 1000).getHours();
- especially multiplying it with 1000 - doing? \$\endgroup\$Matthias Herrmann– Matthias Herrmann2017年03月20日 18:34:49 +00:00Commented Mar 20, 2017 at 18:34 -
1\$\begingroup\$ The 'dt' field in your result is the number of seconds since the Unix epoch. I multiplied that by 1000 to convert it to milliseconds and used it to create a date object representing the time of the forecast. \$\endgroup\$Marc Rohloff– Marc Rohloff2017年03月21日 00:00:44 +00:00Commented Mar 21, 2017 at 0:00
-
\$\begingroup\$ Won't this fail if the values straddle midnight?
apiHours = 2, serverHours = 23, apiHours - serverHours < 2 === true
so it skips the first value even though it's in the future. It may also get tricked up by daylight savings time. How about just comparing the raw timestamps which are monotonic increasing? \$\endgroup\$David Harkness– David Harkness2017年03月22日 01:57:11 +00:00Commented Mar 22, 2017 at 1:57