@@ -457,6 +457,86 @@ static const REBI64 DAYS_OF_JAN_1ST_1970 = 719468; // number of days for 1st Jan
457
457
}
458
458
459
459
460
+ /***********************************************************************
461
+ **
462
+ */ REBDEC Gregorian_To_Julian_Date (REBDAT date , REB_TIMEF time )
463
+ /*
464
+ ** Given a Gregorian date and time, return Julian date
465
+ ** https://www.typecalendar.com/julian-date
466
+ ** https://pdc.ro.nu/jd-code.html
467
+ **
468
+ ***********************************************************************/
469
+ {
470
+ long jd ;
471
+ long d = date .date .day - 1 ;
472
+ long m = date .date .month - 1 ;
473
+ long y = date .date .year ;
474
+
475
+ //printf("%li-%li-%li %i:%i:%i\n", d, m, y, time.h, time.m, time.s);
476
+ if (time .h <= 12 ) {
477
+ d -- ;
478
+ time .h += 12 ;
479
+ } else {
480
+ time .h -= 12 ;
481
+ }
482
+ date = Normalize_Date (d ,m ,y ,0 );
483
+ d = date .date .day - 1 ;
484
+ m = date .date .month ;
485
+ y = date .date .year ;
486
+ //printf("%li-%li-%li %i:%i:%i\n", d, m, y, time.h, time.m, time.s);
487
+
488
+ y += 8000 ;
489
+ if (m < 3 ) { y -- ; m += 12 ; }
490
+ jd = (y * 365 ) + (y /4 ) - (y /100 ) + (y /400 ) - 1200820 ;
491
+ jd += (m * 153 + 3 )/5 - 92 ;
492
+ jd += d ;
493
+
494
+ return (REBDEC )jd + ((double )time .h / 24.0 + (double )time .m / 1440.0 + (double )time .s / 86400.0 );
495
+ }
496
+
497
+ /***********************************************************************
498
+ **
499
+ */ void Julian_To_Gregorian_Date (REBDEC julian , REBINT * day , REBINT * month , REBINT * year , REBI64 * secs )
500
+ /*
501
+ ** Converts a Julian date to a Gregorian date and time.
502
+ ** https://www.typecalendar.com/julian-date
503
+ ** NOTE: month and day are 1-based!
504
+ **
505
+ ***********************************************************************/
506
+ {
507
+ REBINT z , w , x , a , b , c , d , e , f ;
508
+ double fp , ip ;
509
+ REBI64 h , m , s ;
510
+
511
+ fp = modf (julian , & ip ); // The fractional part
512
+
513
+ z = (REBINT )ip ; // The integral part of the Julian day
514
+ w = (z - 1867216.25 ) / 36524.25 ; // The value used in the calculation to determine the leap years. It represents the number of leap years since 4713 BC
515
+ x = w / 4 ; // The number of 4-year cycles (leap year groups) that have passed since the year 4713 BC.
516
+ a = z + 1 + w - x ; // The adjusted Julian day number, taking into account leap years.
517
+ b = a + 1524 ; // The Julian day number shifted by 122.1 to provide a suitable starting point for subsequent calculations.
518
+ c = (b - 122.1 ) / 365.25 ; // The estimated year of the Gregorian calendar.
519
+ d = 365.25 * c ; // The number of days that have passed in the year, excluding the current month.
520
+ e = (b - d ) / 30.6001 ; // The month number.
521
+ f = 30.6001 * e ; // The number of days that have passed in the current month, excluding the current day.
522
+
523
+ * day = b - d - f + fp ;
524
+ * month = (e < 14 ) ? e - 1 : e - 13 ;
525
+ * year = (* month > 2 ) ? c - 4716 : c - 4715 ;
526
+
527
+
528
+ fp *= 24 ;
529
+ h = (REBI64 )fp ;
530
+ fp = (fp - h ) * 60 ;
531
+ m = (REBI64 )fp ;
532
+ fp = (fp - m ) * 60 ;
533
+ s = (REBI64 )round (fp );
534
+
535
+ //printf("--- %i-%i-%i %lli:%lli:%lli\n", *day, *month, *year, h, m, s);
536
+
537
+ * secs = (h + 12 ) * HR_SEC + m * MIN_SEC + s * SEC_SEC ;
538
+ }
539
+
460
540
/***********************************************************************
461
541
**
462
542
*/ void Subtract_Date (REBVAL * d1 , REBVAL * d2 , REBVAL * result )
@@ -679,9 +759,17 @@ static const REBI64 DAYS_OF_JAN_1ST_1970 = 719468; // number of days for 1st Jan
679
759
num = Week_Day (date );
680
760
break ;
681
761
case SYM_YEARDAY :
682
- case SYM_JULIAN :
683
762
num = (REBINT )Julian_Date (date );
684
763
break ;
764
+ case SYM_JULIAN :
765
+ if (secs == NO_TIME ) {
766
+ time .h = 12 ; // Julian date is counted from noon
767
+ } else {
768
+ // Julian date result is in universal time!
769
+ Split_Time (secs - ((i64 )tz ) * ((i64 )ZONE_SECS * SEC_SEC ), & time );
770
+ }
771
+ SET_DECIMAL (val , Gregorian_To_Julian_Date (date , time ));
772
+ return PE_USE ;
685
773
case SYM_UTC :
686
774
* val = * data ;
687
775
VAL_ZONE (val ) = 0 ;
@@ -788,13 +876,18 @@ static const REBI64 DAYS_OF_JAN_1ST_1970 = 719468; // number of days for 1st Jan
788
876
VAL_ZONE (data ) = 0 ;
789
877
return PE_USE ;
790
878
case SYM_YEARDAY :
791
- case SYM_JULIAN :
792
879
if (!IS_INTEGER (val )) return PE_BAD_SET_TYPE ;
793
880
Date_Of_Days ( Days_Of_Jan_1st (year ) + n - 1 , & date );
794
881
day = date .date .day - 1 ;
795
882
month = date .date .month - 1 ;
796
883
year = date .date .year ;
797
884
break ;
885
+ case SYM_JULIAN :
886
+ if (!IS_DECIMAL (val )) return PE_BAD_SET_TYPE ;
887
+ Julian_To_Gregorian_Date (VAL_DECIMAL (val ), & day , & month , & year , & secs );
888
+ day -- ; month -- ; // The date/time normalization expects 0-based day and month
889
+ tz = 0 ; // no timezone
890
+ break ;
798
891
799
892
default :
800
893
return PE_BAD_SET ;
@@ -921,6 +1014,11 @@ static const REBI64 DAYS_OF_JAN_1ST_1970 = 719468; // number of days for 1st Jan
921
1014
Timestamp_To_Date (D_RET , VAL_INT64 (arg ));
922
1015
return R_RET ;
923
1016
}
1017
+ else if (IS_DECIMAL (arg )) {
1018
+ Julian_To_Gregorian_Date (VAL_DECIMAL (arg ), & day , & month , & year , & secs );
1019
+ day -- ; month -- ; // The date/time normalization expects 0-based day and month
1020
+ goto fixTime ;
1021
+ }
924
1022
// else if (IS_NONE(arg)) {
925
1023
// secs = nsec = day = month = year = tz = 0;
926
1024
// goto fixTime;
0 commit comments