找到距离当前时间最近的时间。

3
我猜我的大脑刚刚抛出了一个内存溢出异常并崩溃了。 我的问题是,我有一个大小为3的SYSTEMTIME类成员数组,它是用户定义的(从.lua文件中读取)。
SYSTEMTIME m_MatchTime[3];

然后从文件中以以下方式读取它:
m_MatchTime[0].wDayOfWeek = static_cast<WORD>( m_Lua.GetGlobalNumber( "FirstDay" ) );
m_MatchTime[0].wHour = static_cast<WORD>( m_Lua.GetGlobalNumber( "FirstHour" ) );
m_MatchTime[0].wMinute  = static_cast<WORD>( m_Lua.GetGlobalNumber( "FirstMinute" ) );

m_MatchTime[1].wDayOfWeek = static_cast<WORD>( m_Lua.GetGlobalNumber( "SecondDay" ) );
m_MatchTime[1].wHour = static_cast<WORD>( m_Lua.GetGlobalNumber( "SecondHour" ) );
m_MatchTime[1].wMinute  = static_cast<WORD>( m_Lua.GetGlobalNumber( "SecondMinute" ) );

m_MatchTime[2].wDayOfWeek = static_cast<WORD>( m_Lua.GetGlobalNumber( "ThirdDay" ) );
m_MatchTime[2].wHour = static_cast<WORD>( m_Lua.GetGlobalNumber( "ThirdHour" ) );
m_MatchTime[2].wMinute  = static_cast<WORD>( m_Lua.GetGlobalNumber( "ThirdMinute" ) );

现在我有一个方法:

SYSTEMTIME cTime;
GetLocalTime( &cTime );

我必须计算出三个用户定义时间中哪一个比当前时间更早且更接近,然后计算到该时间的剩余时间, (请注意,星期天=0,星期六=6,还要注意只有wDayOfWeek、wHour和wMinute需要进行比较以找到最接近的时间)。
编辑:现在我将为解决方案提供500美元的奖励,请注意我想要的示例,
今天:第4天,第3小时,第0分钟, 日期:第5天,第5小时,第30分钟, 距离日期剩余时间为:1天,2小时和30分钟。

2
使用SystemTimeToFileTime()函数,这样你就可以简单地比较数字。 - Hans Passant
SystemTimeToFileTime()忽略“wDayOfWeek”成员,并且需要有效的其他成员(如年份、月份、日期),这些成员根据示例代码中的给定内容不足。 - Chad
从您的编辑中可以看到:“今天:第4天...,日期:第5天...”,这难道不意味着日期比今天晚1天2小时30分钟吗? - Sergey Kalinichenko
请问"BEFORE and closer"的意思是什么?首先,从接受的答案来看,似乎您是要把当前日期放在三天之前,而不是相反。由于您只给出了星期几,没有年份中的具体日期,因此任何日期都可以被解释为比当前日期早两天——一天在它之前,另一天在它之后。例如,如果今天是星期五,日期是星期四,我可以说这个日子代表下周的星期四。这种解释正确吗? - Sergey Kalinichenko
5个回答

5

考虑到问题领域,强制时间顺序的严格排序似乎不是必要的(甚至不可取),你只需要找到一组时间中最接近给定标志值的时间。这将需要线性复杂度,但很容易实现。

我建议从已知的纪元开始计算时间差,例如每周日 00:00:00 的秒数,然后比较每个时间与该点之间的差异,以确定哪些时间最接近。

#include <Windows.h>
#include <algorithm>
#include <iostream>

long seconds_from_sunday_epoch(const SYSTEMTIME& t)
{
   size_t seconds = t.wDayOfWeek * 86400;
   seconds += t.wHour * 3600;
   seconds += t.wMinute * 60;
   return seconds;
}

size_t timediff_2(const SYSTEMTIME& t0, const SYSTEMTIME& t1)
{
   size_t seconds_diff = std::abs(
      seconds_from_sunday_epoch(t0) -
      seconds_from_sunday_epoch(t1));

   return seconds_diff;
}

int main()
{
   SYSTEMTIME m_MatchTime[3];


   // Monday: 00:00
   m_MatchTime[0].wDayOfWeek = 1;
   m_MatchTime[0].wHour = 0;
   m_MatchTime[0].wMinute = 0;

   // Sunday: 01:00
   m_MatchTime[1].wDayOfWeek = 0;
   m_MatchTime[1].wHour = 1;
   m_MatchTime[1].wMinute = 0;

   // Wednesday: 15:30
   m_MatchTime[2].wDayOfWeek = 3;
   m_MatchTime[2].wHour = 15;
   m_MatchTime[2].wMinute = 30;

   // Sunday 23:00
   SYSTEMTIME cTime;
   cTime.wDayOfWeek = 0;
   cTime.wHour = 23;
   cTime.wMinute = 0;

   std::cout << timediff_2(cTime, m_MatchTime[0]) << "\n";
   std::cout << timediff_2(cTime, m_MatchTime[1]) << "\n";
   std::cout << timediff_2(cTime, m_MatchTime[2]) << "\n";
}

优秀的观点,暂时修复这个问题留给读者自己练习 :)。这个问题不仅仅是周六/周日的问题,但这是最大的变化之一。对于像星期五/星期一、星期四/星期日等事情也存在问题。 - Chad
这个“漏洞”太明显了,不修复不行。我已经加入了必要的逻辑表来计算星期几的差异。虽然我还没有完全审查它,但我认为它是正确的。 - Chad
2
我认为整个想法都是错误的。如果你有一些未来的日期和一些过去的日期,你将得到不正确的结果:http://ideone.com/9YTKNA - Lol4t0

3

问题是你坐在一个圆圈上,想知道从d1到d2的距离是向右(保持在同一周)还是向左(通过星期日到达下一个值)更短。

首先,你应该使用公式minute+hour*60+weekday*60*24将日期转换为值。这将给出一周中的分钟数。

#include <stdlib.h>
int minOfWeek (int d, int h, int m) {
  return d*60*24+h*60+m;
}

接下来找到最小距离:

const int minutesInWeek=60*24*7;
int bestDistance (int minutes1, int minutes2) {
  int d=abs (minutes1-minutes2);
  int dNext=minutesInWeek-d;
  return d<dNext?d:dNext;
}

所以,从你实际的时间计算出一周中的最小分钟数(minOfWeek),将所有三次时间输入到bestDistance中,并取最小值...


2
标准的C++库可以通过将比较日期的“魔法”移动到函数对象中,并使用采用自定义比较器的 std::sort 重载来优雅地解决这个问题。
以下是您可以使用非常少的代码实现此操作的方法(在ideone上进行快速测试的链接):
class ClosestTo {
    int minute_now;
    int abs_minute(const SYSTEMTIME& t) const {
        return 60 * (24 * t.wDayOfWeek + t.wHour) + t.wMinute;
    }
    int diff_to_now(const SYSTEMTIME& t) const {
        int res = abs_minute(t) - minute_now;
        // Has the date passed this week?
       if (res < 0) {
            // Yes, the date has passed - move to next week:
            res += 7*24*60;
       }
        return res;
    }
public:
    ClosestTo(const SYSTEMTIME& now)
    :   minute_now(abs_minute(now)) {
    }
    // This is the operator the std::sort is going to call to determine ordering
    bool operator() (const SYSTEMTIME& lhs, const SYSTEMTIME& rhs) const {
        // Pick the date implying the shortest difference to minute_now
        return diff_to_now(lhs) < diff_to_now(rhs);
    }
};

就是这样!有了这个比较器,你可以像这样对三个日期进行排序:

ClosestTo cmp(cTime);
sort(m_MatchTime, m_MatchTime+3, cmp);

现在最近的日期位于索引零:
SYSTEMTIME &nearest = m_MatchTime[0];

0

我已经想出了一个解决方案的算法,我知道这不是最专业的方法,但目前为止它是完美无缺的。

int main()
{
SYSTEMTIME m_MatchTime[3];


// Monday: 00:00
m_MatchTime[0].wDayOfWeek = 1;
m_MatchTime[0].wHour = 22;
m_MatchTime[0].wMinute = 4;

// Sunday: 01:00
m_MatchTime[1].wDayOfWeek = 4;
m_MatchTime[1].wHour = 1;
m_MatchTime[1].wMinute = 0;

// Wednesday: 15:30
m_MatchTime[2].wDayOfWeek = 6;
m_MatchTime[2].wHour = 15;
m_MatchTime[2].wMinute = 30;

// Sunday 23:00
SYSTEMTIME cTime;
cTime.wDayOfWeek = 3;
cTime.wHour = 14;
cTime.wMinute = 5;

/*  std::cout << timediff_2(cTime, m_MatchTime[0]) << "\n";
std::cout << timediff_2(cTime, m_MatchTime[1]) << "\n";
std::cout << timediff_2(cTime, m_MatchTime[2]) << "\n";*/

vector<size_t>m_Time;
if( cTime.wDayOfWeek == 0 )
{
    for( int i =0; i<3; i++ )
    {
        if( cTime.wDayOfWeek >= m_MatchTime[i].wDayOfWeek )
            m_Time.push_back( timediff_2(cTime, m_MatchTime[i]) );
    }

    if( m_Time.size() == 0 ) //trim right
    {
        for( int i =0; i<3; i++ )
        {
            if( cTime.wDayOfWeek <= m_MatchTime[i].wDayOfWeek )
                m_Time.push_back( timediff_2(cTime, m_MatchTime[i]) );
        }
    }
}
else
{
    for( int i =0; i<3; i++ )
    {
        if( cTime.wDayOfWeek <= m_MatchTime[i].wDayOfWeek )
            m_Time.push_back( timediff_2(cTime, m_MatchTime[i]) );
    }

    if( m_Time.size() == 0 ) //trim right
    {
        for( int i =0; i<3; i++ )
        {
            if( cTime.wDayOfWeek >= m_MatchTime[i].wDayOfWeek )
                m_Time.push_back( timediff_2(cTime, m_MatchTime[i]) );
        }
    }
}


std::sort( m_Time.begin(), m_Time.end() );

SYSTEMTIME nearest;
if( m_Time.size() > 0 )
{
    for( int l=0; l<3; l++ )
    {
        if( timediff_2( cTime, m_MatchTime[l] ) == m_Time.at(0) )
        {
            nearest = m_MatchTime[l];
            break;
        }
    }
}

unsigned int manydaysleft = howmanydaysuntil(  nearest.wDayOfWeek , cTime.wDayOfWeek );
unsigned int manyhoursleft = howmanyhoursuntil(  nearest.wHour, cTime.wHour );
if( nearest.wHour < cTime.wHour ) //manydaysleft will always be > 0
    manydaysleft--;
unsigned int manyminutesleft = howmanyminutesuntil( nearest.wMinute, cTime.wMinute );
if( nearest.wMinute < cTime.wMinute )
    manyhoursleft--;



/*cout 
    << manydaysleft << endl
    << manyhoursleft << endl
    << manyminutesleft << endl;*/

cout << "CurrentTime\n"  
    << "Day:" << cTime.wDayOfWeek
    << "Hour:" << cTime.wHour
    << "Min:" << cTime.wMinute 

    << "\nDay:" << nearest.wDayOfWeek
    << "Hour:" << nearest.wHour
    << "Min:" << nearest.wMinute

    << "\nDay:" << manydaysleft
    << "Hour:" << manyhoursleft
    << "Min:" << manyminutesleft;

    return 0;
}

0

const unsigned n=3; //用实际的数组大小替换

auto packtime = [](const SYSTEMTIME& t)->unsigned { return t.wDayOfWeek*24*60 + t.wHour*60 + t.wMinute; }; auto unpacktime = [](unsigned total)->SYSTEMTIME { SYSTEMTIME ret;
ret.wDayOfWeek = total/(60*24); total %= (60*24); ret.wHour = total/60; ret.wMinute = total%60;
return ret; }; unsigned const wraptime = 7*24*60; unsigned targettime = packtime(cTime); unsigned mintimedif = wraptime + 1; unsigned mindifidx; unsigned timedif;
for(unsigned i=0; i
if(timedif < targettime) timedif = targettime - timedif; else timedif = wraptime - timedif + targettime;
if(timedif < mintimedif) { mintimedif = timedif; mindifidx = i; } }
SYSTEMTIME dif = unpacktime(mintimedif);
std::cout<<"今天:星期"<

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接