#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달쯤 된 코드.
그레고리언력 기준 BC. 1000억년 부터 AD. 4845억년 까지 표현됨
날짜 계산식에 반복문 따윈 없음.
와 많이 배워갑니다
훌륭하군여
어떤 프로젝트이길래 이런 거대한 초단위 날짜 타입이 필요한거죠? 자전 주기는 계속 변하는 터라 수억년의 기간만 되더라도 인간이 만들어놨던 그 어떤 역법과도 큰 차이가 생길텐데요?
좋은 지적이예요. 재밌는 프로젝트입니다. 히힣
이 프로젝트에서 중요한건 태양의 공전주기가 아니라 기록된 시각이라 말이죠 : )
아. 지구의 태양에 대한 공전주기라고 해야되는데. 대충 잘라먹어버렸네. 뭐 알아듣겠지.
답은 [boost.multiprecision] 이다.
boost 로 어떻게 할 수 있는 영역이 아닌데 ㅡㅡㅋ
안될건 뭐임?
안된다고 한적 없어 부스트로 어떻게 할 영역이 아니라고 했지. 디비의 fixed field 에 넣을거야.
그리고 연대학 문제는 달력시스템 한 두개로 풀리는 문제가 아니란걸 이야기 하는거.
또한 이 코드는 설정으로 간단히 precision 조절이 되지만, 확장성 보단 성능을 위해 최적화 되어 있어.
나도 그냥 임의의 precision을 가지는 데이터 타입을 얘기한거임 제목에 그게 주요 내용인 것 처럼 썻길래
필요한 precision 을 갖는데 / 랑 % 면 충분한데 boost 로 컴파일 속도 떨굴 필욘 없지. 저것보다 빠른 날짜 계산이라도 구현될게 아니라면 말야.
고정된 엔트로피 안에서 어디서 precision 벌어오는것도 아니고.
자기가 직접 작성하면 원래 / % + - * 이게 전부인 거지 뭘 난 그냥 첨엔 우스게 소리로 한건데 고집이 장난 아니시네.. 그럼 논리면 std.string은 왜 썻나요..?
고집이 장난이 아닌게 아니라 니가 구현해오든지유~ std::string 쓰는게 부스트 만큼 컴팔속도가 느림?
네 말대로 boost.multiprecision 로 구현해서 DB 에 집어 넣을때 이것보다 득이 뭐냐고? 용도가 전혀 다른데 뽈소리를 하고 있는게 너임.
참고로 직접 작성한걸 가벼이 여기고 그런건 아닌데 너무 딱딱하게 굴어서 하는 말이오
최적화는 꽤 해뒀지만, 날짜 출력 포맷은 아직 결정하지 못했음. <-- 라고 본문에 적어뒀듯, 어차피 처리가 느린 함수들은 다 대체할거임. 이건 목업 수준의 출력코드일 뿐.
근드 딱히 싸울것도 아닌게 첨에 그냥 웃자고 한말임
나도 웃으면서 boost 가 줄 수 있는 득이 없다고 이야기 한 것 뿐이잖?
float128 을 쓸까 고민했던것도 사실인데... 서버사이드에서 부담주기 싫었거든.
나도 뭐 응 안써 이 정도 답변 생각하고 쓴거라.. 기분 나빳으면 미안하고연 딴지건건 아님
이게 앞에 쓰레드가 있는데... 컨텍스트를 이해하는데 도움 되려나?
http://gall.dcinside.com/board/view/?id=programming&no=592140
코드는 진짜 잘 짜네 ㄹㅇ 굿
http://ideone.com/9h1dk6
예제다듬고 단항연산자 후위형 추가. VC++에서 시비걸어서 바꿔놓았던 type_traits 제거.