首页 > 解决方案 > Nodejs - Express - 如何计算下一个更接近今天的时间()?

问题描述

考虑到以下数组数据,我需要计算下一个更接近“时间”的小时:

var date = new Date();
var time = date.getHours(); // 17 -> it means 5:00 PM
var minute = date.getMinutes(); // 12

// This is how the data has been saved in the database.
{ id: ‘1’, time: '1:00 AM' }
{ id: ‘1’, time: '2:00 PM' }
{ id: ‘1’, time: '7:00 PM' }
{ id: ‘1’, time: '10:00 PM' }
{ id: ‘1’, time: '8:00 PM' }
{ id: ‘1’, time: '11:00 AM' }
{ id: ‘2’, time: '9:00 AM' }
{ id: ‘2’, time: '6:30 PM' }
{ id: ‘2’, time: '5:00 PM' }
{ id: ‘2’, time: '1:00 PM' }

结果需要是这样的数组:

{id: ‘1’, time: '7:00 PM'}
{id: ‘2’, time: '6:30 PM'}

基本上我需要知道每个 ID 下一个更接近下午 5:12 的时间。

到目前为止,这是我的代码:

function calculateNextPill(items) {
let nextPillArr = [];
let itemData = null;
let item_id = null;
var currentTime = new Date();
var closerTime = new Date();    
var newTimes = [];
for(i=0; i<items.length; i++) {
    itemData = items[i].itemdata[0];
    item_id = items[i]._id;

    for (const prop in itemData.pills) {
        const pill = itemData.pills[prop];
        if (pill != undefined && pill.time != undefined) {
            nextPillArr.push({id: item_id, time: pill.time});
        }
    }
}
nextPillArr.forEach(element => {
    var time =  element.time;
    var scheduleTime = new Date();
    var parts = time.match(/(\d+):(\d+) (AM|PM)/);
    if (parts) {
        var hours = parseInt(parts[1]),
            minutes = parseInt(parts[2]),
            tt = parts[3];
        if (tt === 'PM' && hours < 12) hours += 12;
        scheduleTime.setHours(hours, minutes, 0, 0);
        var a = moment(currentTime);
        var b = moment(scheduleTime);
        b.diff(a);
        newTimes.push({id: element._id, diff: b.diff(a)});
        // here I need to calculate which time is closer for which pill. Not done yet. Need more coffe...
    }
});

}

标签: javascriptnode.jsarrays

解决方案


首先,您需要一个函数,该函数可以让您每次都获得某种数值,然后您可以使用它来比较这些值。以下函数将为我们提供 24 小时格式的分钟数:

function time_to_numeric(time) {
    const [_, h, m, meridian] = time.match(/(\d+):(\d+) (AM|PM)/);
    let [hours, min] = [parseInt(h), parseInt(m)];
    if (meridian === "PM" && hours !== 12) hours += 12;
    if (meridian === "AM" && hours === 12) hours -= 12;
    return hours * 60 + min;
}

接下来,我们还需要相同格式的时间now

const now = new Date();
const now_numeric = now.getHours() * 60 + now.getMinutes();

使用它,我们现在可以开始查找每个唯一 id 的最接近时间,假设items是您示例中所有对象的数组。这通过计算以分钟为单位的差异now并在它较低时交换值来工作。如果某个时间比现在更早发生,我们改为计算第二天与该时间的差。我们为每个 id 保存当前最小值的差值和实际时间:

const closer_times_by_id = items.reduce((acc, {id, time}) => {
    const time_numeric = time_to_numeric(time);
    let diff = time_numeric - now_numeric;
    if (diff < 0) diff = time_numeric + MINUTES_PER_DAY - now_numeric;
    const prev_diff = acc[id] && acc[id].diff;
    if (prev_diff === undefined || diff < prev_diff) {
        acc[id] = { diff, time };
    }
    return acc;
}, {});

现在我们的closer_times_by_id 会看起来像{'1': {diff: 158, time: '7:00 PM'}, '2': {diff: 38, time: '5:00 PM'}}. 我们通过以下方式将其映射到数组:

times_arr = Object.entries(closer_times_by_id).map(item => {
    const [id, { time }] = item;
    return { id, time };
});

在此之后,我们完成并times_arr包含您的结果。


完整代码:

const MINUTES_PER_DAY = 24 * 60;

// Takes a string like '1:10 PM' and returns the amount of minutes in 24h format
function time_to_numeric(time) {
    const [_, h, m, meridian] = time.match(/(\d+):(\d+) (AM|PM)/);
    let [hours, min] = [parseInt(h), parseInt(m)];
    if (meridian === "PM" && hours !== 12) hours += 12;
    if (meridian === "AM" && hours === 12) hours -= 12;
    return hours * 60 + min;
}

function closest_items_by_id(items) {
    const now = new Date();
    const now_numeric = now.getHours() * 60 + now.getMinutes();

    // Find closest times for each id, giving preference to times in the
    // future in case of ties
    // After reducing has finished, closer_times_by_id will be an object like
    // {'1': {diff: 158, time: '7:00 PM'}, '2': {diff: 38, time: '5:00 PM'}}
    const closer_times_by_id = items.reduce((acc, {id, time}) => {
        const time_numeric = time_to_numeric(time);
        let diff = time_numeric - now_numeric;
        // If time occured earlier than now, calculate diff to time next day
        if (diff < 0) diff = time_numeric + MINUTES_PER_DAY - now_numeric;
        const prev_diff = acc[id] && acc[id].diff;
        if (prev_diff === undefined || diff < prev_diff) {
            acc[id] = { diff, time };
        }
        return acc;
    }, {});

    // Map closer_times_by_id to desired format
    return Object.entries(closer_times_by_id).map(item => {
        const [id, { time }] = item;
        return { id, time };
    });
}


const raw_data = [
    { id: '1', time: '1:00 AM' },
    { id: '1', time: '11:00 AM' },
    { id: '1', time: '2:00 PM' },
    { id: '1', time: '7:00 PM' },
    { id: '1', time: '8:00 PM' },
    { id: '1', time: '10:00 PM' },
    { id: '2', time: '9:00 AM' },
    { id: '2', time: '1:00 PM' },
    { id: '2', time: '1:10 PM' },
    { id: '2', time: '5:00 PM' },
    { id: '2', time: '6:30 PM' },
]

const now = new Date();
console.log(`Time at SO-server: ${now.getHours()}:${now.getMinutes()}`);
console.log(closest_items_by_id(raw_data));


推荐阅读