viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b38577a16fb3dab004c86b6fb8c469a51a456a5782032fed780bd3a47f47c6526366d52631d19a6150c3966ac4ad0d72ce89bc7533fa462576


viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b38577a16fb3dab004c86b6fb8c469a51a456a5782032fed780bd3a47f47c6526366d52631d19a6150c3966ac4fe5a26ca8eef7260fa462576


#include <iostream>

#include <string>


#define CSTR


using   i8                      = char;

using   u8                      = unsigned char;

using   i16                     = short;

using   u16                     = unsigned short;

using   i32                     = int;

using   u32                     = unsigned int;

using   i64                     = long long;

using   u64                     = unsigned long long;


using   f32                     = float;

using   f64                     = double;


#define rigid                   constexpr


//---------------------------------------------------------------------------------------


rigid   u32 CHAR_BITS           = 8;


template< typename T >

inline  rigid   auto    msb()

{

    return  sizeof( T ) * CHAR_BITS - 1;

}


template< typename T >

inline  rigid   auto    msb_value()

{

    return  (T)1 << msb< T >();

}


#define msb_pos( var ) msb< decltype( var ) >()

#define msb_val( var ) msb_value< decltype( var ) >()


template< typename T0, typename T1 >

inline  void    set_msbs( T0& dst, const T1 bits )

{

    *( (T1*)&dst + ( sizeof dst / sizeof bits - 1 ) ) |= bits;

}

//---------------------------------------------------------------------------------------


template< typename TR >

inline  TR      atou( char*& s )

{

    TR value;

    for( value = 0; *s <= '9' && *s >= '0'; ++s )

        value = value * 10 + ( *s & 0xF );

    return  value;

}


template< typename TR >

inline  TR      atoi( char*& s )

{

    if( *s == '-' )

        return  (TR)( -1 * atou< TR >( ++s ) );

    return  (TR)atou< TR >( s );

}


#include <cmath>

template< typename T = f64 >

inline  T       atof( char*& s )

{

    char* p = s;

    u32 sign = 0;

    T   digit = 0.;

    T   base = 1.;

    T   step = 1.;


    for( i8 token; token = *p++; )

    {

        switch( token )

        {

        case '-':

            sign = msb_val( sign );

            break;

        case '.':

            step = 10;

            break;

        case 'E':

        case 'e':

            digit *= (T)std::pow( 10., (f64)atof< T >( s = p ) );

            goto exit;

        default:

            if( token <= '9' && token >= '0' )

            {

                digit = digit * 10 + ( token & 0xF );

                base *= step;

                continue;

            }

            goto exit;

        }

    }

exit:

    if( s < p - 1 ) s = p - 1;

    set_msbs( digit, sign );

    return  T( digit / base );

}

//---------------------------------------------------------------------------------------


#include <stdarg.h>


template< const u32 MAX_SIZE = 1024 >

inline  std::string     format_string( const char* format, ... )

{

    char    temp[ MAX_SIZE ];

    va_list va;

    va_start( va, format );

    vsprintf( temp, format, va );

    va_end( va );

    return  temp;

//---------------------------------------------------------------------------------------


#include <type_traits>


template< typename T >

inline  rigid   auto    is_signed_()

{

    return  std::is_same< T, i8  >::value || std::is_same< T, i16 >::value ||

            std::is_same< T, i32 >::value || std::is_same< T, i64 >::value;

}


template< typename T >

inline  rigid   auto    is_unsigned_()

{

    return  std::is_same< T, u8  >::value || std::is_same< T, u16 >::value ||

            std::is_same< T, u32 >::value || std::is_same< T, u64 >::value;

}


template< typename T >

inline  rigid   auto    is_floating_()

{

    return  std::is_same< T, f32 >::value || std::is_same< T, f64 >::value;

}


template< typename T >

inline  char*   parse_number( const char* string, T& param )

{

    char* s = (char*)string;

    while( *s <= ' ' || *s == '/' || *s == ':' ) s++;


    if( is_signed_< T >() )

    {

        param = atoi< T >( s );

    }

    else if( is_unsigned_< T >() )

    {

        param = atou< T >( s );

    }

    else if( is_floating_< T >() )

    { 

        param = atof< T >( s );

    }

    return  s;

}


template< typename T, typename... Ts >

inline  char*   parse_number( const char* string, T& param1, Ts&... rest )

{

    return  parse_number( parse_number( string, param1 ), rest... );

}

//---------------------------------------------------------------------------------------


rigid   i32  msecs_in_1sec      = 1000;

rigid   i32   secs_in_1min      = 60;

rigid   i32   mins_in_1hour     = 60;

rigid   i32  hours_in_1day      = 24;

rigid   i32   secs_in_1hour     = mins_in_1hour     * secs_in_1min;

rigid   i32   mins_in_1day      = hours_in_1day     * mins_in_1hour;

rigid   i32   secs_in_1day      = mins_in_1day      * secs_in_1min;

rigid   i32  msecs_in_1day      = secs_in_1day      * msecs_in_1sec;

rigid   i32  value_of_1day      = secs_in_1day;


rigid   i32   days_in_1year     = 365;

rigid   i32   days_in_4years    = days_in_1year     * 4  + 1;

rigid   i32   days_in_100years  = days_in_4years    * 25 - 1;

rigid   i32   days_in_400years  = days_in_100years  * 4  + 1;

rigid   i32   secs_in_1year     = days_in_1year     * secs_in_1day;

                                  

rigid   i64  years_in_bc        = 100000000000LL;

rigid   i64   days_in_bc        = years_in_bc / 400 * days_in_400years;

rigid   i64   secs_in_bc        = days_in_bc        * secs_in_1day;

rigid   i64   days_in_bc_greg   = days_in_400years  * years_in_bc / 400;

rigid   i64   days_in_bc_juli   = days_in_4years    * years_in_bc / 4;

rigid   i64   juli_to_greg      = days_in_bc_greg   - days_in_bc_juli - 2;


rigid   i32 final_day_fragment  = (u64)-1 - (u64)-1 / value_of_1day * value_of_1day;


rigid   u32 sum_days100[ 4 ][ 14 ]

{

    { 0,    0,   31,   59,   90,  120,  151,  181,  212,  243,  273,  304,  334,  365, },

    { 0,  365,  396,  424,  455,  485,  516,  546,  577,  608,  638,  669,  699,  730, },

    { 0,  730,  761,  789,  820,  850,  881,  911,  942,  973, 1003, 1034, 1064, 1095, },

    { 0, 1095, 1126, 1154, 1185, 1215, 1246, 1276, 1307, 1338, 1368, 1399, 1429, 1460, },

};


rigid   u32 sum_days[ 4 ][ 14 ]

{

    { 0,    0,   31,   59,   90,  120,  151,  181,  212,  243,  273,  304,  334,  365, },

    { 0,  365,  396,  424,  455,  485,  516,  546,  577,  608,  638,  669,  699,  730, },

    { 0,  730,  761,  789,  820,  850,  881,  911,  942,  973, 1003, 1034, 1064, 1095, },

    { 0, 1095, 1126, 1155, 1186, 1216, 1247, 1277, 1308, 1339, 1369, 1400, 1430, 1461, },

};


const   char*   day_names[]

{

    "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",

};

//---------------------------------------------------------------------------------------


template< typename T0, typename T1, typename T2 >

inline  auto                    times( const T0 hours, const T1 mins, const T2 secs )

{

    return  hours * secs_in_1hour + mins * secs_in_1min + secs;

}


template< typename T >

inline  u64                     days( const T days )

{

    return  days * secs_in_1day;

}


inline  u64                     seconds( const u64 secs )

{

    return  secs;

}

///--------------------------------------------------------------------------------------


enum    class                   DATE_METHOD

{

    julian,

    gregorian,

};


template< DATE_METHOD method =  DATE_METHOD::gregorian >

class   DATE_

{

private:

    u64                         secs;


    void                        date_parsing( const char* date_string )

    {

        i64     year;

        u32     month, day;

        parse_number( date_string, year, month, day );

        encode( year, month, day );

    }


public:

    CSTR                        DATE_() : secs( 0 )

    {}

    CSTR    explicit            DATE_( const u64 secs ) : secs( secs )

    {}

    CSTR                        DATE_( const i64 year, const u32 mm, const u32 dd )

    {

        encode( year, mm, dd );

    }

    CSTR                        DATE_( const i64 year, const u32 mm, const u32 dd,

                                       const u32 hh, const u32 nn, const u32 ss )

    {

        encode( year, mm, dd );

        secs += times( hh, nn, ss );

    }


    CSTR    explicit            DATE_( const char* date_string )

    {

        date_parsing( date_string );

    }

    CSTR    explicit            DATE_( const std::string date_string )

    {

        date_parsing( date_string.c_str() );

    }


    void                        encode( const i64 year, const u32 month, const u32 day )

    {

        u64     xx  = year + years_in_bc - ( year > 0 );

        if( method == DATE_METHOD::gregorian )

        {

            secs    = xx / 400 * days_in_400years;

            u32 x2  = xx % 400;


            u32 y1  = x2 / 100 * days_in_100years;

            u32 x1  = x2 % 100;


            u32 y0  = x1 / 4 * days_in_4years;

            u32 x0  = x1 % 4;


            auto s  = sum_days[ x0 ];

            if( x2 != 399 && x1 == 99 )

                 s  = sum_days100[ x0 ];


            secs   += y1 + y0 + s[ month ] + day - 1;

        }

        else

        {

            secs    = xx / 4 * days_in_4years +

                      ( sum_days[ xx % 4 ][ month ] + day + ( juli_to_greg - 1 ) );

        }

        secs       *= value_of_1day;

    }


    void                        decode( i64& year, u32& month, u32& day ) const

    {

        u64     xx  = secs / value_of_1day;

        u32     x, y;

        year        = -years_in_bc;

        auto    s   = sum_days;

        if( method == DATE_METHOD::gregorian )

        {

            year   += xx / days_in_400years * 400;

            u32 x2  = xx % days_in_400years;


            u32 y1  = x2 / days_in_100years - x2 / ( days_in_100years * 4 );

            u32 x1  = x2 - days_in_100years * y1;

                y1  = y1 * 100;


            u32 y0  = x1 / days_in_4years * 4;

            x       = x1 % days_in_4years;


            y       = x / days_in_1year - x / ( days_in_1year * 4 );


            if( y1 < 300 && y0 + y == 99  )

                s   = sum_days100;


            year   += y1 + y0 + y;

        }

        else

        {

            xx     -= juli_to_greg;


            u64 y0  = xx / days_in_4years * 4;

            x       = xx % days_in_4years;


            y       = x / days_in_1year - x / ( days_in_1year * 4 );


            year   += y0 + y;

        }


        month       = ( x - y * days_in_1year ) / 29;

        month      += x >= s[ y ][ month + 1 ];

        day         = x - s[ y ][ month ] + 1;

        year       += year >= 0;

    }

    ///----------------------------------------------------------------------------------


    const   auto                name() const

    {

        return  day_names[ secs / value_of_1day % 7 ];

    }


    const   auto                date( bool ad_bc = false ) const

    {

        i64     year;

        u32     month, day;

        decode( year, month, day );

        if( !ad_bc )

            return  format_string( "%lld/u/u", year, month, day );

        else

            return  format_string( "%s.%llu/u/u", year > 0 ? "AD" : "BC",

                    std::abs( year ), month, day );

    }


    const   auto                time( bool am_pm = false ) const

    {

        u32     hh, mm, ss;

        ss      = time_seconds();

        hh      = ss / secs_in_1hour;

        ss      = ss % secs_in_1hour;

        mm      = ss / secs_in_1min;

        ss      = ss % secs_in_1min;

        return  format_string( "u:u:u", hh, mm, ss ) +

                ( am_pm ? ( hh < 12 ? " am" : " pm" ) : "" );

    }


    const   auto                date_time() const

    {

        return  date() + " " + time();

    }


    const   auto                long_date() const

    {

        return  std::string( method == DATE_METHOD::gregorian ? "G:" : "J:" ) +

            date( true ) + " " + name();

    }


    const   auto                long_date_time() const

    {

        return  long_date() + " " + time( true );

    }

    ///----------------------------------------------------------------------------------


    const   auto                seconds() const

    {

        return  secs;

    }


    const   u32                 time_seconds() const

    {

        return  secs % secs_in_1day;

    }


    const   auto                days() const

    {

        return  secs / secs_in_1day;

    }

    ///----------------------------------------------------------------------------------


    auto&                       operator-=( const DATE_& rhs )

    {

        return  secs -= rhs.secs, *this;

    }


    auto&                       operator+=( const DATE_& rhs )

    {

        return  secs += rhs.secs, *this;

    }


    template< DATE_METHOD M >

    const   auto                operator-( const DATE_< M >& rhs ) const

    {

        return  DATE_< method >( secs - rhs.seconds() );

    }


    template< DATE_METHOD M >

    const   auto                operator+( const DATE_< M >& rhs ) const

    {

        return  DATE_< method >( secs + rhs.seconds() );

    }


    const   auto                operator-( const u64 duration ) const

    {

        return  DATE_< method >( secs - duration );

    }


    const   auto                operator+( const u64 duration ) const

    {

        return  DATE_< method >( secs + duration );

    }


    auto&                       operator-=( const u64 duration )

    {

        return  secs -= duration, *this;

    }


    auto&                       operator+=( const u64 duration )

    {

        return  secs += duration, *this;

    }


    auto&                       operator--()

    {

        return  *this -= secs_in_1day;

    }


    auto&                       operator++()

    {

        return  *this += secs_in_1day;

    }


    const   bool                operator<( const DATE_& rhs ) const

    {

        return  secs < rhs.secs;

    }


    friend  std::ostream&       operator<<( std::ostream& os, const DATE_& date )

    {

        return  os << date.long_date_time();

    }

};

//---------------------------------------------------------------------------------------


using   DATE  = DATE_< DATE_METHOD::gregorian >;

using   DATEJ = DATE_< DATE_METHOD::julian >;


inline  auto    historical_date( const DATE gregorian_date )

{

    const   auto    julian_to_gregorian_date = DATE( 1582,10,15 );

    if( gregorian_date < julian_to_gregorian_date )

        return  DATEJ( gregorian_date.seconds() ).long_date();

    return  gregorian_date.long_date();

}

//---------------------------------------------------------------------------------------


율리우스력 ~ 그레고리력으로 넘어가는 경계 ( 1582년 10월 15일 ) 처리와

클래스 공용형태에 주목.


enum    class                   DATE_METHOD

{

    julian,

    gregorian,

};


template< DATE_METHOD method =  DATE_METHOD::gregorian >

class   DATE_


최적화는 꽤 해뒀지만, 날짜 출력 포맷은 아직 결정하지 못했음.

좀 찍어보고 고민을 해야 할듯.

꽤 중요한 프로젝트에 사용될 코드고

니들이 워낙 피드백을 주지 않으니 그닥 공개할 생각은 없었는데,

여기까진 괜찮을듯. 만들어둔지 2달쯤 된 코드.


http://ideone.com/B4iuWV