4:- module(abbreviated_dates,
5[
6 parse/3, 7 parse/4, 8 parse/5, 9 parse/6, 10 single_day/7 11]). 12
13:- [library(dcg/basics)]. 14:- use_module(library(date_time)). 15:- use_module(facts/languages). 16:- use_module(facts/country_language). 17:- use_module(facts/country_date_endianness).
27parse(Context, Expression, Dates) :-
28 parse(Context, Expression, Dates, _, _, _).
29
30parse(Context, Expression, Dates, Syntax) :-
31 parse(Context, Expression, Dates, Syntax, _, _).
32
33parse(Context, Expression, Dates, Syntax, Language) :-
34 parse(Context, Expression, Dates, Syntax, Language, _).
35
36parse(Context, Expression, Dates, Syntax, Language, Country) :-
37 atom_codes(Expression, Codes), phrase(multiple_days([Context], Dates, Language, Syntax, Country), Codes).
38
42multiple_days(_, [], _, [], _) --> [].
43multiple_days([LastKnownDate|Other], [SingleDay|MultipleDays], Language, [S1|S2], Country) -->
44 single_day([LastKnownDate|Other], SingleDay, Language, S1, Country),
45 (" - " | eos),
46 multiple_days([SingleDay, LastKnownDate|Other], MultipleDays, Language, S2, Country).
47
49
51single_day([Context|_], date(Year,MonthNumber,Day), Language, Syntax, _) -->
52 string_without(",", WeekDay), ",", b, date_number(Day), b, string(Month),
53 {
54 factor_month(Month, implicit, Language, MonthNumber, MonthFormat),
55 factor_week_day(WeekDay, WeekDayNumber, Language, WeekDaySyntax),
56 possible_year(Context, Year),
57 week_dayn(date(Year,MonthNumber,Day), WeekDayNumber),
58 date_compare(date(Year,MonthNumber,Day), >=, Context),
59 atomic_list_concat([WeekDaySyntax, ', %d ', MonthFormat], Syntax)
60 }.
61
63single_day([Context|_], date(Year,MonthNumber,Day), Language, Syntax, _) -->
64 string_without(",", WeekDay), ",", b, date_number(Day), b, string(Month), ".",
65 {
66 factor_month(Month, explicit, Language, MonthNumber, MonthFormat),
67 factor_week_day(WeekDay, WeekDayNumber, Language, WeekDaySyntax),
68 possible_year(Context, Year),
69 week_dayn(date(Year,MonthNumber,Day), WeekDayNumber),
70 date_compare(date(Year,MonthNumber,Day), >=, Context),
71 atomic_list_concat([WeekDaySyntax, ', %d ', MonthFormat], Syntax)
72 }.
73
75
77single_day([Context|_], Date, Language, Syntax, Country) --> 78 string(WeekDayCodes), ".", b, date_number(First), separator, date_number(Second),
79 {
80 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
81 atomic_list_concat([WeekDaySyntax, DayMonthSyntax], ' ', Syntax)
82 }.
84single_day([Context|_], Date, Language, Syntax, Country) -->
85 string(WeekDayCodes), ",", b, date_number(First), separator, date_number(Second),
86 {
87 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
88 atomic_list_concat([WeekDaySyntax, DayMonthSyntax], ' ', Syntax)
89 }.
91single_day([Context|_], Date, Language, Syntax, Country) -->
92 string(WeekDayCodes), b, date_number(First), separator, date_number(Second),
93 {
94 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
95 atomic_list_concat([WeekDaySyntax, DayMonthSyntax], ' ', Syntax)
96 }.
98single_day([Context|_], Date, Language, Syntax, Country) -->
99 string(WeekDayCodes), ".", ",", b, integer(First), "-", integer(Second),
100 {
101 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
102 atomic_list_concat([WeekDaySyntax, '., ', DayMonthSyntax], Syntax)
103 }.
104
106single_day([Context|_], Date, Language, Syntax, Country) -->
107 string(WeekDayCodes), ".", ",", b, integer(First), ".", integer(Second), ".",
108 {
109 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
110 atomic_list_concat([WeekDaySyntax, '., ', DayMonthSyntax], Syntax)
111 }.
112
114single_day([Context|_], Date, Language, Syntax, Country) -->
115 string(WeekDayCodes), ".", ",", b, integer(First), ".", integer(Second),
116 {
117 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
118 atomic_list_concat([WeekDaySyntax, '., ', DayMonthSyntax], Syntax)
119 }.
120
122single_day([Context|_], Date, Language, Syntax, Country) -->
123 string(WeekDayCodes), ".", ",", b, integer(First), ".", b, integer(Second),
124 {
125 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
126 atomic_list_concat([WeekDaySyntax, '., ', DayMonthSyntax], Syntax)
127 }.
128
130single_day([Context|_], Date, Language, Syntax, Country) -->
131 string(WeekDayCodes), ".", ",", b, integer(First), "/", integer(Second),
132 {
133 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
134 atomic_list_concat([WeekDaySyntax, '., ', DayMonthSyntax], Syntax)
135 }.
136
138
140single_day([Context|_], Date, Language, Syntax, _) -->
141 string(WeekDayCodes), ",", b, month_day(Day),
142 {
143 factor_week_day(WeekDayCodes, WeekDayNumber, Language, WeekDaySyntax),
144 possible_day(Context, Day, Date),
145 week_dayn(Date, WeekDayNumber),
146 atomic_list_concat([WeekDaySyntax, ' %d'], Syntax)
147 }.
148
150
152single_day([Context|_], Date, Language, Syntax, Country) -->
153 date_number(First), separator, date_number(Second), ",", b, string(WeekDayCodes),
154 {
155 solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country),
156 atomic_list_concat([DayMonthSyntax, WeekDaySyntax], ' ', Syntax)
157 }.
158
160
162single_day([Context|_], Date, Language, Syntax, _) -->
163 month_day(Day), b, string(Month),
164 {factor_month_day(Context, Day, Month, implicit, Date, Language, MonthFormat),atom_concat('%d ', MonthFormat, Syntax)}.
165
167single_day([Context|_], Date, Language, Syntax, _) --> 168 month_day(Day), b, string(Month), ".",
169 {factor_month_day(Context, Day, Month, explicit, Date, Language, MonthFormat),atom_concat('%d ', MonthFormat, Syntax)}.
170
172single_day([Context|_], Date, Language, Syntax, _) --> 173 month_day(Day), ".", b, string(Month),
174 {factor_month_day(Context, Day, Month, implicit, Date, Language, MonthFormat),atom_concat('%d ', MonthFormat, Syntax)}.
175
177single_day([Context|_], Date, Language, Syntax, _) --> 178 month_day(Day), ".", b, string(Month), ".",
179 {factor_month_day(Context, Day, Month, implicit, Date, Language, MonthFormat),atom_concat('%d ', MonthFormat, Syntax)}.
180
182
184single_day([Context|_], Date, Language, Syntax, _) -->
185 string(Month), b, month_day(Day),
186 {factor_month_day(Context, Day, Month, implicit, Date, Language, MonthFormat), atom_concat(MonthFormat,' %d', Syntax)}.
187
189single_day([Context|_], Date, Language, Syntax, _) -->
190 string(Month), ".", b, month_day(Day),
191 {factor_month_day(Context, Day, Month, explicit, Date, Language, MonthFormat), atom_concat(MonthFormat,' %d', Syntax)}.
192
194
196single_day([Context|_], Date, Language, '%d', _) -->
197 month_day(D),
198 {future_date(Context, D, Date), language(Language)}.
199
201single_day([Context|_], Date, Language, '%d', _) -->
202 month_day(D), ".",
203 {future_date(Context, D, Date), language(Language)}.
204
206
208single_day([Context|_], Date, Language, Syntax, _) -->
209 nonblanks(Codes),
210 {atom_codes(Adverb, Codes), adverb(Language, Adverb, Context, Date, Syntax)}.
211
212
213month_day(Day) --> integer(Day), {between(1, 31, Day)}.
214date_number(N) --> integer(N).
215date_number(N) --> integer(N), ".".
216separator --> "-"|"."|"/"|" ".
217b --> white.
218
222
223solve_date_numbers(Context, WeekDayCodes, First, Second, Date, Language, DayMonthSyntax, WeekDaySyntax, Country):-
224 factor_week_day(WeekDayCodes, WeekDayNumber, Language, WeekDaySyntax),
225 possible_year(Context, Year),
226 factor_country_endianness(Language, First, Second, date(Year,Month,Day), DayMonthSyntax, Country),
227 week_dayn(date(Year,Month,Day), WeekDayNumber),
228 Date = date(Year,Month,Day).
229
230factor_month_day(Context, Day, Month, Style, date(Year,MonthNumber,Day), Language, MonthFormat):-
231 factor_month(Month, Style, Language, MonthNumber, MonthFormat),
232 possible_year(Context, Year),
233 date_compare(date(Year,MonthNumber,Day), >=, Context).
234
235factor_week_day(InputCodes, WeekDayNumber, Language, Format):-
236 atom_codes(InputAtom, InputCodes),
237 downcase_atom(InputAtom, LowerCaseInputAtom),
238 week_day_name(Language, WeekDayNumber, WeekDayName),
239 downcase_atom(WeekDayName, LowerCaseWeekDayName),
240 abbreviation(LowerCaseWeekDayName, LowerCaseInputAtom, IsAbbreviated),
241 (IsAbbreviated -> Format = '%a'; Format = '%A').
242
243factor_month(Month, Style, Language, MonthNumber, Syntax):-
244 month_name(Language, MonthNumber, MonthName),
245 abbreviation(MonthName, Abbreviation, IsAbbreviated),
246 atom_codes(MaybeAbbreviation, Month),
247 capitalize_sentence(MaybeAbbreviation, Abbreviation),
248 (IsAbbreviated-> MonthFormat = '%b'; MonthFormat = '%B'),
249 (IsAbbreviated, Style = explicit -> Suffix = '.'; Suffix = ''),
250 atomic_list_concat([MonthFormat, Suffix], Syntax).
251
252factor_country_endianness(Language, First, Second, date(Year,Month,Day), Syntax, Country):-
253 top_endianness(Country, Endianness), 254 top_country_language(Country, Language), 255 day_month_order(Endianness, First, Second, Day, Month, Syntax),
256 valid(date(Year,Month,Day)).
257
258day_month_order(little, Day, Month, Day, Month, '%d %m'). 259day_month_order(middle, Month, Day, Day, Month, '%m %d'). 260day_month_order(big, Month, Day, Day, Month, '%m %d'). 261
262valid(date(Year,Month,Day)):- Month =< 12, date_month_days(Month,Year,MD), Day =< MD.
263
264possible_year(Context, Year):-
265 date_extract(Context, years(Y)),
266 Max is Y + 6,
267 between(Y, Max, Year).
268
269possible_day(Context, Day, Date):-
270 date_extract(Context, years(Year)),
271 date_extract(Context, months(M)),
272 Max is M + 24,
273 between(M, Max, Month),
274 future_date(date(Year,Month,Day), Date).
275
277abbreviation(Atom, Abbreviation, IsAbbreviated):-
278 abbreviation_all_letters(Atom, Abbreviation, IsAbbreviated);
279 abbreviation_consonant(Atom, Abbreviation, IsAbbreviated).
280
281abbreviation_all_letters(Atom, Abbreviation, IsAbbreviated):-
282 order_by([desc(L)], (sub_atom(Atom, 0, _, After, Abbreviation), atom_length(Abbreviation,L))),
283 L > 0,
284 (After = 0 -> IsAbbreviated = false; IsAbbreviated = true).
285
286abbreviation_consonant(Atom, Abbreviation, IsAbbreviated):-
287 atom_remove_vowels(Atom, AtomConsonants),
288 abbreviation_all_letters(AtomConsonants, Abbreviation, IsAbbreviated).
289
290atom_remove_vowels(Atom, AtomConsonants):-
291 atom_chars(Atom, Chars),
292 subtract(Chars, [a, Ä
, e, Ä, i, o, ó, u], Consonants),
293 remove_duplicates(Consonants, Uniques),
294 atom_chars(AtomConsonants, Uniques).
295
296future_date(date(Y, M, D), Day, date(YY,MM,DD)):-
297 date_month_days(M,Y,MD),
298 D =< Day, Day =< MD, 299 !,
300 future_date(date(Y,M,Day), date(YY,MM,DD)).
301future_date(date(Y, M, D), Day, date(YY,MM,DD)):-
302 date_month_days(M,Y,MD),
303 (Day =< D; MD =< Day), 304 !,
305 M2 is M + 1,
306 future_date(date(Y,M2,Day), date(YY,MM,DD)).
307future_date(date(Y, M, D), date(YY,MM,DD)):-
308 M > 12,
309 !,
310 M2 is M - 12,
311 Y2 is Y + 1,
312 future_date(date(Y2,M2,D), date(YY,MM,DD)).
313future_date(date(Y,M,D), date(Y,M,D)).
314
315date_month_days(0,_,31).
316date_month_days(1,_,31).
317date_month_days(2,Y,29) :- date_leap_year(Y), !.
318date_month_days(2,_,28).
319date_month_days(3,_,31).
320date_month_days(4,_,30).
321date_month_days(5,_,31).
322date_month_days(6,_,30).
323date_month_days(7,_,31).
324date_month_days(8,_,31).
325date_month_days(9,_,30).
326date_month_days(10,_,31).
327date_month_days(11,_,30).
328date_month_days(12,_,31).
329date_month_days(13,_,31).
330
331date_leap_year(Y) :-
332 ( ( 0 =:= Y mod 100, 0 =:= Y mod 400 ) ;
333 ( 0 =\= Y mod 100, 0 =:= Y mod 4 ) ).
334
338remove_duplicates(List, Uniques):- remove_duplicates(List, Uniques, []).
339remove_duplicates([], [], _).
340remove_duplicates([Head|Tail], Result, Seen) :-
341 ( member(Head, Seen)
342 -> (Result = Uniques, NewSeen = Seen)
343 ; (Result = [Head|Uniques], NewSeen = [Head])
344 ),
345 remove_duplicates(Tail, Uniques, NewSeen).
346
347capitalize_sentence(LowerCase, UpperCase):-
348 atom_chars(LowerCase, [Lower|Tail]),
349 char_type(Lower, to_lower(Upper)),
350 atom_chars(UpperCase, [Upper|Tail])