japerk / elib (http://edoc.streamhacker.com/elib/)

Extra erlang library modules.

Clone this repository (size: 84.4 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/japerk/elib/
commit 16: 98aeaddf15d6
parent 15: 7d7ea72e8971
branch: timerecurrence
Improve rrule module: * Sprinkle some edoc and comments * Explicitely define which function to export * Clean up unused functions * Fix warning messages during compilation * Remove unused parameter ListRanges in satisfy/3 * Add a new function in_range/2 which check if a range match all the constraints defined by some given rules
Bruno Mahe
9 months ago

Changed (Δ8 bytes):

raw changeset »

src/rrule.erl (45 lines added, 39 lines removed)

Up to file-list src/rrule.erl:

1
%% @doc Datetime conversion functions to convert to and from datetime tuples
2
%% for standard formats.
1
%% @doc rrule provides a set of function to related to time recurrence.
2
%% 
3
3
%%
4
%% @type datetime() = {date(), time()}
5
%% @type date() = {Year::integer(), Month::integer(), Day::integer()}
6
%% @type time() = {Hour::integer(), Min::integer(), Sec::integer()}
7
%% @type daterange() = {date(), date()}
4
%% @type constraint() = {atom(), term()}
5
%% @type rule() = tuple(list(constraint()), DurationInHour::integer())
6
%% @type rules() = list(rule())
8
7
%%
9
8
%% @author Bruno Mahe
10
9
-module(rrule).
11
10
12
11
13
-compile(export_all).
12
-export([in_range/2]).
13
-export([satisfy/3]).
14
14
15
15
16
%% @doc Convert day of the week into an integer usable by the calendar module
17
%% @see calendar:day_of_the_week/1
18
%% @see calendar:day_of_the_week/3
19
%% @spec day_of_the_week(atom()) -> integer()
16
20
day_of_the_week(monday)    -> 1;
17
21
day_of_the_week(tuesday)   -> 2;
18
22
day_of_the_week(wednesday) -> 3;
@@ -22,6 +26,8 @@ day_of_the_week(saturday) -> 6;
22
26
day_of_the_week(sunday)    -> 7.
23
27
24
28
29
%% @doc Convert month name into an integer 
30
%% @spec month(atom()) -> integer()
25
31
month(january)   ->  1;
26
32
month(february)  ->  2;
27
33
month(march)     ->  3;
@@ -37,14 +43,6 @@ month(december) -> 11.
37
43
38
44
39
45
40
new() -> [].
41
42
%				Constraints                                Duration
43
%Rule => {[{month, june}, {weekday, monday}, {hour, 8}], 8}) 
44
%Rules => [Rule]
45
46
47
add_rule(Rules, Rule) -> [Rule|Rules].
48
46
49
47
50
48
find_month_in_range(Month, BeginningRangeDateTime, EndRangeDateTime) ->
@@ -139,10 +137,9 @@ find_day_in_range(Day, BeginningRangeDat
139
137
find_day_in_range(Day, BeginningRangeDateTime, EndRangeDateTime, ListDays) ->
140
138
	
141
139
		{BeginningRangeDate, BeginningRangeTime} = BeginningRangeDateTime,
142
		{BeginRangeYear, BeginRangeMonth, BeginRangeDay} = BeginningRangeDate,
143
140
144
		{EndRangeDate, EndRangeTime} = EndRangeDateTime,
145
		{EndRangeYear, EndRangeMonth, EndRangeDay} = EndRangeDate,
141
		{EndRangeDate, _} = EndRangeDateTime,
142
		{_, _, EndRangeDay} = EndRangeDate,
146
143
147
144
		FoundListDays = case EndRangeDay of
148
145
										Day -> 	BeginSubRange = case EndRangeDate of
@@ -165,18 +162,19 @@ find_day_in_range(Day, BeginningRangeDat
165
162
		end.
166
163
167
164
165
%% @doc Returns a list or ranges which satisfy a list of constraints 
166
%% @spec satisfy(rule(), datetime(), datetime()) -> list({datetime(), datetime())
167
satisfy({[], _}, When, Until) -> {When, Until};
168
168
169
satisfy({[], _}, _, _, ListRanges) -> ListRanges;
170
171
satisfy({[{month, Month}| Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_atom(Month) ->
169
satisfy({[{month, Month}| Constraints], Duration}, BeginRange, EndRange) when is_atom(Month) ->
172
170
		ConstraintMonth = month(Month),
173
171
174
		satisfy({[{month, ConstraintMonth}|Constraints], Duration}, BeginRange, EndRange, ListRanges);
172
		satisfy({[{month, ConstraintMonth}|Constraints], Duration}, BeginRange, EndRange);
175
173
176
satisfy({[{month, Month}|Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_integer(Month), Month > 0, Month < 13 ->
174
satisfy({[{month, Month}|Constraints], Duration}, BeginRange, EndRange) when is_integer(Month), Month > 0, Month < 13 ->
177
175
178
176
		CheckRanges = fun({BeginSubRange, EndSubRange}) ->
179
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange, {BeginSubRange, EndSubRange})
177
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange)
180
178
							end,
181
179
182
180
		lists:map(
@@ -184,10 +182,10 @@ satisfy({[{month, Month}|Constraints], D
184
182
						find_month_in_range(Month, BeginRange, EndRange)
185
183
					);
186
184
187
satisfy({[{day, Day}|Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_integer(Day), Day > 0, Day < 32 ->
185
satisfy({[{day, Day}|Constraints], Duration}, BeginRange, EndRange) when is_integer(Day), Day > 0, Day < 32 ->
188
186
189
187
		CheckRanges = fun({BeginSubRange, EndSubRange}) ->
190
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange, {BeginSubRange, EndSubRange})
188
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange)
191
189
							end,
192
190
193
191
		lists:map(
@@ -195,7 +193,7 @@ satisfy({[{day, Day}|Constraints], Durat
195
193
						find_day_in_range(Day, BeginRange, EndRange)
196
194
					);
197
195
198
satisfy({[{weekday, WeekDay}|Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_atom(WeekDay) ->
196
satisfy({[{weekday, WeekDay}|Constraints], Duration}, BeginRange, EndRange) when is_atom(WeekDay) ->
199
197
	
200
198
		{BeginRangeDate, BeginRangeTime} = BeginRange,
201
199
	
@@ -218,7 +216,7 @@ satisfy({[{weekday, WeekDay}|Constraints
218
216
											),
219
217
220
218
		CheckRanges = fun({BeginSubRange, EndSubRange}) ->
221
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange, {BeginSubRange, EndSubRange})
219
									satisfy({Constraints, Duration}, BeginSubRange, EndSubRange)
222
220
							end,
223
221
224
222
		lists:map(
@@ -228,9 +226,9 @@ satisfy({[{weekday, WeekDay}|Constraints
228
226
229
227
230
228
231
satisfy({[{time, Hour}|Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_integer(Hour), Hour > 0, Hour < 25 ->
232
						satisfy({[{hour, {Hour, 0}}|Constraints], Duration}, BeginRange, EndRange, ListRanges);
233
satisfy({[{time, {Hour, Minutes}}|Constraints], Duration}, BeginRange, EndRange, ListRanges) when is_integer(Hour), Hour > 0, Hour < 25 ->
229
satisfy({[{time, Hour}|Constraints], Duration}, BeginRange, EndRange) when is_integer(Hour), Hour > 0, Hour < 25 ->
230
						satisfy({[{time, {Hour, 0}}|Constraints], Duration}, BeginRange, EndRange);
231
satisfy({[{time, {Hour, Minutes}}|Constraints], Duration}, BeginRange, EndRange) when is_integer(Hour), Hour > 0, Hour < 25 ->
234
232
235
233
		{BeginRangeDate, BeginRangeTime} = BeginRange,
236
234
		{BeginRangeHour, BeginRangeMinute, BeginRangeSeconds} = BeginRangeTime,
@@ -261,8 +259,6 @@ satisfy({[{time, {Hour, Minutes}}|Constr
261
259
																
262
260
																
263
261
																		DatePlusDuration = datetime:time_diff({Date, {Hour, Minutes, 0}}, Duration*3600),
264
																		{DDDate, DDTime} = DatePlusDuration,
265
																		{DDHour, DDMinute, DDSeconds} = DDTime,
266
262
267
263
																		DatePlusDurationInSec = calendar:datetime_to_gregorian_seconds(DatePlusDuration),
268
264
																		EndRangeInSec = calendar:datetime_to_gregorian_seconds(EndRange),
@@ -284,7 +280,7 @@ satisfy({[{time, {Hour, Minutes}}|Constr
284
280
		CheckRanges = fun({BeginSubRange, EndSubRange}) ->
285
281
									case {BeginSubRange, EndSubRange} of
286
282
												{none, none} -> [];
287
												_ -> satisfy({Constraints, Duration}, BeginSubRange, EndSubRange, {BeginSubRange, EndSubRange})
283
												_ -> satisfy({Constraints, Duration}, BeginSubRange, EndSubRange)
288
284
									end
289
285
							end,
290
286
@@ -298,15 +294,25 @@ satisfy({[{time, {Hour, Minutes}}|Constr
298
294
299
295
300
296
301
%in_range({Constraints, Duration} = Rule, {Date, Time})  ->
302
			
303
%;
297
%% @doc Check if a range match the constraints defined by some rules
298
%% @spec in_range(rules(), {datetime(), datetime()}) -> bool()
299
in_range(Rules, {When, Until}) when is_list(Rules) -> lists:any(fun(Rule) -> in_range(Rule, {When, Until})end, Rules);
304
300
305
in_range(Rules, {Date, Time} = DateTime) when is_list(Rules) -> lists:any(fun(Rule) -> in_range(Rule, DateTime)end, Rules).
301
in_range(Rule, {When, Until}) when is_tuple(Rule) -> 
306
302
307
303
304
		Candidates = lists:flatten(
305
							satisfy(Rule, When, Until)
306
						),
307
						
308
						
309
		lists:any(
310
						fun({Begin, End}) ->
311
							datetime:range_in_range({When, Until}, {Begin, End})
312
						end,
313
						Candidates
308
314
315
					).
309
316
310
317
311
318
312
%in_range(Rules, {When, Until}) -> true | false.