【问题标题】:Find the closest time to the current time查找最接近当前时间的时间
【发布时间】:2012-11-05 21:17:43
【问题描述】:

我猜我的大脑刚刚抛出了一个内存不足异常并崩溃了, 我的问题是我有一个 SYSTEMTIME 大小为 3 的类成员数组,它是用户定义的(从 .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 );

我必须从三个用户定义的时间中计算出哪个是 BEFORE 和更接近当前时间,然后计算它的剩余时间, (请注意,Sunday = 0,Saturday = 6,还要注意只有 wDayOfWeek、wHour 和 wMinute 必须进行比较才能最接近)

编辑:现在我奖励 500bounty 以获得解决方案,请注意我想要的示例,

今天:第 4 天,第 3 小时,第 0 分钟,
日期:第 5 天,第 5 小时,第 30 分钟
距离日期的剩余时间为:1 天 2 小时 30 分钟

【问题讨论】:

  • 使用 SystemTimeToFileTime() 这样您就可以简单地比较数字。
  • SystemTimeToFileTime() 会忽略wDayOfWeek 成员,并需要根据示例代码未给出的有效附加成员(如年、月、日)。
  • 从您的编辑中:“今天:第 4 天...,日期:第 5 天...”这不意味着日期比今天 1 天2小时30分钟?
  • 您能否解释一下“BEFORE and close”的含义?首先,从接受的答案看来,您正在寻找当天是“之前”三天中的一天,而不是相反。由于您只给出一周中的某一天而没有给出一年中的某一天,因此任何事情都可以被解释为两天——一个在当前日期之前,一个在它之后。例如,如果今天是星期五,日期是星期四,我可以说这一天表示下一周的星期四。这种解释正确吗?

标签: c++ time systemtime


【解决方案1】:

鉴于问题域,似乎没有必要(甚至不希望)强制执行严格的时间顺序,您只想找出一组时间中的哪一个最接近给定的标记值。这需要线性复杂度,但很容易实现。

我建议计算与已知纪元的时间差,在本例中为星期日 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";
}

【讨论】:

  • 好点,修复(现在)是读者的练习:)。问题不仅仅是周六/周日,而是最大的不同变化。周五/周一、周四/周日等也存在问题。
  • 这个“错误”太明显了,无法修复。我已经放入了计算工作日差异的必要逻辑表。我还没有完全审查它,但我认为它是正确的。
  • 我相信整个想法都被打破了。如果您有一些未来的日期和过去的其他日期,您将得到不正确的结果:ideone.com/9YTKNA
【解决方案2】:

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

首先,您应该使用公式分钟+小时*60+工作日*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,将您在一周内的所有 3 次喂给 bestDistance 并取最小的数字...

【讨论】:

    【解决方案3】:

    标准 C++ 库通过将比较日期的“魔法”转移到仿函数并使用采用自定义比较器的 std::sort 重载,让您可以相当优雅地解决这个问题。

    您可以通过以下方式使用很少的代码行 (link to a quick test on 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];
    

    【讨论】:

      【解决方案4】:

      我已经为解决方案提供了一个算法,我知道它远非最专业的方法,但到目前为止它完美无缺。

      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;
      }
      

      【讨论】:

        【解决方案5】:

        const unsigned n=3; //replace with actual array size

        自动打包时间 = [](const SYSTEMTIME& t)->无符号
        {
            返回 t.wDayOfWeek*24*60 + t.wHour*60 + t.wMinute;
        };
        自动解包时间 = [](无符号总数)->SYSTEMTIME
        {
            系统时间 ret;
        
            ret.wDayOfWeek = 总计/(60*24);
            总计 %= (60*24);
            ret.wHour = 总计/60;
            ret.wMinute = 总计%60;
        
            返回 ret;
        };
        
        无符号常量包裹时间 = 7*24*60;
        无符号目标时间 = 打包时间(cTime);
        
        无符号 mintimedif = wraptime + 1;
        未签名的minifidx;
        无符号时间;
        
        for(无符号 i=0; i

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-31
          相关资源
          最近更新 更多