fork(1) download
  1. //---------------------------------------------------------------------------------------
  2. #include <iostream>
  3. #include <string>
  4. //---------------------------------------------------------------------------------------
  5.  
  6. #define CSTR
  7.  
  8. using i8 = char;
  9. using u8 = unsigned char;
  10. using i16 = short;
  11. using u16 = unsigned short;
  12. using i32 = int;
  13. using u32 = unsigned int;
  14. using i64 = long long;
  15. using u64 = unsigned long long;
  16.  
  17. using f32 = float;
  18. using f64 = double;
  19.  
  20. #define rigid constexpr
  21.  
  22. //---------------------------------------------------------------------------------------
  23.  
  24. rigid u32 CHAR_BITS = 8;
  25.  
  26. template< typename T >
  27. inline rigid auto msb()
  28. {
  29. return sizeof( T ) * CHAR_BITS - 1;
  30. }
  31.  
  32. template< typename T >
  33. inline rigid auto msb_value()
  34. {
  35. return (T)1 << msb< T >();
  36. }
  37.  
  38. #define msb_pos( var ) msb< decltype( var ) >()
  39. #define msb_val( var ) msb_value< decltype( var ) >()
  40.  
  41. template< typename T0, typename T1 >
  42. inline void set_msbs( T0& dst, const T1 bits )
  43. {
  44. *( (T1*)&dst + ( sizeof dst / sizeof bits - 1 ) ) |= bits;
  45. }
  46. //---------------------------------------------------------------------------------------
  47.  
  48. template< typename TR >
  49. inline TR atou( char*& s )
  50. {
  51. TR value;
  52. for( value = 0; *s <= '9' && *s >= '0'; ++s )
  53. value = value * 10 + ( *s & 0xF );
  54. return value;
  55. }
  56.  
  57. template< typename TR >
  58. inline TR atoi( char*& s )
  59. {
  60. if( *s == '-' )
  61. return (TR)( -1 * atou< TR >( ++s ) );
  62. return (TR)atou< TR >( s );
  63. }
  64.  
  65. #include <cmath>
  66. template< typename TR = f64 >
  67. inline TR atof( char*& s )
  68. {
  69. char* p = s;
  70. u32 sign = 0;
  71. TR digit = 0.;
  72. TR base = 1.;
  73. TR step = 1.;
  74.  
  75. for( i8 token; token = *p++; )
  76. {
  77. switch( token )
  78. {
  79. case '-':
  80. sign = msb_val( sign );
  81. break;
  82. case '.':
  83. step = 10;
  84. break;
  85. case 'E':
  86. case 'e':
  87. digit *= (TR)std::pow( 10., (f64)atof< TR >( s = p ) );
  88. goto exit;
  89. default:
  90. if( token <= '9' && token >= '0' )
  91. {
  92. digit = digit * 10 + ( token & 0xF );
  93. base *= step;
  94. continue;
  95. }
  96. goto exit;
  97. }
  98. }
  99. exit:
  100. if( s < p - 1 ) s = p - 1;
  101. set_msbs( digit, sign );
  102. return TR( digit / base );
  103. }
  104. //---------------------------------------------------------------------------------------
  105.  
  106. #include <string>
  107. #include <stdarg.h>
  108.  
  109. template< u32 MAX_SIZE = 1024 >
  110. inline std::string format_string( const char* format, ... )
  111. {
  112. char temp[ MAX_SIZE ];
  113. va_list va;
  114. va_start( va, format );
  115. vsprintf( temp, format, va );
  116. va_end( va );
  117. return temp;
  118. }
  119. //---------------------------------------------------------------------------------------
  120.  
  121. #include <type_traits>
  122.  
  123. template< typename T >
  124. inline char* parse_number( const char* string, T& param )
  125. {
  126. char* s = (char*)string;
  127. while( *s <= ' ' || *s == '/' || *s == ':' ) s++;
  128.  
  129. if( std::is_floating_point< T >() )
  130. param = atof< T >( s );
  131. else
  132. {
  133. if( std::is_signed< T >() )
  134. param = atoi< T >( s );
  135. else
  136. param = atou< T >( s );
  137. }
  138. return s;
  139. }
  140.  
  141. template< typename T, typename... Ts >
  142. inline char* parse_number( const char* string, T& param1, Ts&... rest )
  143. {
  144. return parse_number( parse_number( string, param1 ), rest... );
  145. }
  146. //---------------------------------------------------------------------------------------
  147.  
  148. rigid i32 msecs_in_1sec = 1000;
  149. rigid i32 secs_in_1min = 60;
  150. rigid i32 mins_in_1hour = 60;
  151. rigid i32 hours_in_1day = 24;
  152. rigid i32 secs_in_1hour = mins_in_1hour * secs_in_1min;
  153. rigid i32 mins_in_1day = hours_in_1day * mins_in_1hour;
  154. rigid i32 secs_in_1day = mins_in_1day * secs_in_1min;
  155. rigid i32 msecs_in_1day = secs_in_1day * msecs_in_1sec;
  156. rigid i32 value_of_1day = secs_in_1day;
  157.  
  158. rigid i32 days_in_1year = 365;
  159. rigid i32 days_in_4years = days_in_1year * 4 + 1;
  160. rigid i32 days_in_100years = days_in_4years * 25 - 1;
  161. rigid i32 days_in_400years = days_in_100years * 4 + 1;
  162. rigid i32 secs_in_1year = days_in_1year * secs_in_1day;
  163.  
  164. rigid i64 years_in_bc = 100000000000LL;
  165. rigid i64 days_in_bc = years_in_bc / 400 * days_in_400years;
  166. rigid i64 secs_in_bc = days_in_bc * secs_in_1day;
  167. rigid i64 days_in_bc_greg = days_in_400years * years_in_bc / 400;
  168. rigid i64 days_in_bc_juli = days_in_4years * years_in_bc / 4;
  169. rigid i64 juli_to_greg = days_in_bc_greg - days_in_bc_juli - 2;
  170.  
  171. rigid i32 final_day_fragment = (u64)-1 - (u64)-1 / value_of_1day * value_of_1day;
  172.  
  173. rigid u32 sum_days100[ 4 ][ 14 ]
  174. {
  175. { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, },
  176. { 0, 365, 396, 424, 455, 485, 516, 546, 577, 608, 638, 669, 699, 730, },
  177. { 0, 730, 761, 789, 820, 850, 881, 911, 942, 973, 1003, 1034, 1064, 1095, },
  178. { 0, 1095, 1126, 1154, 1185, 1215, 1246, 1276, 1307, 1338, 1368, 1399, 1429, 1460, },
  179. };
  180.  
  181. rigid u32 sum_days[ 4 ][ 14 ]
  182. {
  183. { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, },
  184. { 0, 365, 396, 424, 455, 485, 516, 546, 577, 608, 638, 669, 699, 730, },
  185. { 0, 730, 761, 789, 820, 850, 881, 911, 942, 973, 1003, 1034, 1064, 1095, },
  186. { 0, 1095, 1126, 1155, 1186, 1216, 1247, 1277, 1308, 1339, 1369, 1400, 1430, 1461, },
  187. };
  188.  
  189. rigid char* day_names[]
  190. {
  191. "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
  192. };
  193. //---------------------------------------------------------------------------------------
  194.  
  195. template< typename T0, typename T1, typename T2 >
  196. inline auto times( const T0 hours, const T1 mins, const T2 secs )
  197. {
  198. return hours * secs_in_1hour + mins * secs_in_1min + secs;
  199. }
  200.  
  201. template< typename T >
  202. inline u64 days( const T days )
  203. {
  204. return days * secs_in_1day;
  205. }
  206.  
  207. inline u64 seconds( const u64 secs )
  208. {
  209. return secs;
  210. }
  211. ///--------------------------------------------------------------------------------------
  212.  
  213. enum class DATE_METHOD
  214. {
  215. julian,
  216. gregorian,
  217. };
  218.  
  219. template< DATE_METHOD method = DATE_METHOD::gregorian >
  220. class DATE_
  221. {
  222. private:
  223. u64 secs;
  224.  
  225. void date_parsing( const char* date_string )
  226. {
  227. i64 year;
  228. u32 month, day;
  229. parse_number( date_string, year, month, day );
  230. encode( year, month, day );
  231. }
  232.  
  233. public:
  234. CSTR DATE_() : secs( 0 )
  235. {}
  236. CSTR explicit DATE_( const u64 secs ) : secs( secs )
  237. {}
  238. CSTR DATE_( const i64 year, const u32 mm, const u32 dd )
  239. {
  240. encode( year, mm, dd );
  241. }
  242. CSTR DATE_( const i64 year, const u32 mm, const u32 dd,
  243. const u32 hh, const u32 nn, const u32 ss )
  244. {
  245. encode( year, mm, dd );
  246. secs += times( hh, nn, ss );
  247. }
  248. CSTR explicit DATE_( const char* date_string )
  249. {
  250. date_parsing( date_string );
  251. }
  252. CSTR explicit DATE_( const std::string date_string )
  253. {
  254. date_parsing( date_string.c_str() );
  255. }
  256.  
  257. void encode( const i64 year, const u32 month, const u32 day )
  258. {
  259. u64 xx = year + years_in_bc - ( year > 0 );
  260. if( method == DATE_METHOD::gregorian )
  261. {
  262. secs = xx / 400 * days_in_400years;
  263. u32 x2 = xx % 400;
  264.  
  265. u32 y1 = x2 / 100 * days_in_100years;
  266. u32 x1 = x2 % 100;
  267.  
  268. u32 y0 = x1 / 4 * days_in_4years;
  269. u32 x0 = x1 % 4;
  270.  
  271. auto s = sum_days[ x0 ];
  272. if( x2 != 399 && x1 == 99 )
  273. s = sum_days100[ x0 ];
  274.  
  275. secs += y1 + y0 + s[ month ] + day - 1;
  276. }
  277. else
  278. {
  279. secs = xx / 4 * days_in_4years +
  280. ( sum_days[ xx % 4 ][ month ] + day + ( juli_to_greg - 1 ) );
  281. }
  282. secs *= value_of_1day;
  283. }
  284.  
  285. void decode( i64& year, u32& month, u32& day ) const
  286. {
  287. u64 xx = secs / value_of_1day;
  288. u32 x, y;
  289. year = -years_in_bc;
  290. auto s = sum_days;
  291. if( method == DATE_METHOD::gregorian )
  292. {
  293. year += xx / days_in_400years * 400;
  294. u32 x2 = xx % days_in_400years;
  295.  
  296. u32 y1 = x2 / days_in_100years - x2 / ( days_in_100years * 4 );
  297. u32 x1 = x2 - days_in_100years * y1;
  298. y1 = y1 * 100;
  299.  
  300. u32 y0 = x1 / days_in_4years * 4;
  301. x = x1 % days_in_4years;
  302.  
  303. y = x / days_in_1year - x / ( days_in_1year * 4 );
  304.  
  305. if( y1 < 300 && y0 + y == 99 )
  306. s = sum_days100;
  307.  
  308. year += y1 + y0 + y;
  309. }
  310. else
  311. {
  312. xx -= juli_to_greg;
  313.  
  314. u64 y0 = xx / days_in_4years * 4;
  315. x = xx % days_in_4years;
  316.  
  317. y = x / days_in_1year - x / ( days_in_1year * 4 );
  318.  
  319. year += y0 + y;
  320. }
  321.  
  322. month = ( x - y * days_in_1year ) / 29;
  323. month += x >= s[ y ][ month + 1 ];
  324. day = x - s[ y ][ month ] + 1;
  325. year += year >= 0;
  326. }
  327. ///----------------------------------------------------------------------------------
  328.  
  329. const auto name() const
  330. {
  331. return day_names[ secs / value_of_1day % 7 ];
  332. }
  333.  
  334. const auto date( bool ad_bc = false ) const
  335. {
  336. i64 year;
  337. u32 month, day;
  338. decode( year, month, day );
  339. if( !ad_bc )
  340. return format_string( "%lld/%02u/%02u", year, month, day );
  341. else
  342. return format_string( "%s.%llu/%02u/%02u", year > 0 ? "AD" : "BC",
  343. std::abs( year ), month, day );
  344. }
  345.  
  346. const auto time( bool am_pm = false ) const
  347. {
  348. u32 hh, mm, ss;
  349. ss = time_seconds();
  350. hh = ss / secs_in_1hour;
  351. ss = ss % secs_in_1hour;
  352. mm = ss / secs_in_1min;
  353. ss = ss % secs_in_1min;
  354. return format_string( "%02u:%02u:%02u", hh, mm, ss ) +
  355. ( am_pm ? ( hh < 12 ? " am" : " pm" ) : "" );
  356. }
  357.  
  358. const auto date_time() const
  359. {
  360. return date() + " " + time();
  361. }
  362.  
  363. const auto long_date() const
  364. {
  365. return std::string( method == DATE_METHOD::gregorian ? "G:" : "J:" ) +
  366. date( true ) + " " + name();
  367. }
  368.  
  369. const auto long_date_time() const
  370. {
  371. return long_date() + " " + time( true );
  372. }
  373. ///----------------------------------------------------------------------------------
  374.  
  375. const auto seconds() const
  376. {
  377. return secs;
  378. }
  379.  
  380. const u32 time_seconds() const
  381. {
  382. return secs % secs_in_1day;
  383. }
  384.  
  385. const auto days() const
  386. {
  387. return secs / secs_in_1day;
  388. }
  389. ///----------------------------------------------------------------------------------
  390.  
  391. template< DATE_METHOD M >
  392. const auto operator-( const DATE_< M >& rhs ) const
  393. {
  394. return DATE_< method >( secs - rhs.seconds() );
  395. }
  396.  
  397. template< DATE_METHOD M >
  398. const auto operator+( const DATE_< M >& rhs ) const
  399. {
  400. return DATE_< method >( secs + rhs.seconds() );
  401. }
  402.  
  403. const auto operator-( const u64 duration ) const
  404. {
  405. return DATE_< method >( secs - duration );
  406. }
  407.  
  408. const auto operator+( const u64 duration ) const
  409. {
  410. return DATE_< method >( secs + duration );
  411. }
  412.  
  413. auto& operator-=( const DATE_& rhs )
  414. {
  415. return secs -= rhs.secs, *this;
  416. }
  417.  
  418. auto& operator+=( const DATE_& rhs )
  419. {
  420. return secs += rhs.secs, *this;
  421. }
  422.  
  423. auto& operator-=( const u64 duration )
  424. {
  425. return secs -= duration, *this;
  426. }
  427.  
  428. auto& operator+=( const u64 duration )
  429. {
  430. return secs += duration, *this;
  431. }
  432.  
  433. auto& operator--()
  434. {
  435. return *this -= secs_in_1day;
  436. }
  437.  
  438. auto& operator++()
  439. {
  440. return *this += secs_in_1day;
  441. }
  442.  
  443. auto operator--( int )
  444. {
  445. DATE_< method > back( secs );
  446. secs -= secs_in_1day;
  447. return back;
  448. }
  449.  
  450. auto operator++( int )
  451. {
  452. DATE_< method > back( secs );
  453. secs += secs_in_1day;
  454. return back;
  455. }
  456.  
  457. const bool operator<( const DATE_& rhs ) const
  458. {
  459. return secs < rhs.secs;
  460. }
  461.  
  462. friend std::ostream& operator<<( std::ostream& os, const DATE_& date )
  463. {
  464. return os << date.long_date_time();
  465. }
  466. };
  467. //---------------------------------------------------------------------------------------
  468.  
  469. using DATE = DATE_< DATE_METHOD::gregorian >;
  470. using DATEJ = DATE_< DATE_METHOD::julian >;
  471.  
  472. inline auto historical_date( const DATE gregorian_date )
  473. {
  474. const auto julian_to_gregorian_date = DATE( 1582,10,15 );
  475. if( gregorian_date < julian_to_gregorian_date )
  476. return DATEJ( gregorian_date.seconds() ).long_date();
  477. return gregorian_date.long_date();
  478. }
  479. //---------------------------------------------------------------------------------------
  480. //---------------------------------------------------------------------------------------
  481.  
  482. using namespace std;
  483.  
  484. int main()
  485. {
  486. cout << sizeof( DATE ) <<
  487. " bytes DATE_< Julian & Gregorian > type" << endl << endl;
  488.  
  489. cout << "Julian date range" << endl;
  490. cout << DATEJ( 0ULL ) << " ~ " << endl;
  491. cout << DATEJ( 0xFFFFFFFFFFFFFFFFULL ) << endl;
  492. cout << endl;
  493.  
  494. cout << "Gregorian date range" << endl;
  495. cout << DATE( 0ULL ) << " ~ " << endl;
  496. cout << DATE( (u64)-1 ) << endl;
  497. cout << endl;
  498.  
  499. cout << "First day of AD unary" << endl;
  500. cout << ++DATEJ( -1,12,31 ) << " == " << DATEJ( 1, 1, 1 ).seconds() <<
  501. " seconds " << endl;
  502. cout << ++DATE( "-1/12/31" ) << " == " << DATE( "1/ 1/ 1" ).seconds() <<
  503. " seconds " << endl;
  504. cout << endl;
  505.  
  506. cout << "First day of AD conversion" << endl;
  507. cout << DATEJ( 1, 1, 1 ) << " == " <<
  508. DATE( DATEJ( 1, 1, 1 ).seconds() ).days() << " th day " << endl;
  509. cout << DATE( 1, 1, 1 ) << " == " <<
  510. DATEJ( DATE( 1, 1, 1 ).seconds() ).days() << " th day " << endl;
  511. cout << endl;
  512.  
  513. cout << "Historical seam of Julian to Gregorian" << endl;
  514. cout << DATE( 1582, 10, 14 ) << " == " <<
  515. historical_date( DATE( "1582/10/14" ) ) << endl;
  516. cout << DATE( 1582, 10, 15 ) << " == " <<
  517. historical_date( DATE( "1582/10/15" ) ) << endl;
  518. cout << endl;
  519.  
  520. cout << "Time methods" << endl;
  521. cout << DATE( times( 23, 59, 30 ) ).time() << endl;
  522. cout << DATE( 2016, 3, 30, 9, 50, 45 ) << endl;
  523. cout << endl;
  524.  
  525. cout << "Adder test" << endl;
  526. DATE date( DATE() + days( days_in_bc ) + times( 23, 59, 30 ) + seconds( 30 ) );
  527. cout << date++.date_time() << endl;
  528. cout << (++date).date_time() << endl;
  529. cout << endl;
  530.  
  531. getchar();
  532. return 0;
  533. }
  534. //---------------------------------------------------------------------------------------
Success #stdin #stdout 0s 3428KB
stdin
Standard input is empty
stdout
8 bytes DATE_< Julian & Gregorian > type

Julian date range
J:BC.99997946612/02/05 Mon 00:00:00 am ~ 
J:AD.484544099479/09/22 Mon 07:00:15 am

Gregorian date range
G:BC.100000000000/01/01 Mon 00:00:00 am ~ 
G:AD.484554049254/11/09 Mon 07:00:15 am

First day of AD unary
J:AD.1/01/01 Sat 00:00:00 am == 3155695199999827200 seconds 
G:AD.1/01/01 Mon 00:00:00 am == 3155695200000000000 seconds 

First day of AD conversion
J:AD.1/01/01 Sat 00:00:00 am == 36524249999998 th day 
G:AD.1/01/01 Mon 00:00:00 am == 36524250000000 th day 

Historical seam of Julian to Gregorian
G:AD.1582/10/14 Thu 00:00:00 am == J:AD.1582/10/04 Thu
G:AD.1582/10/15 Fri 00:00:00 am == G:AD.1582/10/15 Fri

Time methods
23:59:30
G:AD.2016/03/30 Wed 09:50:45 am

Adder test
1/01/02 00:00:00
1/01/04 00:00:00