@@ -109,9 +109,16 @@ public readonly partial struct DateTime
109
109
// All OA dates must be less than (not <=) OADateMaxAsDouble
110
110
private const double OADateMaxAsDouble = 2958466.0 ;
111
111
112
- // Euclidean Affine Functions Algorithm constants
112
+ // Euclidean Affine Functions Algorithm (EAF) constants
113
+
114
+ // Constants used for fast calculation of following subexpressions
115
+ // x / DaysPer4Years
116
+ // x % DaysPer4Years / 4
117
+ private const uint EafMultiplier = ( uint ) ( ( ( 1UL << 32 ) + DaysPer4Years - 1 ) / DaysPer4Years ) ; // 2,939,745
118
+ private const uint EafDivider = EafMultiplier * 4 ; // 11,758,980
119
+
113
120
private const ulong TicksPer6Hours = TicksPerHour * 6 ;
114
- private const int March1BasedDayOfNewYear = 306 ; // Days between March 1 and January 1
121
+ private const int March1BasedDayOfNewYear = 306 ; // Days between March 1 and January 1
115
122
116
123
private static readonly uint [ ] s_daysToMonth365 = {
117
124
0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 , 365 } ;
@@ -1347,13 +1354,13 @@ public DateTime Date
1347
1354
// Cassio Neri, Lorenz Schneiderhttps - Euclidean Affine Functions and Applications to Calendar Algorithms - 2021
1348
1355
internal void GetDate ( out int year , out int month , out int day )
1349
1356
{
1350
- // y400 = number of whole 400 -year periods since 3/1/0000
1351
- // r1 = day number within 400 -year period
1352
- ( uint y400 , uint r1 ) = Math . DivRem ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 , DaysPer400Years ) ;
1353
- ulong u2 = ( ulong ) Math . BigMul ( 2939745 , ( int ) r1 | 3 ) ;
1354
- ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / 11758980 ) ;
1357
+ // y100 = number of whole 100 -year periods since 3/1/0000
1358
+ // r1 = ( day number within 100 -year period) * 4
1359
+ ( uint y100 , uint r1 ) = Math . DivRem ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 , DaysPer400Years ) ;
1360
+ ulong u2 = ( ulong ) Math . BigMul ( ( int ) EafMultiplier , ( int ) r1 | 3 ) ;
1361
+ ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / EafDivider ) ;
1355
1362
int n3 = 2141 * daySinceMarch1 + 197913 ;
1356
- year = ( int ) ( 100 * y400 + ( uint ) ( u2 >> 32 ) ) ;
1363
+ year = ( int ) ( 100 * y100 + ( uint ) ( u2 >> 32 ) ) ;
1357
1364
// compute month and day
1358
1365
month = ( ushort ) ( n3 >> 16 ) ;
1359
1366
day = ( ushort ) n3 / 2141 + 1 ;
@@ -1410,10 +1417,10 @@ public int Day
1410
1417
{
1411
1418
get
1412
1419
{
1413
- // r1 = day number within 400 -year period
1420
+ // r1 = ( day number within 100 -year period) * 4
1414
1421
uint r1 = ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 ) % DaysPer400Years ;
1415
- ulong u2 = ( ulong ) Math . BigMul ( 2939745 , ( int ) r1 | 3 ) ;
1416
- ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / 11758980 ) ;
1422
+ ulong u2 = ( ulong ) Math . BigMul ( ( int ) EafMultiplier , ( int ) r1 | 3 ) ;
1423
+ ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / EafDivider ) ;
1417
1424
int n3 = 2141 * daySinceMarch1 + 197913 ;
1418
1425
// Return 1-based day-of-month
1419
1426
return ( ushort ) n3 / 2141 + 1 ;
@@ -1430,22 +1437,8 @@ public int Day
1430
1437
// Returns the day-of-year part of this DateTime. The returned value
1431
1438
// is an integer between 1 and 366.
1432
1439
//
1433
- public int DayOfYear
1434
- {
1435
- get
1436
- {
1437
- // y400 = number of whole 400-year periods since 3/1/0000
1438
- // r1 = day number within 400-year period
1439
- ( uint y400 , uint r1 ) = Math . DivRem ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 , DaysPer400Years ) ;
1440
- ulong u2 = ( ulong ) Math . BigMul ( 2939745 , ( int ) r1 | 3 ) ;
1441
- ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / 11758980 ) ;
1442
-
1443
- int year = ( int ) ( 100 * y400 + ( uint ) ( u2 >> 32 ) ) + ( daySinceMarch1 >= March1BasedDayOfNewYear ? 1 : 0 ) ;
1444
- return daySinceMarch1 >= March1BasedDayOfNewYear // DatePartDayOfYear case
1445
- ? daySinceMarch1 - March1BasedDayOfNewYear + 1 // rollover December 31
1446
- : daySinceMarch1 + ( 366 - March1BasedDayOfNewYear ) + ( IsLeapYear ( year ) ? 1 : 0 ) ;
1447
- }
1448
- }
1440
+ public int DayOfYear =>
1441
+ 1 + ( int ) ( ( ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) % ( uint ) DaysPer400Years ) | 3U ) * EafMultiplier / EafDivider ) ;
1449
1442
1450
1443
// Returns the hash code for this DateTime.
1451
1444
//
@@ -1501,10 +1494,10 @@ public int Month
1501
1494
{
1502
1495
get
1503
1496
{
1504
- // r1 = day number within 400 -year period
1497
+ // r1 = ( day number within 100 -year period) * 4
1505
1498
uint r1 = ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 ) % DaysPer400Years ;
1506
- ulong u2 = ( ulong ) Math . BigMul ( 2939745 , ( int ) r1 | 3 ) ;
1507
- ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / 11758980 ) ;
1499
+ ulong u2 = ( ulong ) Math . BigMul ( ( int ) EafMultiplier , ( int ) r1 | 3 ) ;
1500
+ ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / EafDivider ) ;
1508
1501
int n3 = 2141 * daySinceMarch1 + 197913 ;
1509
1502
return ( ushort ) ( n3 >> 16 ) - ( daySinceMarch1 >= March1BasedDayOfNewYear ? 12 : 0 ) ;
1510
1503
}
@@ -1560,13 +1553,10 @@ public int Year
1560
1553
{
1561
1554
get
1562
1555
{
1563
- // y400 = number of whole 400-year periods since 3/1/0000
1564
- // r1 = day number within 400-year period
1565
- ( uint y400 , uint r1 ) = Math . DivRem ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) + 1224 , DaysPer400Years ) ;
1566
- ulong u2 = ( ulong ) Math . BigMul ( 2939745 , ( int ) r1 | 3 ) ;
1567
- ushort daySinceMarch1 = ( ushort ) ( ( uint ) u2 / 11758980 ) ;
1568
-
1569
- return ( int ) ( 100 * y400 + ( uint ) ( u2 >> 32 ) ) + ( daySinceMarch1 >= March1BasedDayOfNewYear ? 1 : 0 ) ;
1556
+ // y100 = number of whole 100-year periods since 1/1/0001
1557
+ // r1 = (day number within 100-year period) * 4
1558
+ ( uint y100 , uint r1 ) = Math . DivRem ( ( ( uint ) ( UTicks / TicksPer6Hours ) | 3U ) , DaysPer400Years ) ;
1559
+ return 1 + ( int ) ( 100 * y100 + ( r1 | 3 ) / DaysPer4Years ) ;
1570
1560
}
1571
1561
}
1572
1562
0 commit comments