Current section
Files
Jump to
Current section
Files
src/birl@time.erl
-module(birl@time).
-compile([no_auto_import, nowarn_unused_vars]).
-export([compare/2, difference/2, add/2, subtract/2, now/0, utc_now/0, now_with_offset/1, to_parts/1, to_iso8601/1, from_parts/3, from_iso8601/1, weekday/1]).
-export_type([time/0, week_day/0]).
-opaque time() :: {time, integer(), integer(), gleam@option:option(integer())}.
-type week_day() :: monday |
tuesday |
wednesday |
thursday |
friday |
saturday |
sunday.
-spec compare(time(), time()) -> gleam@order:order().
compare(A, B) ->
{time, Wta, Oa, Mta} = A,
{time, Wtb, Ob, Mtb} = B,
{Ta@1, Tb@1} = case {Mta, Mtb} of
{{some, Ta}, {some, Tb}} ->
{Ta, Tb};
_ ->
{Wta + Oa, Wtb + Ob}
end,
case Ta@1 =:= Tb@1 of
true ->
eq;
false ->
case Ta@1 < Tb@1 of
true ->
lt;
false ->
gt
end
end.
-spec difference(time(), time()) -> birl@duration:duration().
difference(A, B) ->
{time, Wta, Oa, Mta} = A,
{time, Wtb, Ob, Mtb} = B,
{Ta@1, Tb@1} = case {Mta, Mtb} of
{{some, Ta}, {some, Tb}} ->
{Ta, Tb};
_ ->
{Wta + Oa, Wtb + Ob}
end,
{duration, Ta@1 - Tb@1}.
-spec add(time(), birl@duration:duration()) -> time().
add(Value, Duration) ->
{time, Wt, O, Mt} = Value,
{duration, Duration@1} = Duration,
case Mt of
{some, Mt@1} ->
{time, Wt + Duration@1, O, {some, Mt@1 + Duration@1}};
none ->
{time, Wt + Duration@1, O, none}
end.
-spec subtract(time(), birl@duration:duration()) -> time().
subtract(Value, Duration) ->
{time, Wt, O, Mt} = Value,
{duration, Duration@1} = Duration,
case Mt of
{some, Mt@1} ->
{time, Wt - Duration@1, O, {some, Mt@1 - Duration@1}};
none ->
{time, Wt - Duration@1, O, none}
end.
-spec parse_offset(binary()) -> {ok, integer()} | {error, nil}.
parse_offset(Offset) ->
_assert_subject = gleam@regex:from_string(<<"([+-])"/utf8>>),
{ok, Re} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"birl/time"/utf8>>,
function => <<"parse_offset"/utf8>>,
line => 242})
end,
gleam@result:then(case gleam@regex:split(Re, Offset) of
[<<""/utf8>>, <<"+"/utf8>>, Offset@1] ->
{ok, {1, Offset@1}};
[<<""/utf8>>, <<"-"/utf8>>, Offset@2] ->
{ok, {-1, Offset@2}};
[_] ->
{ok, {1, Offset}};
_ ->
{error, nil}
end, fun(_use0) ->
{Sign, Offset@3} = _use0,
case gleam@string:split(Offset@3, <<":"/utf8>>) of
[Hour_str, Minute_str] ->
gleam@result:then(
gleam@int:parse(Hour_str),
fun(Hour) ->
gleam@result:then(
gleam@int:parse(Minute_str),
fun(Minute) ->
{ok,
((Sign
* ((Hour
* 60)
+ Minute))
* 60)
* 1000000}
end
)
end
);
[Offset@4] ->
case gleam@string:length(Offset@4) of
1 ->
gleam@result:then(
gleam@int:parse(Offset@4),
fun(Hour@1) ->
{ok, ((Sign * Hour@1) * 3600) * 1000000}
end
);
2 ->
gleam@result:then(
gleam@int:parse(Offset@4),
fun(Hour@1) ->
{ok, ((Sign * Hour@1) * 3600) * 1000000}
end
);
3 ->
_assert_subject@1 = gleam@string:first(Offset@4),
{ok, Hour_str@1} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"birl/time"/utf8>>,
function => <<"parse_offset"/utf8>>,
line => 263})
end,
Minute_str@1 = gleam@string:slice(Offset@4, 1, 2),
gleam@result:then(
gleam@int:parse(Hour_str@1),
fun(Hour@2) ->
gleam@result:then(
gleam@int:parse(Minute_str@1),
fun(Minute@1) ->
{ok,
((Sign
* ((Hour@2
* 60)
+ Minute@1))
* 60)
* 1000000}
end
)
end
);
4 ->
Hour_str@2 = gleam@string:slice(Offset@4, 0, 2),
Minute_str@2 = gleam@string:slice(Offset@4, 2, 2),
gleam@result:then(
gleam@int:parse(Hour_str@2),
fun(Hour@3) ->
gleam@result:then(
gleam@int:parse(Minute_str@2),
fun(Minute@2) ->
{ok,
((Sign
* ((Hour@3
* 60)
+ Minute@2))
* 60)
* 1000000}
end
)
end
);
_ ->
{error, nil}
end;
_ ->
{error, nil}
end
end).
-spec generate_offset(integer()) -> {ok, binary()} | {error, nil}.
generate_offset(Offset) ->
case Offset of
0 ->
{ok, <<"Z"/utf8>>};
_ ->
case begin
_pipe = [{Offset, micro_second}],
_pipe@1 = birl@duration:new(_pipe),
birl@duration:decompose(_pipe@1)
end of
[{Hour, hour}, {Minute, minute}] ->
_pipe@10 = [case Hour > 0 of
true ->
gleam@string:concat(
[<<"+"/utf8>>,
begin
_pipe@2 = Hour,
_pipe@3 = gleam@int:to_string(
_pipe@2
),
gleam@string:pad_left(
_pipe@3,
2,
<<"0"/utf8>>
)
end]
);
false ->
gleam@string:concat(
[<<"-"/utf8>>,
begin
_pipe@4 = Hour,
_pipe@5 = gleam@int:absolute_value(
_pipe@4
),
_pipe@6 = gleam@int:to_string(
_pipe@5
),
gleam@string:pad_left(
_pipe@6,
2,
<<"0"/utf8>>
)
end]
)
end, begin
_pipe@7 = Minute,
_pipe@8 = gleam@int:absolute_value(_pipe@7),
_pipe@9 = gleam@int:to_string(_pipe@8),
gleam@string:pad_left(_pipe@9, 2, <<"0"/utf8>>)
end],
_pipe@11 = gleam@string:join(_pipe@10, <<":"/utf8>>),
{ok, _pipe@11};
_ ->
{error, nil}
end
end.
-spec parse_iso_section(binary(), binary(), integer()) -> {ok, list(integer())} |
{error, nil}.
parse_iso_section(Section, Pattern_string, Default) ->
_assert_subject = gleam@regex:from_string(Pattern_string),
{ok, Pattern} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"birl/time"/utf8>>,
function => <<"parse_iso_section"/utf8>>,
line => 327})
end,
_pipe = case gleam@regex:scan(Pattern, Section) of
[{match, _, [{some, Major}]}] ->
[gleam@int:parse(Major), {ok, Default}, {ok, Default}];
[{match, _, [{some, Major}, none]}] ->
[gleam@int:parse(Major), {ok, Default}, {ok, Default}];
[{match, _, [{some, Major@1}, {some, Middle}]}] ->
[gleam@int:parse(Major@1), gleam@int:parse(Middle), {ok, Default}];
[{match, _, [{some, Major@1}, {some, Middle}, none]}] ->
[gleam@int:parse(Major@1), gleam@int:parse(Middle), {ok, Default}];
[{match, _, [{some, Major@2}, {some, Middle@1}, {some, Minor}]}] ->
[gleam@int:parse(Major@2),
gleam@int:parse(Middle@1),
gleam@int:parse(Minor)];
_ ->
[{error, nil}]
end,
gleam@list:try_map(_pipe, fun(Part) -> case Part of
{ok, Inner} ->
{ok, Inner};
{error, nil} ->
{error, nil}
end end).
-spec now() -> time().
now() ->
Now = birl_ffi:now(),
Offset_in_minutes = birl_ffi:local_offset(),
Monotonic_now = birl_ffi:monotonic_now(),
{time, Now, Offset_in_minutes * 60000000, {some, Monotonic_now}}.
-spec utc_now() -> time().
utc_now() ->
Now = birl_ffi:now(),
Monotonic_now = birl_ffi:monotonic_now(),
{time, Now, 0, {some, Monotonic_now}}.
-spec now_with_offset(binary()) -> {ok, time()} | {error, nil}.
now_with_offset(Offset) ->
gleam@result:then(
parse_offset(Offset),
fun(Offset@1) ->
Now = birl_ffi:now(),
Monotonic_now = birl_ffi:monotonic_now(),
_pipe = {time, Now, Offset@1, {some, Monotonic_now}},
{ok, _pipe}
end
).
-spec to_parts(time()) -> {{integer(), integer(), integer()},
{integer(), integer(), integer()},
binary()}.
to_parts(Value) ->
case Value of
{time, T, O, _} ->
{Date, Time} = birl_ffi:to_parts(T + O),
_assert_subject = generate_offset(O),
{ok, Offset} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"birl/time"/utf8>>,
function => <<"to_parts"/utf8>>,
line => 56})
end,
{Date, Time, Offset}
end.
-spec to_iso8601(time()) -> binary().
to_iso8601(Value) ->
{{Year, Month, Day}, {Hour, Minute, Second}, Offset} = to_parts(Value),
<<<<<<<<<<<<<<<<<<<<<<<<(gleam@int:to_string(Year))/binary, "-"/utf8>>/binary,
(begin
_pipe = Month,
_pipe@1 = gleam@int:to_string(
_pipe
),
gleam@string:pad_left(
_pipe@1,
2,
<<"0"/utf8>>
)
end)/binary>>/binary,
"-"/utf8>>/binary,
(begin
_pipe@2 = Day,
_pipe@3 = gleam@int:to_string(
_pipe@2
),
gleam@string:pad_left(
_pipe@3,
2,
<<"0"/utf8>>
)
end)/binary>>/binary,
"T"/utf8>>/binary,
(begin
_pipe@4 = Hour,
_pipe@5 = gleam@int:to_string(_pipe@4),
gleam@string:pad_left(
_pipe@5,
2,
<<"0"/utf8>>
)
end)/binary>>/binary,
":"/utf8>>/binary,
(begin
_pipe@6 = Minute,
_pipe@7 = gleam@int:to_string(_pipe@6),
gleam@string:pad_left(_pipe@7, 2, <<"0"/utf8>>)
end)/binary>>/binary,
":"/utf8>>/binary,
(begin
_pipe@8 = Second,
_pipe@9 = gleam@int:to_string(_pipe@8),
gleam@string:pad_left(_pipe@9, 2, <<"0"/utf8>>)
end)/binary>>/binary,
".000"/utf8>>/binary,
Offset/binary>>.
-spec from_parts(
{integer(), integer(), integer()},
{integer(), integer(), integer()},
binary()
) -> {ok, time()} | {error, nil}.
from_parts(Date, Time, Offset) ->
gleam@result:then(
parse_offset(Offset),
fun(Offset_number) ->
_pipe = birl_ffi:from_parts({Date, Time}, Offset_number),
_pipe@1 = {time, _pipe, Offset_number, none},
{ok, _pipe@1}
end
).
-spec from_iso8601(binary()) -> {ok, time()} | {error, nil}.
from_iso8601(Value) ->
_assert_subject = gleam@regex:from_string(<<"(.*)([+|\\-].*)"/utf8>>),
{ok, Offset_pattern} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"birl/time"/utf8>>,
function => <<"from_iso8601"/utf8>>,
line => 99})
end,
Value@1 = gleam@string:trim(Value),
{Date_string@2, Offsetted_time_string@1} = case gleam@string:split(
Value@1,
<<"T"/utf8>>
) of
[Date_string] ->
{Date_string, <<"00"/utf8>>};
[Date_string@1, Offsetted_time_string] ->
{Date_string@1, Offsetted_time_string}
end,
{Time_string@1, Offset_string@1} = case gleam@string:ends_with(
Offsetted_time_string@1,
<<"Z"/utf8>>
) of
true ->
{gleam@string:drop_right(Offsetted_time_string@1, 1),
<<"+00:00"/utf8>>};
false ->
case gleam@regex:scan(Offset_pattern, Offsetted_time_string@1) of
[{match, _, [{some, Time_string}, {some, Offset_string}]}] ->
{Time_string, Offset_string};
[] ->
Local_offset_in_minutes = birl_ffi:local_offset(),
_assert_subject@1 = generate_offset(
Local_offset_in_minutes
* 60000000
),
{ok, Local_offset_string} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"birl/time"/utf8>>,
function => <<"from_iso8601"/utf8>>,
line => 122})
end,
{Offsetted_time_string@1, Local_offset_string}
end
end,
Date_string@3 = gleam@string:replace(
Date_string@2,
<<"-"/utf8>>,
<<""/utf8>>
),
Time_string@2 = gleam@string:replace(
Time_string@1,
<<":"/utf8>>,
<<""/utf8>>
),
{Time_string@5, Milli_seconds_result} = case gleam@string:split(
Time_string@2,
<<"."/utf8>>
) of
[Time_string@3] ->
{Time_string@3, {ok, 0}};
[Time_string@4, Milli_seconds_string] ->
{Time_string@4, gleam@int:parse(Milli_seconds_string)}
end,
case Milli_seconds_result of
{ok, Milli_seconds} ->
gleam@result:then(
parse_iso_section(
Date_string@3,
<<"(\\d{4})(\\d{2})?(\\d{2})?"/utf8>>,
1
),
fun(_use0) ->
[Year, Month, Day] = _use0,
gleam@result:then(
parse_iso_section(
Time_string@5,
<<"(\\d{2})(\\d{2})?(\\d{2})?"/utf8>>,
0
),
fun(_use0@1) ->
[Hour, Minute, Second] = _use0@1,
case from_parts(
{Year, Month, Day},
{Hour, Minute, Second},
Offset_string@1
) of
{ok, {time, Timestamp, Offset, none}} ->
{ok,
{time,
Timestamp
+ (Milli_seconds
* 1000),
Offset,
none}};
{error, nil} ->
{error, nil}
end
end
)
end
);
{error, nil} ->
{error, nil}
end.
-spec weekday(time()) -> week_day().
weekday(Value) ->
case Value of
{time, T, O, _} ->
_assert_subject = gleam@list:at(
[monday, tuesday, wednesday, thursday, friday, saturday, sunday],
birl_ffi:weekday(T + O)
),
{ok, Weekday} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"birl/time"/utf8>>,
function => <<"weekday"/utf8>>,
line => 235})
end,
Weekday
end.