Question

I guess my brain just threw an out of memory exception and crashed, My problem is I have a class member array of SYSTEMTIME size 3 which is user defined (read from a .lua)

SYSTEMTIME m_MatchTime[3];

Then it's read this way from the file:

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" ) );

now I have a method:

SYSTEMTIME cTime;
GetLocalTime( &cTime );

I must calculate which from the three user defined times is BEFORE and closer to the current time, then calculate the remaining time to it, (please notice that Sunday = 0, Saturday = 6, also note that only wDayOfWeek, wHour and wMinute must be compared to get to the closest )

Edit: Now I'm awarding 500bounty for a solution, please note the example of what I want,

Today: Day 4, Hour 3, Minute 0,
Date: Day 5, Hour 5, Minute 30
The remaining time until date is: 1 days, 2 hour and 30 minutes
.

Was it helpful?

Solution 4

I have came with an algorithm for the solution, I know its far from the most professional way to do it, but its flawless so far.

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

OTHER TIPS

Given the problem domain, it appears that enforcing a strict ordering of times is not necessary (or even desirable), you just want to find which of a set of times is closest to a given sentinel value. This will require linear complexity, but is easy achievable.

I suggest calculating the time difference from a known epoch, in this case, Sunday 00:00:00 in seconds, then comparing the differences of each time from that point to see which are closest.

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

So the problem is that you are sitting on a circle and want to know wether the distance going from d1 to d2 right (remaining in the same week) or left (one value to the next thru sunday) is shorter.

First you should transform the date into a value with the formula minute+hour*60+weekday*60*24. This will give you the minute in the week.

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

next find the min distance:

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

So calculate from your actual time the minOfWeek, feed it with all of your 3 times in week to the bestDistance and take the smallest number...

The standard C++ library lets you solve this rather elegantly by moving the "magic" of comparing dates to a functor, and using the std::sort overload that takes a custom comparator.

Here is how you can do it with very few lines of code (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);
    }
};

That's it, really! With this comparator in hand, you can sort your three dates like this:

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

Now the nearest date is at the index zero:

SYSTEMTIME &nearest = m_MatchTime[0];

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

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<n; ++i)
{
    timedif = packtime(m_MatchTime[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<<"Today: Day "<<cTime.wDayOfWeek<<" Hour "<<cTime.wHour<<" Minute "<<cTime.wMinute<<std::endl;
std::cout<<"Nearest day: Day "<<m_MatchTime[mindifidx].wDayOfWeek<<" Hour "<<m_MatchTime[mindifidx].wHour<<" Minute "<<m_MatchTime[mindifidx].wMinute<<std::endl;
std::cout<<"Difference: "<<dif.wDayOfWeek<<" days "<<dif.wHour<<" hours "<<dif.wMinute<<" minutes"<<std::endl;</code>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top