From 7230f747e7e456d217b1136bee729efe922896cf Mon Sep 17 00:00:00 2001 From: Jesse Gumm Date: Fri, 17 Jun 2016 17:11:29 -0500 Subject: [PATCH] Update readme, Ensure sort can crash with option --- README.markdown | 36 ++++++++++++++++++++++++++++++++++++ src/qdate.erl | 13 +++++++------ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index 6749887..b08e993 100644 --- a/README.markdown +++ b/README.markdown @@ -217,6 +217,42 @@ ok **Note 2:** These functions will properly compare times with different timezones (for example: `compare("12am CST",'==',"1am EST")` will properly return true) +### Sorting + +`qdate` also provides a convenience functions for sorting lists of dates/times: + + + `sort(List)` - Sort the list in ascending order of earliest to latest. + + `sort(Op, List)` - Sort the list where `Op` is one of the following: + + `'<'` or `'=<'` or `'<='` - Sort ascending + + `'>'` or `'>='` or `'=>'` - Sort descending + + `sort(Op, List, Opts)` - Sort the list according to the `Op`, with options provided in `Opts`. `Opts` is a proplist of the following options: + + `{non_dates, NonDates}` - Tells it how to handle non-dates. `NonDates` can be any of the following: + + `back` **(default)** - put any non-dates at the end (the back) of the list + + `front` - put any non-dates at the beginning of the list + + `crash` - if there are any non-dates, crash. + +Example: + +```erlang + 1> Dates = ["non date string", <<"garbage">>, + 1466200861, "2011-01-01", "7pm", + {{1999,6,21},{5,30,0}}, non_date_atom, {some_tuple,123}]. + 2> qdate:sort('>=', Dates, [{non_dates, front}]). + [<<"garbage">>,"non date string", + {some_tuple,123}, + non_date_atom,1466200861,"2011-01-01", + {{1999,6,21},{5,30,0}}, + "7pm"] +``` + +**Note 1:** This sorting is optimized to be much faster than using a home-grown +sort using the `compare` functions, as this normalizes the items in the list +before comparing (so it's only really comparing integers, which is quite fast). + +**Note 2:** This is one of the few qdate functions that don't have the "Date" +as the last argument. This follows the pattern in Erlang/OTP to put options as +the last argument (for example, `re:run/3`) + ### Timezone Functions + `set_timezone(Key, TZ)` - Set the timezone to TZ for the key `Key` diff --git a/src/qdate.erl b/src/qdate.erl index 7ff236a..acc5837 100644 --- a/src/qdate.erl +++ b/src/qdate.erl @@ -489,20 +489,22 @@ sort(List) -> sort('=<', List). sort(Op, List) -> - sort(Op, List, [{non_date, back}]). + sort(Op, List, [{non_dates, back}]). sort(Op, List, Opts) -> - WithNorm = add_sort_normalization(List), + NonDateOpt = proplists:get_value(non_dates, Opts, back), + WithNorm = add_sort_normalization(List, NonDateOpt), SortFun = make_sort_fun(Op, Opts), Sorted = lists:sort(SortFun, WithNorm), strip_sort_normalization(Sorted). %% Normalization pre-processes the dates (converting them to unixtimes for easy %% comparison, and also tags non-dates (dates that crashed during parsing) as such -add_sort_normalization(List) -> +add_sort_normalization(List, NonDateOpt) -> lists:map(fun(Date) -> Sortable = try to_unixtime(Date) - catch _:_ -> {non_date, Date} + catch _:_ when NonDateOpt=/=crash -> + {non_date, Date} end, {Sortable, Date} end, List). @@ -511,9 +513,8 @@ add_sort_normalization(List) -> strip_sort_normalization(List) -> [Date || {_, Date} <- List]. -make_sort_fun(Op, Opts) -> +make_sort_fun(Op, NonDateOpt) -> DateComp = sort_op_comp_fun(Op), - NonDateOpt = proplists:get_value(non_date, Opts, back), fun({{non_date, A}, _}, {{non_date, B},_}) -> DateComp(A,B);