Skip to content

Commit 2682dc7

Browse files
committed
code remarks, macros and r2.6 support
1 parent cd7a329 commit 2682dc7

File tree

1 file changed

+69
-25
lines changed

1 file changed

+69
-25
lines changed

ext/date/date_core.c

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "ruby/util.h"
88
#include <math.h>
99
#include <time.h>
10-
#include <stdint.h> /* For uint64_t in Neri-Schneider algorithm */
1110
#if defined(HAVE_SYS_TIME_H)
1211
#include <sys/time.h>
1312
#endif
@@ -453,6 +452,9 @@ do {\
453452
static int c_valid_civil_p(int, int, int, double,
454453
int *, int *, int *, int *);
455454

455+
/* Check if using pure Gregorian calendar (sg == -Infinity) */
456+
#define c_gregorian_only_p(sg) (isinf(sg) && (sg) < 0)
457+
456458
/* Forward declarations for Neri-Schneider optimized functions */
457459
static int c_gregorian_civil_to_jd(int y, int m, int d);
458460
static void c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd);
@@ -467,7 +469,7 @@ c_find_fdoy(int y, double sg, int *rjd, int *ns)
467469
int d, rm, rd;
468470

469471
/* Fast path: pure Gregorian calendar */
470-
if (isinf(sg) && sg < 0) {
472+
if (c_gregorian_only_p(sg)) {
471473
*rjd = c_gregorian_fdoy(y);
472474
*ns = 1;
473475
return 1;
@@ -486,7 +488,7 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns)
486488
int i, rm, rd;
487489

488490
/* Fast path: pure Gregorian calendar */
489-
if (isinf(sg) && sg < 0) {
491+
if (c_gregorian_only_p(sg)) {
490492
*rjd = c_gregorian_ldoy(y);
491493
*ns = 1;
492494
return 1;
@@ -519,7 +521,7 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
519521
int i, rm, rd;
520522

521523
/* Fast path: pure Gregorian calendar */
522-
if (isinf(sg) && sg < 0) {
524+
if (c_gregorian_only_p(sg)) {
523525
*rjd = c_gregorian_ldom_jd(y, m);
524526
*ns = 1;
525527
return 1;
@@ -537,8 +539,8 @@ c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns)
537539
{
538540
int jd;
539541

540-
/* Fast path: pure Gregorian calendar (sg == -infinity) */
541-
if (isinf(sg) && sg < 0) {
542+
/* Fast path: pure Gregorian calendar */
543+
if (c_gregorian_only_p(sg)) {
542544
*rjd = c_gregorian_civil_to_jd(y, m, d);
543545
*ns = 1;
544546
return;
@@ -570,7 +572,7 @@ static void
570572
c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom)
571573
{
572574
/* Fast path: pure Gregorian or date after switchover, within safe range */
573-
if (((isinf(sg) && sg < 0) || jd >= sg) && ns_jd_in_range(jd)) {
575+
if ((c_gregorian_only_p(sg) || jd >= sg) && ns_jd_in_range(jd)) {
574576
c_gregorian_jd_to_civil(jd, ry, rm, rdom);
575577
return;
576578
}
@@ -789,7 +791,40 @@ c_gregorian_last_day_of_month(int y, int m)
789791
*/
790792

791793
/* JDN of March 1, Year 0 in proleptic Gregorian calendar */
792-
#define NS_GREGORIAN_EPOCH 1721120
794+
#define NS_EPOCH 1721120
795+
796+
/* Days in a 4-year cycle (3 normal years + 1 leap year) */
797+
#define NS_DAYS_IN_4_YEARS 1461
798+
799+
/* Days in a 400-year Gregorian cycle (97 leap years in 400 years) */
800+
#define NS_DAYS_IN_400_YEARS 146097
801+
802+
/* Years per century */
803+
#define NS_YEARS_PER_CENTURY 100
804+
805+
/*
806+
* Multiplier for extracting year within century using fixed-point arithmetic.
807+
* This is ceil(2^32 / NS_DAYS_IN_4_YEARS) for the Euclidean affine function.
808+
*/
809+
#define NS_YEAR_MULTIPLIER 2939745
810+
811+
/*
812+
* Coefficients for month calculation from day-of-year.
813+
* Maps day-of-year to month using: month = (NS_MONTH_COEFF * doy + NS_MONTH_OFFSET) >> 16
814+
*/
815+
#define NS_MONTH_COEFF 2141
816+
#define NS_MONTH_OFFSET 197913
817+
818+
/*
819+
* Coefficients for civil date to JDN month contribution.
820+
* Maps month to accumulated days: days = (NS_CIVIL_MONTH_COEFF * m - NS_CIVIL_MONTH_OFFSET) / 32
821+
*/
822+
#define NS_CIVIL_MONTH_COEFF 979
823+
#define NS_CIVIL_MONTH_OFFSET 2919
824+
#define NS_CIVIL_MONTH_DIVISOR 32
825+
826+
/* Days from March 1 to December 31 (for Jan/Feb year adjustment) */
827+
#define NS_DAYS_BEFORE_NEW_YEAR 306
793828

794829
/*
795830
* Safe bounds for Neri-Schneider algorithm to avoid integer overflow.
@@ -815,48 +850,57 @@ c_gregorian_civil_to_jd(int y, int m, int d)
815850
int d0 = d - 1;
816851

817852
/* Calculate year contribution with leap year correction */
818-
int q1 = DIV(y0, 100);
819-
int yc = DIV(1461 * y0, 4) - q1 + DIV(q1, 4);
853+
int q1 = DIV(y0, NS_YEARS_PER_CENTURY);
854+
int yc = DIV(NS_DAYS_IN_4_YEARS * y0, 4) - q1 + DIV(q1, 4);
820855

821856
/* Calculate month contribution using integer arithmetic */
822-
int mc = (979 * m0 - 2919) / 32;
857+
int mc = (NS_CIVIL_MONTH_COEFF * m0 - NS_CIVIL_MONTH_OFFSET) / NS_CIVIL_MONTH_DIVISOR;
823858

824859
/* Combine and add epoch offset to get JDN */
825-
return yc + mc + d0 + NS_GREGORIAN_EPOCH;
860+
return yc + mc + d0 + NS_EPOCH;
826861
}
827862

828863
/* Optimized: Julian Day Number -> Gregorian date */
829864
static void
830865
c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd)
831866
{
832867
int r0, n1, q1, r1, n2, q2, r2, n3, q3, r3, y0, j;
833-
uint64_t u2;
868+
#ifdef HAVE_LONG_LONG
869+
unsigned LONG_LONG u2;
870+
#endif
834871

835872
/* Convert JDN to rata die (March 1, Year 0 epoch) */
836-
r0 = jd - NS_GREGORIAN_EPOCH;
873+
r0 = jd - NS_EPOCH;
837874

838875
/* Extract century and day within 400-year cycle */
839876
/* Use Euclidean (floor) division for negative values */
840877
n1 = 4 * r0 + 3;
841-
q1 = DIV(n1, 146097); /* Century */
842-
r1 = MOD(n1, 146097) / 4; /* Day within 400-year cycle */
878+
q1 = DIV(n1, NS_DAYS_IN_400_YEARS);
879+
r1 = MOD(n1, NS_DAYS_IN_400_YEARS) / 4;
843880

844-
/* Use 64-bit arithmetic for year calculation within century */
881+
/* Calculate year within century and day of year */
845882
n2 = 4 * r1 + 3;
846-
u2 = (uint64_t)2939745 * (uint64_t)n2;
847-
q2 = (int)(u2 >> 32); /* Year within century */
848-
r2 = (int)((uint32_t)u2 / 2939745 / 4); /* Day of year */
883+
#ifdef HAVE_LONG_LONG
884+
/* Use 64-bit arithmetic to avoid overflow */
885+
u2 = (unsigned LONG_LONG)NS_YEAR_MULTIPLIER * (unsigned LONG_LONG)n2;
886+
q2 = (int)(u2 >> 32);
887+
r2 = (int)((unsigned int)u2 / NS_YEAR_MULTIPLIER / 4);
888+
#else
889+
/* Fallback for systems without 64-bit integers */
890+
q2 = n2 / NS_DAYS_IN_4_YEARS;
891+
r2 = (n2 % NS_DAYS_IN_4_YEARS) / 4;
892+
#endif
849893

850894
/* Calculate month and day using integer arithmetic */
851-
n3 = 2141 * r2 + 197913;
852-
q3 = n3 >> 16; /* Month (3-14) */
853-
r3 = (n3 & 0xFFFF) / 2141; /* Day of month (0-based) */
895+
n3 = NS_MONTH_COEFF * r2 + NS_MONTH_OFFSET;
896+
q3 = n3 >> 16;
897+
r3 = (n3 & 0xFFFF) / NS_MONTH_COEFF;
854898

855899
/* Combine century and year */
856-
y0 = 100 * q1 + q2;
900+
y0 = NS_YEARS_PER_CENTURY * q1 + q2;
857901

858902
/* Adjust for January/February (shift from fiscal year) */
859-
j = (r2 >= 306) ? 1 : 0;
903+
j = (r2 >= NS_DAYS_BEFORE_NEW_YEAR) ? 1 : 0;
860904

861905
*ry = y0 + j;
862906
*rm = j ? q3 - 12 : q3;

0 commit comments

Comments
 (0)