Packages

A comprehensive calendar library for Gleam — date, time, datetime, naive datetime, duration, ISO 8601 parsing and formatting, timezone support. Port of Elixir's Calendar modules.

Current section

Files

Jump to
sidereal src calendar@datetime.erl
Raw

src/calendar@datetime.erl

-module(calendar@datetime).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/calendar/datetime.gleam").
-export([new/12, new_utc/8, new_utc_simple/6, from_naive_datetime/5, to_naive_datetime/1, to_date/1, to_time/1, to_local_timestamp/1, to_utc_timestamp/1, compare/2, from_utc_timestamp/2, add_seconds/2, to_string/1, to_iso8601/1, new_from_date_and_time/2, new_from_date_and_time_with_tz/6, from_naive_utc/1, from_naive_with_timezone/5, shift_zone/5, to_erl/1, from_erl/5, before/2, 'after'/2, shift/2, truncate/2, convert/2, from_gregorian_seconds/3, to_gregorian_seconds/1, from_unix/3, utc_now_with_precision/2, utc_now/0, now/4, add/3, to_unix/2, diff/3, to_iso8601_basic/1, to_iso8601_with_format/2, from_iso8601/1, from_iso8601_with_calendar/2]).
-export_type([date_time/0, date_time_error/0, date_time_format/0, time_unit/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type date_time() :: {date_time,
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
binary(),
binary(),
integer(),
integer(),
{integer(), integer()},
binary()}.
-type date_time_error() :: invalid_date_time |
invalid_date |
invalid_time |
invalid_format |
time_zone_not_found |
utc_only_time_zone_database |
ambiguous_time |
gap_in_time.
-type date_time_format() :: extended | basic.
-type time_unit() :: native | second | millisecond | microsecond | nanosecond.
-file("src/calendar/datetime.gleam", 66).
?DOC(" Creates a new DateTime struct.\n").
-spec new(
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
binary(),
binary(),
integer(),
integer(),
{integer(), integer()},
binary()
) -> {ok, date_time()} | {error, date_time_error()}.
new(
Year,
Month,
Day,
Hour,
Minute,
Second,
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
Microsecond,
Calendar
) ->
case calendar@date:new(Year, Month, Day, Calendar) of
{error, _} ->
{error, invalid_date};
{ok, _} ->
case calendar@time:new(Hour, Minute, Second, Microsecond, Calendar) of
{error, _} ->
{error, invalid_time};
{ok, _} ->
{ok,
{date_time,
Year,
Month,
Day,
Hour,
Minute,
Second,
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
Microsecond,
Calendar}}
end
end.
-file("src/calendar/datetime.gleam", 108).
?DOC(" Creates a UTC DateTime from date and time components.\n").
-spec new_utc(
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
{integer(), integer()},
binary()
) -> {ok, date_time()} | {error, date_time_error()}.
new_utc(Year, Month, Day, Hour, Minute, Second, Microsecond, Calendar) ->
new(
Year,
Month,
Day,
Hour,
Minute,
Second,
<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0,
Microsecond,
Calendar
).
-file("src/calendar/datetime.gleam", 135).
?DOC(" Creates a simple UTC DateTime with default values.\n").
-spec new_utc_simple(
integer(),
integer(),
integer(),
integer(),
integer(),
integer()
) -> {ok, date_time()} | {error, date_time_error()}.
new_utc_simple(Year, Month, Day, Hour, Minute, Second) ->
new_utc(
Year,
Month,
Day,
Hour,
Minute,
Second,
{0, 0},
<<"Calendar.ISO"/utf8>>
).
-file("src/calendar/datetime.gleam", 147).
?DOC(" Creates a DateTime from a NaiveDateTime and timezone information.\n").
-spec from_naive_datetime(
calendar@naive_datetime:naive_date_time(),
binary(),
binary(),
integer(),
integer()
) -> date_time().
from_naive_datetime(Ndt, Time_zone, Zone_abbr, Utc_offset, Std_offset) ->
{date_time,
erlang:element(2, Ndt),
erlang:element(3, Ndt),
erlang:element(4, Ndt),
erlang:element(5, Ndt),
erlang:element(6, Ndt),
erlang:element(7, Ndt),
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
erlang:element(8, Ndt),
erlang:element(9, Ndt)}.
-file("src/calendar/datetime.gleam", 234).
?DOC(" Extracts the NaiveDateTime part from a DateTime.\n").
-spec to_naive_datetime(date_time()) -> calendar@naive_datetime:naive_date_time().
to_naive_datetime(Dt) ->
case calendar@naive_datetime:new(
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(12, Dt),
erlang:element(13, Dt)
) of
{ok, Ndt} ->
Ndt;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid datetime in valid DateTime struct"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"calendar/datetime"/utf8>>,
function => <<"to_naive_datetime"/utf8>>,
line => 248})
end.
-file("src/calendar/datetime.gleam", 253).
?DOC(" Extracts the Date part from a DateTime.\n").
-spec to_date(date_time()) -> calendar@date:date().
to_date(Dt) ->
case calendar@date:new(
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(13, Dt)
) of
{ok, D} ->
D;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid date in valid DateTime struct"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"calendar/datetime"/utf8>>,
function => <<"to_date"/utf8>>,
line => 256})
end.
-file("src/calendar/datetime.gleam", 261).
?DOC(" Extracts the Time part from a DateTime.\n").
-spec to_time(date_time()) -> calendar@time:time().
to_time(Dt) ->
case calendar@time:new(
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(12, Dt),
erlang:element(13, Dt)
) of
{ok, T} ->
T;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid time in valid DateTime struct"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"calendar/datetime"/utf8>>,
function => <<"to_time"/utf8>>,
line => 264})
end.
-file("src/calendar/datetime.gleam", 281).
?DOC(" Convert DateTime to local timestamp.\n").
-spec to_local_timestamp(date_time()) -> integer().
to_local_timestamp(Dt) ->
Date_part = to_date(Dt),
Date_timestamp = calendar@date:to_timestamp(Date_part),
Time_seconds = ((erlang:element(5, Dt) * 3600) + (erlang:element(6, Dt) * 60))
+ erlang:element(7, Dt),
Date_timestamp + Time_seconds.
-file("src/calendar/datetime.gleam", 275).
?DOC(" Convert DateTime to UTC timestamp.\n").
-spec to_utc_timestamp(date_time()) -> integer().
to_utc_timestamp(Dt) ->
Local_timestamp = to_local_timestamp(Dt),
Local_timestamp - (erlang:element(10, Dt) + erlang:element(11, Dt)).
-file("src/calendar/datetime.gleam", 268).
-spec compare(date_time(), date_time()) -> gleam@order:order().
compare(Dt1, Dt2) ->
Utc1 = to_utc_timestamp(Dt1),
Utc2 = to_utc_timestamp(Dt2),
gleam@int:compare(Utc1, Utc2).
-file("src/calendar/datetime.gleam", 289).
?DOC(" Create DateTime from UTC timestamp.\n").
-spec from_utc_timestamp(integer(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
from_utc_timestamp(Timestamp, Time_zone) ->
case Time_zone =:= <<"Etc/UTC"/utf8>> of
true ->
case calendar@naive_datetime:from_timestamp(Timestamp) of
{error, _} ->
{error, invalid_date_time};
{ok, Ndt} ->
{ok,
from_naive_datetime(
Ndt,
<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0
)}
end;
false ->
{error, utc_only_time_zone_database}
end.
-file("src/calendar/datetime.gleam", 307).
?DOC(" Add seconds to a DateTime (adjusts UTC time).\n").
-spec add_seconds(date_time(), integer()) -> {ok, date_time()} |
{error, date_time_error()}.
add_seconds(Dt, Seconds) ->
Utc_timestamp = to_utc_timestamp(Dt),
from_utc_timestamp(Utc_timestamp + Seconds, erlang:element(8, Dt)).
-file("src/calendar/datetime.gleam", 316).
?DOC(" Helper functions\n").
-spec pad_left(binary(), integer(), binary()) -> binary().
pad_left(Str, Width, Pad_char) ->
Current_length = string:length(Str),
case Current_length >= Width of
true ->
Str;
false ->
<<(gleam@string:repeat(Pad_char, Width - Current_length))/binary,
Str/binary>>
end.
-file("src/calendar/datetime.gleam", 324).
-spec pad_microseconds(integer(), integer()) -> binary().
pad_microseconds(Microseconds, Precision) ->
Ms_str = erlang:integer_to_binary(Microseconds),
Padded = case string:length(Ms_str) < Precision of
true ->
<<(gleam@string:repeat(
<<"0"/utf8>>,
Precision - string:length(Ms_str)
))/binary,
Ms_str/binary>>;
false ->
Ms_str
end,
gleam@string:slice(Padded, 0, Precision).
-file("src/calendar/datetime.gleam", 333).
-spec format_offset(integer()) -> binary().
format_offset(Total_offset) ->
case Total_offset =:= 0 of
true ->
<<"+00:00"/utf8>>;
false ->
Sign = case Total_offset >= 0 of
true ->
<<"+"/utf8>>;
false ->
<<"-"/utf8>>
end,
Abs_offset = case Total_offset < 0 of
true ->
- Total_offset;
false ->
Total_offset
end,
Hours = Abs_offset div 3600,
Minutes = (Abs_offset rem 3600) div 60,
<<<<<<Sign/binary,
(pad_left(
erlang:integer_to_binary(Hours),
2,
<<"0"/utf8>>
))/binary>>/binary,
":"/utf8>>/binary,
(pad_left(erlang:integer_to_binary(Minutes), 2, <<"0"/utf8>>))/binary>>
end.
-file("src/calendar/datetime.gleam", 171).
?DOC(" Converts a DateTime to a string with timezone information.\n").
-spec to_string(date_time()) -> binary().
to_string(Dt) ->
Date_part = <<<<<<<<(pad_left(
erlang:integer_to_binary(erlang:element(2, Dt)),
4,
<<"0"/utf8>>
))/binary,
"-"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(3, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
"-"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(4, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
Time_part = <<<<<<<<(pad_left(
erlang:integer_to_binary(erlang:element(5, Dt)),
2,
<<"0"/utf8>>
))/binary,
":"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(6, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
":"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(7, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
{Ms, Precision} = erlang:element(12, Dt),
Microsecond_part = case (Ms =:= 0) orelse (Precision =:= 0) of
true ->
<<""/utf8>>;
false ->
<<"."/utf8, (pad_microseconds(Ms, Precision))/binary>>
end,
Offset_part = format_offset(erlang:element(10, Dt) + erlang:element(11, Dt)),
<<<<<<<<<<<<Date_part/binary, " "/utf8>>/binary, Time_part/binary>>/binary,
Microsecond_part/binary>>/binary,
Offset_part/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(9, Dt))/binary>>.
-file("src/calendar/datetime.gleam", 204).
?DOC(" Converts a DateTime to ISO8601 format with timezone.\n").
-spec to_iso8601(date_time()) -> binary().
to_iso8601(Dt) ->
Date_part = <<<<<<<<(pad_left(
erlang:integer_to_binary(erlang:element(2, Dt)),
4,
<<"0"/utf8>>
))/binary,
"-"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(3, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
"-"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(4, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
Time_part = <<<<<<<<(pad_left(
erlang:integer_to_binary(erlang:element(5, Dt)),
2,
<<"0"/utf8>>
))/binary,
":"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(6, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
":"/utf8>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(7, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
{Ms, Precision} = erlang:element(12, Dt),
Microsecond_part = case (Ms =:= 0) orelse (Precision =:= 0) of
true ->
<<""/utf8>>;
false ->
<<"."/utf8, (pad_microseconds(Ms, Precision))/binary>>
end,
Offset_part = case erlang:element(8, Dt) =:= <<"Etc/UTC"/utf8>> of
true ->
<<"Z"/utf8>>;
false ->
format_offset(erlang:element(10, Dt) + erlang:element(11, Dt))
end,
<<<<<<<<Date_part/binary, "T"/utf8>>/binary, Time_part/binary>>/binary,
Microsecond_part/binary>>/binary,
Offset_part/binary>>.
-file("src/calendar/datetime.gleam", 377).
?DOC(" Creates a DateTime from Date and Time structs with UTC timezone.\n").
-spec new_from_date_and_time(calendar@date:date(), calendar@time:time()) -> {ok,
date_time()} |
{error, date_time_error()}.
new_from_date_and_time(Date_val, Time_val) ->
case erlang:element(5, Date_val) =:= erlang:element(6, Time_val) of
false ->
{error, invalid_date_time};
true ->
new_utc(
erlang:element(2, Date_val),
erlang:element(3, Date_val),
erlang:element(4, Date_val),
erlang:element(2, Time_val),
erlang:element(3, Time_val),
erlang:element(4, Time_val),
erlang:element(5, Time_val),
erlang:element(5, Date_val)
)
end.
-file("src/calendar/datetime.gleam", 398).
?DOC(" Creates a DateTime from Date and Time structs with specified timezone.\n").
-spec new_from_date_and_time_with_tz(
calendar@date:date(),
calendar@time:time(),
binary(),
binary(),
integer(),
integer()
) -> {ok, date_time()} | {error, date_time_error()}.
new_from_date_and_time_with_tz(
Date_val,
Time_val,
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset
) ->
case erlang:element(5, Date_val) =:= erlang:element(6, Time_val) of
false ->
{error, invalid_date_time};
true ->
new(
erlang:element(2, Date_val),
erlang:element(3, Date_val),
erlang:element(4, Date_val),
erlang:element(2, Time_val),
erlang:element(3, Time_val),
erlang:element(4, Time_val),
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
erlang:element(5, Time_val),
erlang:element(5, Date_val)
)
end.
-file("src/calendar/datetime.gleam", 448).
?DOC(" Creates a DateTime from NaiveDateTime with UTC timezone.\n").
-spec from_naive_utc(calendar@naive_datetime:naive_date_time()) -> date_time().
from_naive_utc(Ndt) ->
from_naive_datetime(Ndt, <<"Etc/UTC"/utf8>>, <<"UTC"/utf8>>, 0, 0).
-file("src/calendar/datetime.gleam", 453).
?DOC(" Creates a DateTime from NaiveDateTime with specified timezone.\n").
-spec from_naive_with_timezone(
calendar@naive_datetime:naive_date_time(),
binary(),
binary(),
integer(),
integer()
) -> {ok, date_time()} | {error, date_time_error()}.
from_naive_with_timezone(Ndt, Time_zone, Zone_abbr, Utc_offset, Std_offset) ->
{ok, from_naive_datetime(Ndt, Time_zone, Zone_abbr, Utc_offset, Std_offset)}.
-file("src/calendar/datetime.gleam", 464).
?DOC(" Shifts a DateTime to a different timezone.\n").
-spec shift_zone(date_time(), binary(), binary(), integer(), integer()) -> {ok,
date_time()} |
{error, date_time_error()}.
shift_zone(Dt, Time_zone, Zone_abbr, Utc_offset, Std_offset) ->
case Time_zone =:= erlang:element(8, Dt) of
true ->
{ok, Dt};
false ->
Utc_timestamp = to_utc_timestamp(Dt),
Adjusted_timestamp = (Utc_timestamp + Utc_offset) + Std_offset,
case calendar@naive_datetime:from_timestamp(Adjusted_timestamp) of
{error, _} ->
{error, invalid_date_time};
{ok, Ndt} ->
{ok,
from_naive_datetime(
Ndt,
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset
)}
end
end.
-file("src/calendar/datetime.gleam", 553).
?DOC(" Converts DateTime to Erlang datetime tuple.\n").
-spec to_erl(date_time()) -> {{integer(), integer(), integer()},
{integer(), integer(), integer()}}.
to_erl(Dt) ->
{{erlang:element(2, Dt), erlang:element(3, Dt), erlang:element(4, Dt)},
{erlang:element(5, Dt), erlang:element(6, Dt), erlang:element(7, Dt)}}.
-file("src/calendar/datetime.gleam", 558).
?DOC(" Creates DateTime from Erlang datetime tuple.\n").
-spec from_erl(
{{integer(), integer(), integer()}, {integer(), integer(), integer()}},
binary(),
binary(),
integer(),
integer()
) -> {ok, date_time()} | {error, date_time_error()}.
from_erl(Erl_datetime, Time_zone, Zone_abbr, Utc_offset, Std_offset) ->
{{Year, Month, Day}, {Hour, Minute, Second}} = Erl_datetime,
new(
Year,
Month,
Day,
Hour,
Minute,
Second,
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
{0, 0},
<<"Calendar.ISO"/utf8>>
).
-file("src/calendar/datetime.gleam", 583).
?DOC(" Returns `true` if the first datetime is strictly earlier than the second.\n").
-spec before(date_time(), date_time()) -> boolean().
before(Dt1, Dt2) ->
case compare(Dt1, Dt2) of
lt ->
true;
_ ->
false
end.
-file("src/calendar/datetime.gleam", 591).
?DOC(" Returns `true` if the first datetime is strictly later than the second.\n").
-spec 'after'(date_time(), date_time()) -> boolean().
'after'(Dt1, Dt2) ->
case compare(Dt1, Dt2) of
gt ->
true;
_ ->
false
end.
-file("src/calendar/datetime.gleam", 617).
?DOC(" Adds time to a DateTime using Duration.\n").
-spec shift(date_time(), calendar@duration:duration()) -> {ok, date_time()} |
{error, date_time_error()}.
shift(Dt, Dur) ->
Month_shift = (erlang:element(2, Dur) * 12) + erlang:element(3, Dur),
Day_shift = (erlang:element(4, Dur) * 7) + erlang:element(5, Dur),
{Us, _} = erlang:element(9, Dur),
{Y, M, D, H, Min, S, Microsecond} = calendar@iso:shift_naive_datetime(
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(12, Dt),
Month_shift,
Day_shift,
((erlang:element(6, Dur) * 3600) + (erlang:element(7, Dur) * 60)) + erlang:element(
8,
Dur
),
Us
),
new(
Y,
M,
D,
H,
Min,
S,
erlang:element(8, Dt),
erlang:element(9, Dt),
erlang:element(10, Dt),
erlang:element(11, Dt),
Microsecond,
erlang:element(13, Dt)
).
-file("src/calendar/datetime.gleam", 657).
?DOC(" Returns the given datetime with the microsecond field truncated to the given precision.\n").
-spec truncate(date_time(), integer()) -> date_time().
truncate(Dt, Precision) ->
{Ms, _} = erlang:element(12, Dt),
Truncated_ms = case Precision of
0 ->
0;
1 ->
(Ms div 100000) * 100000;
2 ->
(Ms div 10000) * 10000;
3 ->
(Ms div 1000) * 1000;
4 ->
(Ms div 100) * 100;
5 ->
(Ms div 10) * 10;
_ ->
Ms
end,
{date_time,
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(8, Dt),
erlang:element(9, Dt),
erlang:element(10, Dt),
erlang:element(11, Dt),
{Truncated_ms, Precision},
erlang:element(13, Dt)}.
-file("src/calendar/datetime.gleam", 686).
?DOC(" Converts the given `datetime` from its calendar to the given `calendar`.\n").
-spec convert(date_time(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
convert(Dt, Target_calendar) ->
case erlang:element(13, Dt) =:= Target_calendar of
true ->
{ok, Dt};
false ->
{ok,
{date_time,
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(8, Dt),
erlang:element(9, Dt),
erlang:element(10, Dt),
erlang:element(11, Dt),
erlang:element(12, Dt),
Target_calendar}}
end.
-file("src/calendar/datetime.gleam", 712).
?DOC(" Creates a DateTime from Gregorian seconds (seconds since 0000-01-01 00:00:00 UTC).\n").
-spec from_gregorian_seconds(integer(), {integer(), integer()}, binary()) -> {ok,
date_time()} |
{error, date_time_error()}.
from_gregorian_seconds(Seconds, Microsecond, Calendar) ->
{Ms, Precision} = Microsecond,
Iso_days = calendar@iso:gregorian_seconds_to_iso_days(Seconds, Ms),
{Year, Month, Day, Hour, Minute, Second, {Us, _}} = calendar@iso:naive_datetime_from_iso_days(
Iso_days
),
new(
Year,
Month,
Day,
Hour,
Minute,
Second,
<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0,
{Us, Precision},
Calendar
).
-file("src/calendar/datetime.gleam", 739).
?DOC(
" Converts a DateTime to Gregorian seconds (seconds since 0000-01-01 00:00:00 UTC).\n"
" Returns #(gregorian_seconds, microseconds).\n"
).
-spec to_gregorian_seconds(date_time()) -> {integer(), integer()}.
to_gregorian_seconds(Dt) ->
{Ms, _} = erlang:element(12, Dt),
Iso_days = calendar@iso:naive_datetime_to_iso_days(
erlang:element(2, Dt),
erlang:element(3, Dt),
erlang:element(4, Dt),
erlang:element(5, Dt),
erlang:element(6, Dt),
erlang:element(7, Dt),
erlang:element(12, Dt)
),
{Days, {Day_fraction_us, _}} = Iso_days,
Total_offset = erlang:element(10, Dt) + erlang:element(11, Dt),
Seconds_in_day = Day_fraction_us div 1000000,
Total_seconds = ((Days * 86400) + Seconds_in_day) - Total_offset,
{Total_seconds, Ms}.
-file("src/calendar/datetime.gleam", 761).
-spec convert_to_seconds(integer(), time_unit()) -> integer().
convert_to_seconds(Value, Unit) ->
case Unit of
second ->
Value;
millisecond ->
Value div 1000;
microsecond ->
Value div 1000000;
nanosecond ->
Value div 1000000000;
native ->
Value div 1000000000
end.
-file("src/calendar/datetime.gleam", 427).
?DOC(" Converts a Unix timestamp to a DateTime.\n").
-spec from_unix(integer(), time_unit(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
from_unix(Timestamp, Unit, _) ->
Seconds = convert_to_seconds(Timestamp, Unit),
case calendar@naive_datetime:from_timestamp(Seconds) of
{error, _} ->
{error, invalid_date_time};
{ok, Ndt} ->
{ok,
from_naive_datetime(
Ndt,
<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0
)}
end.
-file("src/calendar/datetime.gleam", 364).
?DOC(" Returns the current datetime in UTC with specified precision and calendar.\n").
-spec utc_now_with_precision(time_unit(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
utc_now_with_precision(Time_unit, Calendar) ->
Timestamp = os:system_time(),
case from_unix(Timestamp, Time_unit, Calendar) of
{ok, Dt} ->
{ok, Dt};
{error, _} ->
new(
1970,
1,
1,
0,
0,
0,
<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0,
{0, 0},
Calendar
)
end.
-file("src/calendar/datetime.gleam", 359).
?DOC(" Returns the current datetime in UTC.\n").
-spec utc_now() -> {ok, date_time()} | {error, date_time_error()}.
utc_now() ->
utc_now_with_precision(native, <<"Calendar.ISO"/utf8>>).
-file("src/calendar/datetime.gleam", 492).
?DOC(" Returns the current datetime in a specific timezone.\n").
-spec now(binary(), binary(), integer(), integer()) -> {ok, date_time()} |
{error, date_time_error()}.
now(Time_zone, Zone_abbr, Utc_offset, Std_offset) ->
case utc_now() of
{ok, Utc_dt} ->
shift_zone(Utc_dt, Time_zone, Zone_abbr, Utc_offset, Std_offset);
{error, E} ->
{error, E}
end.
-file("src/calendar/datetime.gleam", 607).
?DOC(" Adds an amount of time to a DateTime in the given unit.\n").
-spec add(date_time(), integer(), time_unit()) -> {ok, date_time()} |
{error, date_time_error()}.
add(Dt, Amount, Unit) ->
Seconds = convert_to_seconds(Amount, Unit),
add_seconds(Dt, Seconds).
-file("src/calendar/datetime.gleam", 772).
-spec convert_from_seconds(integer(), time_unit()) -> integer().
convert_from_seconds(Seconds, Unit) ->
case Unit of
second ->
Seconds;
millisecond ->
Seconds * 1000;
microsecond ->
Seconds * 1000000;
nanosecond ->
Seconds * 1000000000;
native ->
Seconds * 1000000000
end.
-file("src/calendar/datetime.gleam", 442).
?DOC(" Converts a DateTime to Unix timestamp.\n").
-spec to_unix(date_time(), time_unit()) -> integer().
to_unix(Dt, Unit) ->
Utc_seconds = to_utc_timestamp(Dt),
convert_from_seconds(Utc_seconds, Unit).
-file("src/calendar/datetime.gleam", 599).
?DOC(" Calculates the difference between two datetimes in the specified unit.\n").
-spec diff(date_time(), date_time(), time_unit()) -> integer().
diff(Dt1, Dt2, Unit) ->
Timestamp1 = to_utc_timestamp(Dt1),
Timestamp2 = to_utc_timestamp(Dt2),
Diff_seconds = Timestamp1 - Timestamp2,
convert_from_seconds(Diff_seconds, Unit).
-file("src/calendar/datetime.gleam", 783).
-spec format_offset_basic(integer()) -> binary().
format_offset_basic(Total_offset) ->
case Total_offset =:= 0 of
true ->
<<"+0000"/utf8>>;
false ->
Sign = case Total_offset >= 0 of
true ->
<<"+"/utf8>>;
false ->
<<"-"/utf8>>
end,
Abs_offset = case Total_offset < 0 of
true ->
- Total_offset;
false ->
Total_offset
end,
Hours = Abs_offset div 3600,
Minutes = (Abs_offset rem 3600) div 60,
<<<<Sign/binary,
(pad_left(erlang:integer_to_binary(Hours), 2, <<"0"/utf8>>))/binary>>/binary,
(pad_left(erlang:integer_to_binary(Minutes), 2, <<"0"/utf8>>))/binary>>
end.
-file("src/calendar/datetime.gleam", 527).
?DOC(" Converts DateTime to basic ISO 8601 format.\n").
-spec to_iso8601_basic(date_time()) -> binary().
to_iso8601_basic(Dt) ->
Date_part = <<<<(pad_left(
erlang:integer_to_binary(erlang:element(2, Dt)),
4,
<<"0"/utf8>>
))/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(3, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(4, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
Time_part = <<<<(pad_left(
erlang:integer_to_binary(erlang:element(5, Dt)),
2,
<<"0"/utf8>>
))/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(6, Dt)),
2,
<<"0"/utf8>>
))/binary>>/binary,
(pad_left(
erlang:integer_to_binary(erlang:element(7, Dt)),
2,
<<"0"/utf8>>
))/binary>>,
{Ms, Precision} = erlang:element(12, Dt),
Microsecond_part = case (Ms =:= 0) orelse (Precision =:= 0) of
true ->
<<""/utf8>>;
false ->
<<"."/utf8, (pad_microseconds(Ms, Precision))/binary>>
end,
Offset_part = case erlang:element(8, Dt) =:= <<"Etc/UTC"/utf8>> of
true ->
<<"Z"/utf8>>;
false ->
format_offset_basic(erlang:element(10, Dt) + erlang:element(11, Dt))
end,
<<<<<<<<Date_part/binary, "T"/utf8>>/binary, Time_part/binary>>/binary,
Microsecond_part/binary>>/binary,
Offset_part/binary>>.
-file("src/calendar/datetime.gleam", 519).
?DOC(" Converts DateTime to ISO 8601 with format option.\n").
-spec to_iso8601_with_format(date_time(), date_time_format()) -> binary().
to_iso8601_with_format(Dt, Format) ->
case Format of
extended ->
to_iso8601(Dt);
basic ->
to_iso8601_basic(Dt)
end.
-file("src/calendar/datetime.gleam", 976).
-spec parse_offset_hhmm(binary()) -> {ok, integer()} | {error, nil}.
parse_offset_hhmm(S) ->
case gleam_stdlib:contains_string(S, <<":"/utf8>>) of
true ->
case gleam@string:split(S, <<":"/utf8>>) of
[H_str, M_str] ->
case {gleam_stdlib:parse_int(H_str),
gleam_stdlib:parse_int(M_str)} of
{{ok, H}, {ok, M}} ->
{ok, (H * 3600) + (M * 60)};
{_, _} ->
{error, nil}
end;
_ ->
{error, nil}
end;
false ->
case string:length(S) of
4 ->
case {gleam_stdlib:parse_int(gleam@string:slice(S, 0, 2)),
gleam_stdlib:parse_int(gleam@string:slice(S, 2, 2))} of
{{ok, H@1}, {ok, M@1}} ->
{ok, (H@1 * 3600) + (M@1 * 60)};
{_, _} ->
{error, nil}
end;
2 ->
case gleam_stdlib:parse_int(S) of
{ok, H@2} ->
{ok, H@2 * 3600};
{error, _} ->
{error, nil}
end;
_ ->
{error, nil}
end
end.
-file("src/calendar/datetime.gleam", 904).
-spec split_time_at_offset(binary(), binary()) -> {ok, {binary(), integer()}} |
{error, nil}.
split_time_at_offset(S, Sep) ->
case gleam@string:split_once(S, Sep) of
{ok, {Time_part, Offset_part}} ->
case parse_offset_hhmm(Offset_part) of
{ok, Seconds} ->
Sign = case Sep of
<<"+"/utf8>> ->
1;
_ ->
-1
end,
{ok, {Time_part, Sign * Seconds}};
{error, _} ->
{error, nil}
end;
{error, _} ->
{error, nil}
end.
-file("src/calendar/datetime.gleam", 951).
-spec try_5_char_negative_offset(binary(), integer()) -> {ok,
{binary(), integer()}} |
{error, nil}.
try_5_char_negative_offset(S, Len) ->
case Len >= 5 of
false ->
{error, nil};
true ->
Maybe = gleam@string:slice(S, Len - 5, 5),
case gleam@string:first(Maybe) of
{ok, <<"-"/utf8>>} ->
Offset_part = gleam@string:drop_start(Maybe, 1),
case parse_offset_hhmm(Offset_part) of
{ok, Seconds} ->
Time_part = gleam@string:slice(S, 0, Len - 5),
{ok, {Time_part, - Seconds}};
{error, _} ->
{error, nil}
end;
_ ->
{error, nil}
end
end.
-file("src/calendar/datetime.gleam", 922).
-spec split_time_at_negative_offset(binary()) -> {ok, {binary(), integer()}} |
{error, nil}.
split_time_at_negative_offset(S) ->
Len = string:length(S),
case Len >= 6 of
false ->
{error, nil};
true ->
Maybe = gleam@string:slice(S, Len - 6, 6),
case gleam@string:first(Maybe) of
{ok, <<"-"/utf8>>} ->
Offset_part = gleam@string:drop_start(Maybe, 1),
case parse_offset_hhmm(Offset_part) of
{ok, Seconds} ->
Time_part = gleam@string:slice(S, 0, Len - 6),
{ok, {Time_part, - Seconds}};
{error, _} ->
try_5_char_negative_offset(S, Len)
end;
_ ->
try_5_char_negative_offset(S, Len)
end
end.
-file("src/calendar/datetime.gleam", 857).
-spec parse_time_with_tz(binary(), binary()) -> {ok,
{calendar@time:time(), {binary(), binary(), integer(), integer()}}} |
{error, date_time_error()}.
parse_time_with_tz(Time_string, _) ->
case gleam_stdlib:string_ends_with(Time_string, <<"Z"/utf8>>) of
true ->
Time_part = gleam@string:drop_end(Time_string, 1),
case calendar@time:from_iso8601(Time_part) of
{error, _} ->
{error, invalid_format};
{ok, Parsed_time} ->
{ok,
{Parsed_time,
{<<"Etc/UTC"/utf8>>, <<"UTC"/utf8>>, 0, 0}}}
end;
false ->
case split_time_at_offset(Time_string, <<"+"/utf8>>) of
{ok, {Time_part@1, Offset_seconds}} ->
case calendar@time:from_iso8601(Time_part@1) of
{error, _} ->
{error, invalid_format};
{ok, Parsed_time@1} ->
{ok,
{Parsed_time@1,
{<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
Offset_seconds,
0}}}
end;
{error, _} ->
case split_time_at_negative_offset(Time_string) of
{ok, {Time_part@2, Offset_seconds@1}} ->
case calendar@time:from_iso8601(Time_part@2) of
{error, _} ->
{error, invalid_format};
{ok, Parsed_time@2} ->
{ok,
{Parsed_time@2,
{<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
Offset_seconds@1,
0}}}
end;
{error, _} ->
case calendar@time:from_iso8601(Time_string) of
{error, _} ->
{error, invalid_format};
{ok, Parsed_time@3} ->
{ok,
{Parsed_time@3,
{<<"Etc/UTC"/utf8>>,
<<"UTC"/utf8>>,
0,
0}}}
end
end
end
end.
-file("src/calendar/datetime.gleam", 820).
-spec try_parse_datetime_with_separator(binary(), binary(), binary()) -> {ok,
date_time()} |
{error, date_time_error()}.
try_parse_datetime_with_separator(String, Separator, Calendar) ->
case gleam@string:split(String, Separator) of
[Date_part, Time_part] ->
case calendar@date:from_iso8601_with_calendar(Date_part, Calendar) of
{error, _} ->
{error, invalid_format};
{ok, Parsed_date} ->
case parse_time_with_tz(Time_part, Calendar) of
{error, _} ->
{error, invalid_format};
{ok, {Parsed_time, Tz_info}} ->
{Time_zone, Zone_abbr, Utc_offset, Std_offset} = Tz_info,
new(
erlang:element(2, Parsed_date),
erlang:element(3, Parsed_date),
erlang:element(4, Parsed_date),
erlang:element(2, Parsed_time),
erlang:element(3, Parsed_time),
erlang:element(4, Parsed_time),
Time_zone,
Zone_abbr,
Utc_offset,
Std_offset,
erlang:element(5, Parsed_time),
Calendar
)
end
end;
_ ->
{error, invalid_format}
end.
-file("src/calendar/datetime.gleam", 805).
-spec parse_iso8601_datetime(binary(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
parse_iso8601_datetime(String, Calendar) ->
case try_parse_datetime_with_separator(String, <<"T"/utf8>>, Calendar) of
{ok, Datetime} ->
{ok, Datetime};
{error, _} ->
case try_parse_datetime_with_separator(
String,
<<" "/utf8>>,
Calendar
) of
{ok, Datetime@1} ->
{ok, Datetime@1};
{error, _} ->
{error, invalid_format}
end
end.
-file("src/calendar/datetime.gleam", 506).
?DOC(" Parses an ISO 8601 datetime string.\n").
-spec from_iso8601(binary()) -> {ok, date_time()} | {error, date_time_error()}.
from_iso8601(String) ->
parse_iso8601_datetime(String, <<"Calendar.ISO"/utf8>>).
-file("src/calendar/datetime.gleam", 511).
?DOC(" Parses an ISO 8601 datetime string with specified calendar.\n").
-spec from_iso8601_with_calendar(binary(), binary()) -> {ok, date_time()} |
{error, date_time_error()}.
from_iso8601_with_calendar(String, Calendar) ->
parse_iso8601_datetime(String, Calendar).