简体   繁体   中英

How can i comparing times correctly in 24h format?

I get an object with times like this:

const times = {
   "sunrise": "Wed Jul 08 2020 05:17:15 GMT+0200", //this is a date object not a string
   "goldenHourEnd:" "Wed Jul 08 2020 06:12:13 GMT+0200",
   "morning": "Wed Jul 08 2020 08:04:20 GMT+0200",
   "solarNoon": "Wed Jul 08 2020 13:35:04 GMT+0200",
   "evening": "Wed Jul 08 2020 19:05:48 GMT+0200",
   "goldenHour": "Wed Jul 08 2020 20:57:55 GMT+0200",
   "sunset": "Wed Jul 08 2020 21:52:53 GMT+0200",
   "nauticalDusk": "Wed Jul 08 2020 23:57:10 GMT+0200"
};

At the moment, i am using this function to get the current Phase, based on the current client time:

function getCurrentTimePhase(object) {
  return Object.entries(object)
  .map(([k, v]) => [ k, Date.now() - Date.parse(v) ])
  .reduce((pre, cur) => cur[1] < pre[1] && cur[1] > 0 ? cur : pre)[0];
}

The problem is that the function does not always return the current time phase. For Example:

//current client time is Wed Jul 08 2020 01:31:04 GMT+0200
const currentPhase = getCurrentTimePhase(times);
console.log(currentPhase); //output: solarNoon

The Function will be returned solarNoon . Actually the function should be returned nauticalDusk, because we are still in this phase. The next phase sunrise starts at Wed Jul 08 2020 05:17:15 GMT+0200 , which should be returned when I have passed this time mark and so on.

How can i solve this? Any ideas?

Running your code and replacing Date.now() with new Date('Wed Jul 08 2020 01:31:04 GMT+0200') the result I get is "sunrise". That's because there is no initial value for the accumulator passed to reduce , so the first two elements of Object.entries(times) are passed and ['sunrise', 'Wed Jul 08 2020 05:17:15 GMT+0200'] is initially assigned to the accumulator. No current value fits the criteria to replace the initial accumulator so it's returned.

I think the use of map is redundant, and reduce is inefficient as the loop should stop as soon as a suitable value is found.

The following uses findIndex to get the first phase after the passed date (default is the current date and time), then gets the previous phase. If there is no phase either before or after the date, the last phase is used.

I also put in a sort to ensure the entries are suitably ordered.

 let times = { "sunrise": new Date('Wed Jul 08 2020 05:17:15 GMT+0200'), "goldenHourEnd": new Date('Wed Jul 08 2020 06:12:13 GMT+0200'), "morning": new Date('Wed Jul 08 2020 08:04:20 GMT+0200'), "solarNoon": new Date('Wed Jul 08 2020 13:35:04 GMT+0200'), "evening": new Date('Wed Jul 08 2020 19:05:48 GMT+0200'), "goldenHour": new Date('Wed Jul 08 2020 20:57:55 GMT+0200'), "sunset": new Date('Wed Jul 08 2020 21:52:53 GMT+0200'), "nauticalDusk": new Date('Wed Jul 08 2020 23:57:10 GMT+0200') }; function getCurrentTimePhase(data, date = new Date()) { // Ensure phases are sorted by date and time let entries = Object.entries(data).sort((a, b) => a[1] - b[1]); // Find index of first phase that is after date let i = entries.findIndex(phase => date - phase[1] < 0); // Return phase prior to the one found // If no prior phase, or none found (i == -1), return last phase return entries[i <= 0? entries.length - 1: i-1][0]; } // Test dates [new Date('Wed Jul 08 2020 01:31:04 GMT+0200'), // Before sunrise, return nauticalDusk new Date('Wed Jul 08 2020 06:12:12 GMT+0200'), // After sunrise, before goldenHourEnd, return sunrise new Date('Wed Jul 08 2020 13:35:05 GMT+0200'), // After solarNoon, before evening, return solarNoon new Date('Wed Jul 08 2020 21:52:54 GMT+0200'), // After sunset, before goldenHourEnd, return sunset new Date('Wed Jul 08 2020 23:57:15 GMT+0200') // After nauticalDusk, return nauticalDusk ].forEach(d => console.log(getCurrentTimePhase(times, d)));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM