#ifndef INCLUDED_L3_DATE_H #define INCLUDED_L3_DATE_H // *Universal, Real Date* Copyright (C) Krzysztof Bosak 2000-11-16...2000-12-07. // All rights reserved. // kbosak@box43.pl // http://www.kbosak.prv.pl #include #include #include #include "l3_array.h" #include "l3_crc.h" #include "l3_ran2.h" ///////////////////////////////////////////////////////////////////////////// class RealDate { // sizeof(RealDate) is 4! private: unsigned _day:5; // 1...31 (max 0...31) unsigned _month:4; // 1...12 (max 0...15) signed _year:23; // -4'000'000...4'000'000 (max -2^22...2^22-1 == -4'194'304...4'194'303) static int _encrypt_date_idum; static const int month_length[2][13]; public: enum _initialization_mode {COMPILATION_DATE, CURRENT_GMT_DATE, CURRENT_LOCAL_DATE}; inline RealDate(); inline explicit RealDate(_initialization_mode mode); inline RealDate(int year, int day_of_year); inline RealDate(int year, int month, int day); bool LoadCompilationDate(); bool LoadCurrentGmtDate(); bool LoadCurrentLocalDate(); friend ostream& operator<<(ostream& str, const RealDate& date); friend bool operator==(const RealDate& date_a, const RealDate& date_b); friend bool operator<(const RealDate& date_a, const RealDate& date_b); inline int DayOfYear() const; inline void GetMonthDay(int year, int yearday, int& get_month, int& get_day) const; inline bool IsLeapYear() const; inline int LengthOfNormalYear() const; inline int LengthOfLeapYear() const; inline int LengthOfYear() const; inline int Year() const; inline int Month() const; inline int Day() const; const basearray EncryptDate() const; bool LoadEncryptedDate(basearray buffer); inline void operator+=(int days); inline void operator-=(int days); private: inline bool _valid_date() const; inline void _assert_date() const; }; int RealDate::_encrypt_date_idum=static_cast(time(NULL)+clock()); const int RealDate::month_length[2][13]= { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; inline RealDate::RealDate() : _day(1), _month(1), _year(2000) { _assert_date(); } inline RealDate::RealDate(_initialization_mode mode) { switch(mode) { case COMPILATION_DATE: LoadCompilationDate(); break; case CURRENT_GMT_DATE: LoadCurrentGmtDate(); break; case CURRENT_LOCAL_DATE: LoadCurrentLocalDate(); break; default: assert(0); } _assert_date(); } inline RealDate::RealDate(int year, int day_of_year) { assert(_year!=0); assert(day_of_year>=1); _year=year; assert(day_of_year<=LengthOfYear()); const int old_month=_month; const int old_day=_day; int get_month; int get_day; GetMonthDay(_year, day_of_year, get_month, get_day); _month=get_month; _day=get_day; if(_valid_date()==false) { _month=old_month; _day=old_day; #ifdef USE_EXCEPTIONS throw "RealDate::RealDate(int year, int day_of_year): Invalid date.\n"; #endif return; } _assert_date(); } inline RealDate::RealDate(int year, int month, int day) { assert(_year!=0); assert(month>=1); assert(month<=12); assert(day>=1); assert(day<=31); _year=year; _month=month; _day=day; if(_valid_date()==false) { _year=0; _month=0; _day=0; #ifdef USE_EXCEPTIONS throw "RealDate::RealDate(int year, int month, int day): Invalid date.\n"; #endif return; } _assert_date(); } bool RealDate::LoadCompilationDate() { const RealDate backup=*this; assert(strlen(__DATE__)==11); // DAY char day_string[3]="99"; day_string[0]=__DATE__[4]; day_string[1]=__DATE__[5]; const int day=atoi(day_string);// __DATE__ is not always terminated with 0 with Intel icl compiler. assert(day>=1); assert(day<=31); // MONTH const char * const month_array[]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char month_name[]="abc"; month_name[0]=__DATE__[0]; month_name[1]=__DATE__[1]; month_name[2]=__DATE__[2]; int month; for(month=0; month<12; month++) { if(strcmp(month_name, month_array[month])==0) { break; } } assert(month<12); month++; assert(month>=1); assert(month<=12); // YEAR char date_string[5]="1234"; date_string[0]=__DATE__[7]; date_string[1]=__DATE__[8]; date_string[2]=__DATE__[9]; date_string[3]=__DATE__[10];// __DATE__ is not always terminated with 0 with Intel icl compiler. const int year=atoi(date_string); assert(year>=1970); assert(year<=2038); // UPDATING DATE _day=day; _month=month; _year=year; if(_valid_date()==false) { *this=backup; #ifdef USE_EXCEPTIONS throw "RealDate::LoadCompilationDate(): Invalid date.\n"; #endif return false; } _assert_date(); return true; } bool RealDate::LoadCurrentGmtDate() { // Coordinated universal time based date const time_t ltime=time(NULL); tm* gmt; gmt=gmtime(<ime); if(gmt==NULL) { #ifdef USE_EXCEPTIONS throw "RealDate::LoadCurrentGmtDate(): gmtime(<ime) returned NULL.\n"; #endif return false; } assert(gmt!=NULL); const RealDate backup=*this; _year=gmt->tm_year+1900; _month=gmt->tm_mon+1; _day=gmt->tm_mday; if(_valid_date()==false) { *this=backup; #ifdef USE_EXCEPTIONS throw "RealDate::LoadCurrentGmtDate(): Invalid date.\n"; #endif return false; } _assert_date(); return true; } bool RealDate::LoadCurrentLocalDate() { // Coordinated local time based date const time_t ltime=time(NULL); tm* local; local=localtime(<ime); if(local==NULL) { #ifdef USE_EXCEPTIONS throw "RealDate::LoadCurrentLocalDate(): localtime(<ime) returned NULL.\n"; #endif return false; } assert(local!=NULL); const RealDate backup=*this; _year=local->tm_year+1900; _month=local->tm_mon+1; _day=local->tm_mday; if(_valid_date()==false) { *this=backup; #ifdef USE_EXCEPTIONS throw "RealDate::LoadCurrentLocalDate(): Invalid date.\n"; #endif return false; } _assert_date(); return true; } ostream& operator<<(ostream& str, const RealDate& date) { return str< date_b._year) return false; if(date_a._month < date_b._month) return true; else if(date_a._month > date_b._month) return false; if(date_a._day < date_b._day) return true; else // date_a._day > date_b._day or equal return false; } inline bool operator<=(const RealDate& date_a, const RealDate& date_b) { return operator<(date_a, date_b) || operator==(date_a, date_b); } inline int RealDate::DayOfYear() const { // Based on K&R 'The C programming language' int day=_day; const int leap=_year%4==0 && _year%100!=0 || _year%400==0; for(unsigned i=1; i<_month; i++) { day+=month_length[leap][i]; } return day; } inline void RealDate::GetMonthDay(int year, int yearday, int& get_month, int& get_day) const { // Based on K&R 'The C programming language' const int leap=year%4==0 && year%100!=0 || year%400==0; int i; for(i=1; yearday>month_length[leap][i]; i++) { yearday-=month_length[leap][i]; } get_month=i; get_day=yearday; } inline bool RealDate::IsLeapYear() const { return (_year%4==0 && _year%100!=0 || _year%400==0)==1; } inline int RealDate::LengthOfNormalYear() const { return 365; } inline int RealDate::LengthOfLeapYear() const { return 366; } inline int RealDate::LengthOfYear() const { if(IsLeapYear()==true) { return LengthOfLeapYear(); } else { return LengthOfNormalYear(); } } inline int RealDate::Year() const { return _year; } inline int RealDate::Month() const { return _month; } inline int RealDate::Day() const { return _day; } inline void RealDate::_assert_date() const { assert(_year>=-4000000); assert(_year<=4000000); assert(DayOfYear() <= LengthOfYear()); assert(_month>=1); assert(_month<=12); assert(_day>=1); #ifndef NDEBUG const int leap=IsLeapYear(); assert(static_cast(_day) <= month_length[leap][_month]); #endif } inline bool RealDate::_valid_date() const { if( _year<-4000000 || _year>4000000 || DayOfYear() > LengthOfYear() || _month<1 || _month>12 || _day<1) { return false; } const int leap=IsLeapYear(); if(static_cast(_day) > month_length[leap][_month]) return false; return true; } const basearray RealDate::EncryptDate() const { basearray buffer(13); buffer[0]=static_cast(_day); buffer[1]=static_cast(_month); buffer[2]=static_cast(_year>>16); buffer[3]=static_cast(_year>>8); buffer[4]=static_cast(_year); unsigned crc=crc32::crc32(0, &buffer[0], 5); buffer[5]=static_cast(crc>>24); buffer[6]=static_cast(crc>>16); buffer[7]=static_cast(crc>>8); buffer[8]=static_cast(crc); for(int r=0; r<10; r++) { ran2int(&_encrypt_date_idum); } //cout<<_encrypt_date_idum<(_encrypt_date_idum>>24); buffer[10]=static_cast(_encrypt_date_idum>>16); buffer[11]=static_cast(_encrypt_date_idum>>8); buffer[12]=static_cast(_encrypt_date_idum); for(int i=0; i<=8; i++) { ran2int(&_encrypt_date_idum); buffer[i]^=static_cast(_encrypt_date_idum); } return buffer; } bool RealDate::LoadEncryptedDate(basearray buffer) { assert(buffer.size()==13); int idum= (buffer[9]<<24)+ (buffer[10]<<16)+ (buffer[11]<<8)+ (buffer[12]); //cout<(idum); } unsigned crc= (buffer[5]<<24u)+ (buffer[6]<<16u)+ (buffer[7]<<8u)+ static_cast(buffer[8]); if(crc32::crc32(0, &buffer[0], 5)!=crc) { #ifdef USE_EXCEPTIONS throw "RealDate::LoadEncryptedDate(basearray buffer: Bad CRC32.\n"; #endif return false; } RealDate backup(*this); _day=buffer[0]; _month=buffer[1]; _year= (buffer[2]<<16)+ (buffer[3]<<8)+ (buffer[4]); if(_valid_date()==false) { *this=backup; #ifdef USE_EXCEPTIONS throw "RealDate::LoadEncryptedDate(basearray buffer: Invalid date.\n"; #endif return false; } return true; } inline void RealDate::operator+=(int days) { const int old_year=_year; int day_of_year=DayOfYear()+days; while(day_of_year>LengthOfYear()) { day_of_year-=LengthOfYear(); assert(_year<4000000); if(_year==4000000) { _year=old_year; #ifdef USE_EXCEPTIONS throw "RealDate::operator+=(int days): _year in RealDate is too high.\n"; #endif return; } _year++; if(_year==0) { _year++; } } while(day_of_year<1) { assert(_year>-4000000); if(_year==-4000000) { _year=old_year; #ifdef USE_EXCEPTIONS throw "RealDate::operator+=(int days): _year in RealDate is too low.\n"; #endif return; } _year--; if(_year==0) { _year--; } day_of_year+=LengthOfYear(); } *this=RealDate(_year, day_of_year); _assert_date(); } inline void RealDate::operator-=(int days) { operator+=(-days); } ///////////////////////////////////////////////////////////////////////////// #endif //_INCLUDED_L3_DATE_H