블로그는 나의 힘!

현재 시간에서 설정한 시간 만큼 원하는 갯수 까지 랜덤으로 출력하게 하는 코드.

 

예를 들어 2013-05-01 12:00:00 현재 시간이고 2013-06-30 12:30:00 까지 50개를 생성하게 설정한다면,

해당 기간까지 Tick 을 계산하여 랜덤으로 갯수 만큼 시간을 출력하게 하는 코드이다.

 

uniform_int_distribution을 사용하여 rand()의 문제점인 RAND_MAX(32767) 사이즈의 한계 문제점으로 몰리는 현상을 줄인 코드이다. 테스트도 하루, 1주, 1달, 반년, 1년, 2년 까지 테스트 해보고 그래프로 뽑아봐서 확인해 보니 고르게 분포 되는 것 확인하였다...

 

 

원하는 목적에 따라 나오는 날짜 랜덤이니 의사 랜덤이라고 봐야 겠지.

이거 어디 쓸려고 만든거냐고?! 생각해봐.. 원하는 기간을 잡고 해당 아이템을 갯수만큼 출력하게 한다....

 

이벤트로 사용할 수 있는 코드임.

'기간을 1달 잡고 그 기간에 10만원 상품권을 10개 드립니다.' 라고 해봐...

거기에 하루에 몰리게 안나오고 고르게 분포되어서 나오게 만들어야 한다면?! 생각 좀 많이 해야 할껄?!

 

이벤트에서 유용하게 사용할 수 있는 코드여. 그래서 만들었수...

 

- _-) 이거 만드는데 솔까 테스트 한다고 고생...

진짜 날짜 계산은 생각할 것이 많아서 무수한 테스트를 해야 한다는게 참으로 힘들다는거...

거기에 랜덤으로 날짜 출력하게 나와야 하고 고르게 분포 되어야 한다는 여러 필요 조건이 있어 참 까다로울 수밖에....

 

사용법 :

RandomTerm 함수에서 

설정한 종료 기한(SDate) 그리고 그 기간에 생성될 랜덤 갯수(int)를 넣어 날짜 리스트(vector<SDate>)를 구한다.

 

 

 

 

 

#include <time.h>
#include <winbase.h>
#include <random>

 

/*
typedef struct _SYSTEMTIME {
        WORD wYear;
        WORD wMonth;
        WORD wDayOfWeek;
        WORD wDay;
        WORD wHour;
        WORD wMinute;
        WORD wSecond;
        WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

 

struct tm {
        int tm_sec;     // seconds after the minute [0, 59]
        int tm_min;     // minutes after the hour [0, 59]
        int tm_hour;    // hour since midnight [0, 23]
        int tm_mday;    // day of thr month [1, 31]
        int tm_mon;     // months since January [0, 11]
        int tm_year;    // years since 1900
        int tm_wday;    // day since Sunday [0, 6]
        int tm_yday;    // days since January 1 [0, 365]
        int tm_isdst;   // daylight saving time flag
};

 

// 날짜 관련 구조체. operator 포함
struct SDate
{
        int iYear;
        int iMonth;
        int iDay;
        int iHour;
        int iMin;
        int iSec;

 

        SDate()
        {
                Initialize();
        }

 

        void Initialize()
        {
                memset( this, 0x00, sizeof(SDate) );
        }

 

        SDate& operator=( const SDate& rhsDate )
        {
                this->iYear = rhsDate.iYear;

                this->iMonth = rhsDate.iMonth;

                this->iDay = rhsDate.iDay;

                this->iHour = rhsDate.iHour;

                this->iMin = rhsDate.iMin;

                this->iSec = rhsDate.iSec;

 

                return (*this);
        }

 

        bool operator<( const SDate& rhsDate ) const
        {
                if( this->iYear > rhsDate.iYear ) return false;

                if( this->iYear < rhsDate.iYear ) return true;


                if( this->iMonth > rhsDate.iMonth ) return false;

                if( this->iMonth < rhsDate.iMonth ) return true;

                if( this->iDay > rhsDate.iDay ) return false;

                if( this->iDay < rhsDate.iDay ) return true;

                if( this->iHour > rhsDate.iHour ) return false;

                if( this->iHour < rhsDate.iHour ) return true;

                if( this->iMin > rhsDate.iMin ) return false;

                if( this->iMin < rhsDate.iMin ) return true;

                if( this->iSec >= rhsDate.iSec ) return false;

 

                return true;
        }

 

        bool operator>( const SDate& rhsDate ) const
        {
                if( this->iYear < rhsDate.iYear ) return false;

                if( this->iYear > rhsDate.iYear ) return true;

                if( this->iMonth < rhsDate.iMonth ) return false;

                if( this->iMonth > rhsDate.iMonth ) return true;

                if( this->iDay < rhsDate.iDay ) return false;

                if( this->iDay > rhsDate.iDay ) return true;


                if( this->iHour < rhsDate.iHour ) return false;

                if( this->iHour > rhsDate.iHour ) return true;

                if( this->iMin < rhsDate.iMin ) return false;

                if( this->iMin > rhsDate.iMin ) return true;

                if( this->iSec <= rhsDate.iSec ) return false;

 

                return true;
        }

 

        bool operator==( const SDate& rhsDate ) const
        {
                if( this->iYear != rhsDate.iYear ) return false;
                if( this->iMonth != rhsDate.iMonth ) return false;
                if( this->iDay != rhsDate.iDay ) return false;
                if( this->iHour != rhsDate.iHour ) return false;
                if( this->iMin != rhsDate.iMin ) return false;
                if( this->iSec != rhsDate.iSec ) return false;

 

                return true;
        }

 

        bool operator!=( const SDate& rhsDate ) const
        {
                if( this->iYear != rhsDate.iYear ) return true;
                if( this->iMonth != rhsDate.iMonth ) return true;
                if( this->iDay != rhsDate.iDay ) return true;
                if( this->iHour != rhsDate.iHour ) return true;
                if( this->iMin != rhsDate.iMin ) return true;
                if( this->iSec != rhsDate.iSec ) return true;

 

                return false;
        }

 

        bool operator<=( const SDate& rhsDate ) const
        {
                if( this->iYear > rhsDate.iYear ) return false;

                if( this->iYear < rhsDate.iYear ) return true;


                if( this->iMonth > rhsDate.iMonth ) return false;

                if( this->iMonth < rhsDate.iMonth ) return true;

                if( this->iDay > rhsDate.iDay ) return false;

                if( this->iDay < rhsDate.iDay ) return true;

                if( this->iHour > rhsDate.iHour ) return false;

                if( this->iHour < rhsDate.iHour ) return true;

                if( this->iMin > rhsDate.iMin ) return false;

                if( this->iMin < rhsDate.iMin ) return true;


                if( this->iSec > rhsDate.iSec ) return false;

 

                return true;
        }

 

        bool operator>=( const SDate& rhsDate ) const
        {
                if( this->iYear < rhsDate.iYear ) return false;

                if( this->iYear > rhsDate.iYear ) return true;

                if( this->iMonth < rhsDate.iMonth ) return false;

                if( this->iMonth > rhsDate.iMonth ) return true;

                if( this->iDay < rhsDate.iDay ) return false;

                if( this->iDay > rhsDate.iDay ) return true;


                if( this->iHour < rhsDate.iHour ) return false;

                if( this->iHour > rhsDate.iHour ) return true;

                if( this->iMin < rhsDate.iMin ) return false;

                if( this->iMin > rhsDate.iMin ) return true;


                if( this->iSec < rhsDate.iSec ) return false;

 

                return true;
        }
} // !SDate
*/

 

#define DATE_1DAYTOTIME (60 * 60 * 24)    // 86400 [Second * Minute * Hour]

 

// 저장된 SYSTEMTIME의 데이터를 Tick으로 변환해 반환해 준다.
int GetSystemTimeToTime_t( const SYSTEMTIME& systemTime )
{
        tm tmTime;
        time_t timeTime;


        tmTime.tm_sec = systemTime.wSecond;
        tmTime.tm_min = systemTime.wMinute;
        tmTime.tm_hour = systemTime.wHour;
        tmTime.tm_mday = systemTime.wDay;
        tmTime.tm_mon = systemTime.wMonth - 1;
        tmTime.tm_year = systemTime.wYear - 1900;
        tmTime.tm_isdst = 0;
       
        timeTime = ::mktime( &tmTime );

        return static_cast<int>( timeTime );
}

 

// 입력한 Tick 값을 Date 구조체에 담는다.
void GetTimeToDateInfo( SDate& sDateInfo, int iTime )
{

        //time_t atm = time( NULL );   // 현재 시간 초 단위로 담기
        time_t atm = static_cast<time_t>( iTime );
        tm tmTime;

 

        // 현재 초단위 시간을 분리하여 구조체 담기
        // 2번째 인자에 Tick을 넣으면 그 Tick 시간 설정된 시간으로 구조체 담기
        // localtime 함수로 현재 시간 구할 수 있으나 VS 2005 이후보안이 강화
        // localtime 사용시 waring c4996 경고 뜸
        localtime_s( &tmTime, &atm );

 

        sDateInfo.iSec = tmTime.tm_sec;
        sDateInfo.iMin = tmTime.tm_min;
        sDateInfo.iHour = tmTime.tm_hour;
        sDateInfo.iDay = tmTime.tm_mday;
        sDateInfo.iMonth = tmTime.tm_mon + 1;
        sDateInfo.iYear = tmTime.tm_year + 1900;
}

 

// 입력학 SYSTEMTIME 값을 Date 구조체에 담는다.
void GetSysTimeToDateInfo( SDate& sDateInfo, const SYSTEMTIME& sysTime )
{
        sDateInfo.iSec = sysTime.wSecond;
        sDateInfo.iMin = sysTime.wMinute;
        sDateInfo.iHour = sysTime.wHour;
        sDateInfo.iDay = sysTime.wDay;
        sDateInfo.iMonth = sysTime.wMonth;
        sDateInfo.iYear = sysTime.wYear;
}

 

// 입력학 Date 값을 SYSTEMTIME  구조체에 담는다.
void GetDateToSysTimeInfo( SYSTEMTIME& sysTime, const SDate& sDateInfo )
{
        sysTime.wYear = sDateInfo.iYear;
        sysTime.wMonth = sDateInfo.iMonth;
        sysTime.wDay = sDateInfo.iDay;
        sysTime.wHour = sDateInfo.iHour;
        sysTime.wMinute = sDateInfo.iMin;
        sysTime.wSecond = sDateInfo.iSec;
        sysTime.wMilliseconds = 0;
        sysTime.wDayOfWeek = 0;
}

 

// SYSTEMTIME 값을 비교하여 몇초 차이 나는지 계산하여 반환한다.
double CompareSystemTime( PSYSTEMTIME pTargetTime, PSYSTEMTIME pCompareTime )
{
        tm tmTime1, tmTime2;
        time_t timeTime1, timeTime2;

 

        tmTime1.tm_sec = pTargetTime->wSecond;
        tmTime1.tm_min = pTargetTime->wMinute;
        tmTime1.tm_hour = pTargetTime->wHour;
        tmTime1.tm_mday = pTargetTime->wDay;
        tmTime1.tm_mon = pTargetTime->wMonth - 1;
        tmTime1.tm_year = pTargetTime->wYear - 1900;
        tmTime1.tm_isdst = 0;
        timeTime1 = ::mktime( &tmTime1 );

 

        tmTime2.tm_sec = pCompareTime->wSecond;
        tmTime2.tm_min = pCompareTime->wMinute;
        tmTime2.tm_hour = pCompareTime->wHour;
        tmTime2.tm_mday = pCompareTime->wDay;
        tmTime2.tm_mon = pCompareTime->wMonth - 1;
        tmTime2.tm_year = pCompareTime->wYear - 1900;
        tmTime2.tm_isdst = 0;
        timeTime2 = ::mktime( &tmTime2 );

 

        // time2와 time1의 second 차이를 double 형으로 리턴
        return ::difftime( timeTime1, timeTime2 );

}

 

// 날짜 기간 계산 의사 랜덤 코드

// 설정한 기간까지 count 갯수 만큼 랜덤으로 날짜 설정하기
BOOL RandomTerm( std::vector<SDate>& vecTermDate, const SDate& sTermDate, int iTermCount )
{
        if( 0 >= iTermCount )   return FALSE;

 

        SYSTEMTIME CurrentSysTime;
        // 현재 시간 SYSTEMTIME 구조체 담기
        ::GetLocalTime( &CurrentSysTime );

 

        SYSTEMTIME TermSysTime;
        GetDateToSysTimeInfo( TermSysTime, sTermDate );
        TermSysTime.wSecond = 0; // 초는 필요 없을꺼 같아 초기화.

 

        // Check Term
        int iTerm = (int)( CompareSystemTime(&TermSysTime, &CurrentSysTime) );
        if( 0 >= iTerm )   return FALSE;

 

        int iTermDay = iTerm / DATE_1DAYTOTIME;
        int iCurrentTime = GetSystemTimeToTime_t( CurrentSysTime );

 

        // set random
        // 기본으로 제공하는 rand()는 RAND_MAX 0x7fff 로 10진수로 32767 사이즈
        // 관련하여 그 이상으로 랜덤을 원할 경우 한계점 문제 생김
        // stl이 제공하는 uniform_intdistribution 랜덤 경우 설정한 값까지 랜덤 가능
        // rand()에 비해 랜덤이 한곳으로 몰리지 않고 고르게 분포
        // 시간, 일, 주, 달, 년 테스트 확인 하였음
        std::default_random_engine generator;

        //std::default_random_engine generator( (unsigned)time(NULL) );
        std::uniform_int_distribution<int> distributionDay( 0, iTerm );  // 설정된 기간(Tick) 만큼 랜덤으로 생성

 

        // C11 이전 버전 경우

        // 1.

        //std::tr1::mt19937 engine( (unsigned int)time(NULL) );

        //std::tr1::uniform_int<> distribution( 0, iTerm );

        //std::tr1::variate_generator<std::tr1::mt19937, std::tr1::uniform_int<> > generator( engine, distribution );

 

        // 2.

        //std::tr1::mt19937 engine( (unsigned int)time(NULL) );

        //int iRandomProb = (int)( engine() % iTerm );

 

 

        printf( "[RandomTerm] TermCount(%d) \n", iTermCount );
        printf( "[RandomTerm] CurrentDate(%d-%d-%d %d:%d:%d) TermDate(%d-%d-%d %d:%d:00) \n",
                 CurrentSysTime.wYear, CurrentSysTime.wMonth, CurrentSysTime.wDay,

                 CurrentSysTime.wHour, CurrentSysTime.wMinute, CurrentSysTime.wSecond,

                 sTermDate.iYear, sTermDate.iMonth, sTermDate.iDay, sTermDate.iHour, sTermDate.iMin );
        
        // 기간 랜덤 출력 나온것 담기
        vecTermDate.clear();
        for( int i = 0; i < iTermCount; ++i )
        {
                int iRandomTime = 0;
                //if( 0 < iTermDay )
                        iRandomTime = distributionDay( generator );

 

                SDate sDateInfo;
                GetTimeToDateInfo( sDateInfo, iCurrentTime + iRandomTime );

 

                if( sTermDate > sDateInfo )
                {
                        vecTermDate.push_back( sDateInfo );

 

                        printf( "[RandomTerm] Set TermDate Count(%d) Date(%d-%d-%d %d:%d:%d) \n",
                                 i, sDateInfo.iYear, sDateInfo.iMonth, sDateInfo.iDay,
                                 sDateInfo.iHour, sDateInfo.iMin, sDateInfo.iSec );
                }
        } // !for

 

        if( 0 >= vecTermDate.size() )   return FALSE;

 

        return TRUE;
}

 

추가로 참조할 만한 블로그
localtime_s 관련 :
http://bbk1999.blog.me/90030287559
difftime 관련 : http://itguru.tistory.com/111
uniform_int_distribution 관련

: http://devmachine.blog.me/177685246 , https://devmachine.blog.me/221240867011

 

그외 : https://blog.naver.com/jamiet1/221373609163

 

Posted by Mister_Q