Найти ближайшее время к текущему времени

Я думаю, мой мозг просто выбросил исключение из памяти и потерпел крах,
Моя проблема в том, что у меня есть массив членов класса 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 );

Я должен рассчитать, какое из трех заданных пользователем времен ДО и ближе к текущему времени, а затем рассчитать оставшееся до него время,
(обратите внимание, что Sunday = 0, Saturday = 6, также обратите внимание, что только wDayOfWeek, wHour и wMinute должны сравниваться, чтобы добраться до ближайшего)

Изменить: теперь я награждаю 500bounty для решения, пожалуйста, обратите внимание на пример того, что я хочу,

Сегодня: день 4, час 3, минута 0,
Дата: День 5, Час 5, Минута 30
Оставшееся время до даты: 1 день, 2 часа и 30 минут
.

2

Решение

Учитывая проблемную область, кажется, что принудительное строгое упорядочение времени не является необходимым (или даже желательным), вы просто хотите выяснить, какое из набора раз ближе всего к заданному значению часового. Это потребует линейной сложности, но легко достижимо.

Я предлагаю рассчитать разницу во времени с известной эпохой, в данном случае, воскресенье 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";
}
5

Другие решения

Таким образом, проблема в том, что вы сидите на круге и хотите узнать, короче ли расстояние от 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 перегрузка, которая принимает пользовательский компаратор.

Вот как вы можете сделать это с помощью всего лишь нескольких строк кода (ссылка на быстрый тест на 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];
2

Я пришел с алгоритмом для решения, я знаю, что это далеко не самый профессиональный способ сделать это, но пока он безупречен.

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; //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>
0
По вопросам рекламы [email protected]