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

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

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

J:BC.1/12/31 Fri 00:00:00 am == 3155695199999740800 seconds 
G:BC.1/12/31 Sun 00:00:00 am == 3155695200000000000 seconds 

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 

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
1/01/02 00:00:00