Last active
December 15, 2015 00:29
-
-
Save mndrix/5173377 to your computer and use it in GitHub Desktop.
Modified Julian Day calculations in Prolog. This experiment might form the basis of a date library someday.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- module(julian, [ date_name/2 | |
, day_of_week/2 | |
, gregorian/3 | |
]). | |
:- use_module(library(clpfd)). | |
%% gregorian(?Year, ?Month, ?Day) is det. | |
% | |
% True if Year, Month and Day form a valid date in the Gregorian | |
% calendar. For example, one could iterate all leap years with | |
% | |
% == | |
% gregorian(Y, 2, 29), Y #> 1776, indomain(Y). | |
% == | |
gregorian(Y,M,D) :- | |
Y in -4713..3267, | |
M in 1..12, | |
( (D in 1..28) | |
#\/ (M #\= 2 #/\ D in 29..30) | |
#\/ (M in 1 \/ 3 \/ 5 \/ 7 \/ 8 \/ 10 \/ 12 #/\ D #= 31) | |
#\/ (M #= 2 #/\ D #= 29 #/\ Y mod 400 #= 0) | |
#\/ (M #= 2 #/\ D #= 29 #/\ Y mod 4 #= 0 #/\ Y mod 100 #\= 0) | |
). | |
%% mjd(?MJD:integer) is det. | |
% | |
% True if MJD is a valid modified Julian day number. | |
mjd(MJD) :- | |
MJD in -2400328 .. 514671. | |
%% day_of_week(?Datetime, ?DayOfWeek:atom) is det. | |
% | |
% True Datetime occurs on the given day of the week. | |
day_of_week(datetime(MJD, _), DayOfWeek) :- | |
(MJD+2) mod 7 #= DayNumber, | |
day_name(DayNumber, DayOfWeek). | |
%% day_name(?Number:integer, ?DayOfWeek:atom) | |
% | |
% True if Number is the ISO number for DayOfWeek. | |
% 0 is Monday, 6 is Sunday. | |
day_name(0, monday). | |
day_name(1, tuesday). | |
day_name(2, wednesday). | |
day_name(3, thursday). | |
day_name(4, friday). | |
day_name(5, saturday). | |
day_name(6, sunday). | |
date_name(datetime(MJD,_Nano), gregorian(Year, Month, Day)) :- | |
gregorian(Year, Month, Day), | |
mjd(MJD), | |
!, | |
Y = 4716, | |
V = 3, | |
J = 1401, | |
U = 5, | |
M = 2, | |
S = 153, | |
N = 12, | |
W = 2, | |
R = 4, | |
B = 274277, | |
P = 1461, | |
C = -38, | |
F0 #= JD + J, | |
F1 #= F0 + (((4 * JD + B)/146097) * 3)/4 + C, | |
E #= R * F1 + V, | |
G #= mod(E, P)/R, | |
H #= U * G + W, | |
Day #= (mod(H, S))/U + 1, | |
Month #= mod(H/S + M, N) + 1, | |
Year #= E/P - Y + (N + M - Month)/N, | |
MJD #= JD - 2400001, | |
( ground(MJD) -> | |
labeling([leftmost, up, step], [Year, Month, Day]) | |
; ground(Year), ground(Month), ground(Day) -> | |
labeling([leftmost, up, step], [MJD]) | |
; true | |
). | |
date_name(Datetime, july_fourth) :- | |
Y #>= 1776, | |
date_name(Datetime, gregorian(Y,7,4)). | |
:- begin_tests(acceptable_gregorian_dates). | |
test(march_16_2013) :- | |
gregorian(2013,3,16). | |
% leap year rules | |
test(1900, [fail]) :- | |
gregorian(1900,2,29). | |
test(2000) :- | |
gregorian(2012,2,29). | |
test(2012) :- | |
gregorian(2012,2,29). | |
test(2013, [fail]) :- | |
gregorian(2013,2,29). | |
test(2014, [fail]) :- | |
gregorian(2014,2,29). | |
test(2016) :- | |
gregorian(2016,2,29). | |
:- end_tests(acceptable_gregorian_dates). | |
:- begin_tests(gregorian_conversion). | |
test(march_16_2013) :- | |
date_name(datetime(56367, _), gregorian(2013,3,16)). | |
test(unix_epoch) :- | |
date_name(datetime(40587, _), gregorian(1970,1,1)). | |
:- end_tests(gregorian_conversion). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Find Fourth of July on a Sunday during Dwight Eisenhower's presidency: