-module(birl@duration). -compile(no_auto_import). -export([new/1, accurate_new/1, decompose/1, accurate_decompose/1, parse/1]). -export_type([duration/0, unit/0]). -type duration() :: {duration, integer()}. -type unit() :: milli_second | second | minute | hour | day | week | month | year. -spec new(list({integer(), unit()})) -> duration(). new(Values) -> _pipe = Values, _pipe@1 = gleam@list:fold( _pipe, 0, fun(Total, Current) -> {Amount, Unit} = Current, case Unit of milli_second -> Total + Amount; second -> Total + (Amount * 1000000); minute -> Total + (Amount * 60000000); hour -> Total + (Amount * 3600000000); day -> Total + (Amount * 86400000000); week -> Total + (Amount * 604800000000); month -> Total + (Amount * 2592000000000); year -> Total + (Amount * 31536000000000) end end ), {duration, _pipe@1}. -spec accurate_new(list({integer(), unit()})) -> duration(). accurate_new(Values) -> _pipe = Values, _pipe@1 = gleam@list:fold( _pipe, 0, fun(Total, Current) -> {Amount, Unit} = Current, case Unit of milli_second -> Total + Amount; second -> Total + (Amount * 1000000); minute -> Total + (Amount * 60000000); hour -> Total + (Amount * 3600000000); day -> Total + (Amount * 86400000000); week -> Total + (Amount * 604800000000); month -> Total + (Amount * 2629746000000); year -> Total + (Amount * 31556952000000) end end ), {duration, _pipe@1}. -spec decompose(duration()) -> list({integer(), unit()}). decompose(Duration) -> {duration, Value} = Duration, {Years, Remaining} = extract(Value, 31536000000000), {Months, Remaining@1} = extract(Remaining, 2592000000000), {Days, Remaining@2} = extract(Remaining@1, 86400000000), {Hours, Remaining@3} = extract(Remaining@2, 3600000000), {Minutes, Remaining@4} = extract(Remaining@3, 60000000), {Seconds, Remaining@5} = extract(Remaining@4, 1000000), _pipe = [{Years, year}, {Months, month}, {Days, day}, {Hours, hour}, {Minutes, minute}, {Seconds, second}, {Remaining@5, milli_second}], gleam@list:filter(_pipe, fun(Item) -> erlang:element(1, Item) > 0 end). -spec accurate_decompose(duration()) -> list({integer(), unit()}). accurate_decompose(Duration) -> {duration, Value} = Duration, {Years, Remaining} = extract(Value, 31556952000000), {Months, Remaining@1} = extract(Remaining, 2629746000000), {Days, Remaining@2} = extract(Remaining@1, 86400000000), {Hours, Remaining@3} = extract(Remaining@2, 3600000000), {Minutes, Remaining@4} = extract(Remaining@3, 60000000), {Seconds, Remaining@5} = extract(Remaining@4, 1000000), _pipe = [{Years, year}, {Months, month}, {Days, day}, {Hours, hour}, {Minutes, minute}, {Seconds, second}, {Remaining@5, milli_second}], gleam@list:filter(_pipe, fun(Item) -> erlang:element(1, Item) > 0 end). -spec parse(binary()) -> {ok, duration()} | {error, nil}. parse(Expression) -> {ok, Re@1} = case gleam@regex:from_string(<<"(\\d+)\\s*(\\w+)"/utf8>>) of {ok, Re} -> {ok, Re}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"birl/duration"/utf8>>, function => <<"parse"/utf8>>, line => 183}) end, {Accurate, Expression@2} = case gleam@string:starts_with( Expression, <<"accurate:"/utf8>> ) of true -> [_@1, Expression@1] = gleam@string:split(Expression, <<":"/utf8>>), {true, Expression@1}; false -> {false, Expression} end, case begin _pipe = Expression@2, _pipe@1 = gleam@string:split(_pipe, <<"+"/utf8>>), _pipe@2 = gleam@list:map(_pipe@1, fun gleam@string:trim/1), _pipe@3 = gleam@list:map(_pipe@2, fun gleam@string:lowercase/1), _pipe@4 = gleam@list:map( _pipe@3, fun(_capture) -> gleam@regex:scan(Re@1, _capture) end ), gleam@list:try_map(_pipe@4, fun(Item) -> case Item of [{match, _@2, [{some, Amount_string}, {some, Unit}]}] -> case gleam@int:parse(Amount_string) of {error, _try@1} -> {error, _try@1}; {ok, Amount} -> case gleam@list:find( [{year, [<<"y"/utf8>>, <<"year"/utf8>>, <<"years"/utf8>>]}, {month, [<<"mon"/utf8>>, <<"month"/utf8>>, <<"months"/utf8>>]}, {week, [<<"w"/utf8>>, <<"week"/utf8>>, <<"weeks"/utf8>>]}, {day, [<<"d"/utf8>>, <<"day"/utf8>>, <<"days"/utf8>>]}, {hour, [<<"h"/utf8>>, <<"hour"/utf8>>, <<"hours"/utf8>>]}, {minute, [<<"m"/utf8>>, <<"min"/utf8>>, <<"minute"/utf8>>, <<"minutes"/utf8>>]}, {second, [<<"s"/utf8>>, <<"sec"/utf8>>, <<"secs"/utf8>>, <<"second"/utf8>>, <<"seconds"/utf8>>]}, {milli_second, [<<"ms"/utf8>>, <<"msec"/utf8>>, <<"msecs"/utf8>>, <<"millisecond"/utf8>>, <<"milliseconds"/utf8>>]}], fun(Item@1) -> gleam@list:contains( erlang:element(2, Item@1), Unit ) end ) of {error, _try@2} -> {error, _try@2}; {ok, {Unit@1, _@3}} -> _pipe@5 = {Amount, Unit@1}, {ok, _pipe@5} end end; _@4 -> {error, nil} end end) end of {ok, Values} -> _pipe@6 = case Accurate of true -> accurate_new(Values); false -> new(Values) end, {ok, _pipe@6}; {error, nil} -> {error, nil} end. -spec extract(integer(), integer()) -> {integer(), integer()}. extract(Duration, Unit) -> {ok, Amount@1} = case gleam@int:divide(Duration, Unit) of {ok, Amount} -> {ok, Amount}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"birl/duration"/utf8>>, function => <<"extract"/utf8>>, line => 226}) end, {ok, Remaining@1} = case gleam@int:modulo(Duration, Unit) of {ok, Remaining} -> {ok, Remaining}; _try@1 -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try@1, module => <<"birl/duration"/utf8>>, function => <<"extract"/utf8>>, line => 227}) end, {Amount@1, Remaining@1}.