

#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
댓글 영역
획득법
① NFT 발행
작성한 게시물을 NFT로 발행하면 일주일 동안 사용할 수 있습니다. (최초 1회)
② NFT 구매
다른 이용자의 NFT를 구매하면 한 달 동안 사용할 수 있습니다. (구매 시마다 갱신)
사용법
디시콘에서지갑연결시 바로 사용 가능합니다.