-module(tempo@datetime). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/3, now_utc/0, from_string/1, literal/1, to_string/1, from_unix_utc/1, from_unix_milli_utc/1, from_unix_micro_utc/1, get_date/1, get_time/1, get_offset/1, drop_offset/1, drop_time/1, to_second_precision/1, to_milli_precision/1, to_micro_precision/1, to_nano_precision/1, add/2, apply_offset/1, to_unix_utc/1, to_unix_milli_utc/1, to_unix_micro_utc/1, to_utc/1, compare/2, is_earlier/2, is_earlier_or_equal/2, is_equal/2, is_later/2, is_later_or_equal/2, difference/2, to_period/2, subtract/2, to_offset/2, to_local/1, now_local/0, now_text/0, to_local_time/1, to_local_date/1, time_left_in_day/1]). -spec new(tempo:date(), tempo:time(), tempo:offset()) -> tempo:date_time(). new(Date, Time, Offset) -> {date_time, tempo@naive_datetime:new(Date, Time), Offset}. -spec now_utc() -> tempo:date_time(). now_utc() -> Now_ts_nano = tempo_ffi:now(), new( tempo@date:from_unix_utc(Now_ts_nano div 1000000000), tempo@time:from_unix_nano_utc(Now_ts_nano), {offset, 0} ). -spec split_time_and_offset(binary()) -> {ok, {binary(), binary()}} | {error, tempo:error()}. split_time_and_offset(Time_with_offset) -> case gleam@string:slice(Time_with_offset, -1, 1) of <<"Z"/utf8>> -> _pipe = {gleam@string:drop_right(Time_with_offset, 1), <<"Z"/utf8>>}, {ok, _pipe}; <<"z"/utf8>> -> _pipe@1 = {gleam@string:drop_right(Time_with_offset, 1), <<"Z"/utf8>>}, {ok, _pipe@1}; _ -> case gleam@string:split(Time_with_offset, <<"-"/utf8>>) of [Time, Offset] -> _pipe@2 = {Time, <<"-"/utf8, Offset/binary>>}, {ok, _pipe@2}; _ -> case gleam@string:split(Time_with_offset, <<"+"/utf8>>) of [Time@1, Offset@1] -> _pipe@3 = {Time@1, <<"+"/utf8, Offset@1/binary>>}, {ok, _pipe@3}; _ -> {error, date_time_invalid_format} end end end. -spec from_string(binary()) -> {ok, tempo:date_time()} | {error, tempo:error()}. from_string(Datetime) -> case gleam@string:split(Datetime, <<"T"/utf8>>) of [Date, Time] -> gleam@result:'try'( tempo@date:from_string(Date), fun(Date@1) -> gleam@result:'try'( split_time_and_offset(Time), fun(_use0) -> {Time@1, Offset} = _use0, gleam@result:'try'( tempo@time:from_string(Time@1), fun(Time@2) -> gleam@result:map( tempo@offset:from_string(Offset), fun(Offset@1) -> new(Date@1, Time@2, Offset@1) end ) end ) end ) end ); [Date@2] -> _pipe = tempo@date:from_string(Date@2), gleam@result:map( _pipe, fun(_capture) -> new(_capture, {time, 0, 0, 0, 0}, {offset, 0}) end ); _ -> {error, date_time_invalid_format} end. -spec literal(binary()) -> tempo:date_time(). literal(Datetime) -> case from_string(Datetime) of {ok, Datetime@1} -> Datetime@1; {error, date_time_invalid_format} -> erlang:error(#{gleam_error => panic, message => <<"Invalid datetime literal format"/utf8>>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 49}); {error, date_time_out_of_bounds} -> erlang:error(#{gleam_error => panic, message => <<"Invalid datetime literal value"/utf8>>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 51}); {error, _} -> erlang:error(#{gleam_error => panic, message => <<"Invalid datetime literal"/utf8>>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 52}) end. -spec to_string(tempo:date_time()) -> binary(). to_string(Datetime) -> <<(begin _pipe = erlang:element(2, Datetime), tempo@naive_datetime:to_string(_pipe) end)/binary, (case erlang:element(2, erlang:element(3, Datetime)) of 0 -> <<"Z"/utf8>>; _ -> _pipe@1 = erlang:element(3, Datetime), tempo@offset:to_string(_pipe@1) end)/binary>>. -spec from_unix_utc(integer()) -> tempo:date_time(). from_unix_utc(Unix_ts) -> new( tempo@date:from_unix_utc(Unix_ts), tempo@time:from_unix_utc(Unix_ts), {offset, 0} ). -spec from_unix_milli_utc(integer()) -> tempo:date_time(). from_unix_milli_utc(Unix_ts) -> new( tempo@date:from_unix_milli_utc(Unix_ts), tempo@time:from_unix_milli_utc(Unix_ts), {offset, 0} ). -spec from_unix_micro_utc(integer()) -> tempo:date_time(). from_unix_micro_utc(Unix_ts) -> new( tempo@date:from_unix_micro_utc(Unix_ts), tempo@time:from_unix_micro_utc(Unix_ts), {offset, 0} ). -spec get_date(tempo:date_time()) -> tempo:date(). get_date(Datetime) -> erlang:element(2, erlang:element(2, Datetime)). -spec get_time(tempo:date_time()) -> tempo:time(). get_time(Datetime) -> erlang:element(3, erlang:element(2, Datetime)). -spec get_offset(tempo:date_time()) -> tempo:offset(). get_offset(Datetime) -> erlang:element(3, Datetime). -spec drop_offset(tempo:date_time()) -> tempo:naive_date_time(). drop_offset(Datetime) -> erlang:element(2, Datetime). -spec drop_time(tempo:date_time()) -> tempo:date_time(). drop_time(Datetime) -> {date_time, tempo@naive_datetime:drop_time(erlang:element(2, Datetime)), erlang:element(3, Datetime)}. -spec to_second_precision(tempo:date_time()) -> tempo:date_time(). to_second_precision(Datetime) -> new( erlang:element(2, erlang:element(2, Datetime)), begin _pipe = erlang:element(3, erlang:element(2, Datetime)), tempo@time:to_second_precision(_pipe) end, erlang:element(3, Datetime) ). -spec to_milli_precision(tempo:date_time()) -> tempo:date_time(). to_milli_precision(Datetime) -> new( erlang:element(2, erlang:element(2, Datetime)), begin _pipe = erlang:element(3, erlang:element(2, Datetime)), tempo@time:to_milli_precision(_pipe) end, erlang:element(3, Datetime) ). -spec to_micro_precision(tempo:date_time()) -> tempo:date_time(). to_micro_precision(Datetime) -> new( erlang:element(2, erlang:element(2, Datetime)), begin _pipe = erlang:element(3, erlang:element(2, Datetime)), tempo@time:to_micro_precision(_pipe) end, erlang:element(3, Datetime) ). -spec to_nano_precision(tempo:date_time()) -> tempo:date_time(). to_nano_precision(Datetime) -> new( erlang:element(2, erlang:element(2, Datetime)), begin _pipe = erlang:element(3, erlang:element(2, Datetime)), tempo@time:to_nano_precision(_pipe) end, erlang:element(3, Datetime) ). -spec add(tempo:date_time(), tempo:duration()) -> tempo:date_time(). add(Datetime, Duration_to_add) -> _pipe = Datetime, _pipe@1 = drop_offset(_pipe), _pipe@2 = tempo@naive_datetime:add(_pipe@1, Duration_to_add), tempo@naive_datetime:set_offset(_pipe@2, erlang:element(3, Datetime)). -spec apply_offset(tempo:date_time()) -> tempo:naive_date_time(). apply_offset(Datetime) -> _pipe = Datetime, _pipe@1 = add(_pipe, tempo@offset:to_duration(erlang:element(3, Datetime))), drop_offset(_pipe@1). -spec to_unix_utc(tempo:date_time()) -> integer(). to_unix_utc(Datetime) -> Utc_dt = begin _pipe = Datetime, apply_offset(_pipe) end, tempo@date:to_unix_utc(erlang:element(2, Utc_dt)) + (tempo@time:to_nanoseconds( erlang:element(3, Utc_dt) ) div 1000000000). -spec to_unix_milli_utc(tempo:date_time()) -> integer(). to_unix_milli_utc(Datetime) -> Utc_dt = begin _pipe = Datetime, apply_offset(_pipe) end, tempo@date:to_unix_milli_utc(erlang:element(2, Utc_dt)) + (tempo@time:to_nanoseconds( erlang:element(3, Utc_dt) ) div 1000000). -spec to_unix_micro_utc(tempo:date_time()) -> integer(). to_unix_micro_utc(Datetime) -> Utc_dt = begin _pipe = Datetime, apply_offset(_pipe) end, tempo@date:to_unix_micro_utc(erlang:element(2, Utc_dt)) + (tempo@time:to_nanoseconds( erlang:element(3, Utc_dt) ) div 1000). -spec to_utc(tempo:date_time()) -> tempo:date_time(). to_utc(Datetime) -> _pipe = Datetime, _pipe@1 = add(_pipe, tempo@offset:to_duration(erlang:element(3, Datetime))), _pipe@2 = drop_offset(_pipe@1), tempo@naive_datetime:set_offset(_pipe@2, {offset, 0}). -spec compare(tempo:date_time(), tempo:date_time()) -> gleam@order:order(). compare(A, B) -> _pipe = apply_offset(A), tempo@naive_datetime:compare(_pipe, apply_offset(B)). -spec is_earlier(tempo:date_time(), tempo:date_time()) -> boolean(). is_earlier(A, B) -> compare(A, B) =:= lt. -spec is_earlier_or_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_earlier_or_equal(A, B) -> (compare(A, B) =:= lt) orelse (compare(A, B) =:= eq). -spec is_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_equal(A, B) -> compare(A, B) =:= eq. -spec is_later(tempo:date_time(), tempo:date_time()) -> boolean(). is_later(A, B) -> compare(A, B) =:= gt. -spec is_later_or_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_later_or_equal(A, B) -> (compare(A, B) =:= gt) orelse (compare(A, B) =:= eq). -spec difference(tempo:date_time(), tempo:date_time()) -> tempo:period(). difference(A, B) -> _pipe = apply_offset(A), tempo@naive_datetime:difference(_pipe, apply_offset(B)). -spec to_period(tempo:date_time(), tempo:date_time()) -> tempo:period(). to_period(Start, End) -> _pipe = apply_offset(Start), tempo@naive_datetime:to_period(_pipe, apply_offset(End)). -spec subtract(tempo:date_time(), tempo:duration()) -> tempo:date_time(). subtract(Datetime, Duration_to_subtract) -> _pipe = Datetime, _pipe@1 = drop_offset(_pipe), _pipe@2 = tempo@naive_datetime:subtract(_pipe@1, Duration_to_subtract), tempo@naive_datetime:set_offset(_pipe@2, erlang:element(3, Datetime)). -spec to_offset(tempo:date_time(), tempo:offset()) -> tempo:date_time(). to_offset(Datetime, Offset) -> _pipe = Datetime, _pipe@1 = to_utc(_pipe), _pipe@2 = subtract(_pipe@1, tempo@offset:to_duration(Offset)), _pipe@3 = drop_offset(_pipe@2), tempo@naive_datetime:set_offset(_pipe@3, Offset). -spec to_local(tempo:date_time()) -> tempo:uncertain_conversion(tempo:date_time()). to_local(Datetime) -> gleam@bool:lazy_guard( erlang:element(3, Datetime) =:= tempo@offset:local(), fun() -> {precise, Datetime} end, fun() -> Local_dt = begin _pipe = Datetime, to_offset(_pipe, tempo@offset:local()) end, case erlang:element(2, erlang:element(2, Local_dt)) =:= tempo@date:current_local( ) of true -> {precise, Local_dt}; false -> {imprecise, Local_dt} end end ). -spec now_local() -> tempo:date_time(). now_local() -> case begin _pipe = now_utc(), to_local(_pipe) end of {precise, Datetime} -> Datetime; {imprecise, Datetime@1} -> Datetime@1 end. -spec now_text() -> binary(). now_text() -> _pipe = now_local(), _pipe@1 = drop_offset(_pipe), _pipe@2 = tempo@naive_datetime:to_milli_precision(_pipe@1), _pipe@3 = tempo@naive_datetime:to_string(_pipe@2), gleam@string:replace(_pipe@3, <<"T"/utf8>>, <<" "/utf8>>). -spec to_local_time(tempo:date_time()) -> tempo:uncertain_conversion(tempo:time()). to_local_time(Datetime) -> case to_local(Datetime) of {precise, Datetime@1} -> _pipe = erlang:element(3, erlang:element(2, Datetime@1)), {precise, _pipe}; {imprecise, Datetime@2} -> _pipe@1 = erlang:element(3, erlang:element(2, Datetime@2)), {imprecise, _pipe@1} end. -spec to_local_date(tempo:date_time()) -> tempo:uncertain_conversion(tempo:date()). to_local_date(Datetime) -> case to_local(Datetime) of {precise, Datetime@1} -> _pipe = erlang:element(2, erlang:element(2, Datetime@1)), {precise, _pipe}; {imprecise, Datetime@2} -> _pipe@1 = erlang:element(2, erlang:element(2, Datetime@2)), {imprecise, _pipe@1} end. -spec time_left_in_day(tempo:date_time()) -> tempo:time(). time_left_in_day(Datetime) -> _pipe = erlang:element(3, erlang:element(2, Datetime)), tempo@time:left_in_day(_pipe).