-module(tempo@datetime). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/tempo/datetime.gleam"). -export([new/3, from_string/1, literal/1, from_unix_micro/1, from_timestamp/1, from_string_fast/1, to_string/1, to_calendar_parts/1, parse/2, parse_any/1, describe_parse_error/1, to_utc/1, format/2, to_unix_micro/1, to_timestamp/1, from_unix_seconds/1, apply_offset/1, to_unix_seconds/1, from_unix_milli/1, to_unix_milli/1, from_dynamic_string/1, from_dynamic_unix_utc/1, from_dynamic_unix_milli_utc/1, from_dynamic_unix_micro_utc/1, get_date/1, get_calendar_date/1, get_time/1, get_calendar_time_of_day/1, get_offset/1, drop_offset/1, drop_time/1, to_offset/2, to_local_imprecise/1, to_local_time_imprecise/1, to_local_date_imprecise/1, to_timezone/2, get_timezone_name/1, compare/2, is_earlier/2, is_earlier_or_equal/2, is_equal/2, is_later/2, is_later_or_equal/2, difference/2, as_period/2, add/2, subtract/2, time_left_in_day/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Functions to use with the `DateTime` type in Tempo.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " import tempo/datetime\n" " import snag\n" "\n" " pub fn main() {\n" " datetime.literal(\"2024-12-25T06:00:00+05:00\")\n" " |> datetime.format(\"ddd @ h:mm A, Z\")\n" " // -> \"Fri @ 6:00 AM, +05:00\"\n" "\n" " datetime.parse(\"06:21:2024 23:17:07.123Z\", \"MM:DD:YYYY HH:mm:ss.SSSZ\")\n" " |> snag.map_error(datetime.describe_parse_error)\n" " |> result.map(datetime.to_string)\n" " // -> Ok(\"2024-06-21T23:17:07.123Z\")\n" " }\n" " ```\n" "\n" " ```gleam\n" " import gleam/list\n" " import tempo/datetime\n" " import tempo/period\n" "\n" " pub fn get_every_friday_between(datetime1, datetime2) {\n" " period.new(datetime1, datetime2)\n" " |> period.comprising_dates\n" " |> list.filter(fn(date) {\n" " date |> date.to_day_of_week == date.Fri\n" " })\n" " // -> [\"2024-06-21\", \"2024-06-28\", \"2024-07-05\"]\n" " }\n" " ```\n" ). -file("src/tempo/datetime.gleam", 68). ?DOC( " Create a new datetime from a date, time, and offset.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.new(\n" " date.literal(\"2024-06-13\"),\n" " time.literal(\"23:04:00.009\"),\n" " offset.literal(\"+10:00\"),\n" " )\n" " // -> datetime.literal(\"2024-06-13T23:04:00.009+10:00\")\n" " ```\n" ). -spec new(tempo:date(), tempo:time(), tempo:offset()) -> tempo:date_time(). new(Date, Time, Offset) -> tempo:datetime(Date, Time, Offset). -file("src/tempo/datetime.gleam", 180). -spec parse_offset(bitstring()) -> {ok, tempo:offset()} | {error, tempo@error:offset_parse_error()}. parse_offset(Input) -> case gtempo@internal:take_offset_minutes(Input) of {ok, {Minutes, <<>>}} -> _pipe = tempo:validate_offset(tempo:offset(Minutes)), gleam@result:replace_error( _pipe, {offset_out_of_bounds, gtempo@internal:remaining_string(Input)} ); _ -> {error, {offset_invalid_format, gtempo@internal:remaining_string(Input)}} end. -file("src/tempo/datetime.gleam", 115). ?DOC( " Parses a datetime string in the format `YYYY-MM-DDThh:mm:ss.sTZD`,\n" " `YYYYMMDDThhmmss.sTZD`, `YYYY-MM-DD hh:mm:ss.sTZD`,\n" " `YYYYMMDD hhmmss.sTZD`, `YYYY-MM-DD`, `YYYY-M-D`, `YYYY/MM/DD`,\n" " `YYYY/M/D`, `YYYY.MM.DD`, `YYYY.M.D`, `YYYY_MM_DD`, `YYYY_M_D`,\n" " `YYYY MM DD`, `YYYY M D`, or `YYYYMMDD`.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.from_string(\"20240613T230400.009+00:00\")\n" " // -> datetime.literal(\"2024-06-13T23:04:00.009Z\")\n" " ```\n" ). -spec from_string(binary()) -> {ok, tempo:date_time()} | {error, tempo@error:date_time_parse_error()}. from_string(Datetime) -> Input = gleam_stdlib:identity(Datetime), gleam@result:'try'( begin _pipe = gtempo@internal:take_date_parts(Input), gleam@result:replace_error( _pipe, {date_time_invalid_format, Datetime} ) end, fun(_use0) -> {Date_parts, After_date} = _use0, gleam@result:'try'( begin _pipe@1 = gtempo@internal:accept_datetime_delimiter( After_date ), gleam@result:replace_error( _pipe@1, {date_time_invalid_format, Datetime} ) end, fun(Before_time) -> gleam@result:'try'( begin _pipe@2 = gtempo@internal:take_time_parts( Before_time ), gleam@result:replace_error( _pipe@2, {date_time_invalid_format, Datetime} ) end, fun(_use0@1) -> {Time_parts, After_time} = _use0@1, gleam@result:'try'( begin _pipe@3 = tempo@date:from_tuple(Date_parts), gleam@result:map_error( _pipe@3, fun(Error) -> {date_time_date_parse_error, Datetime, {date_out_of_bounds, gtempo@internal:taken_string( Input, After_date ), Error}} end ) end, fun(Date) -> {Hour, Minute, Second, Microsecond} = Time_parts, gleam@result:'try'( begin _pipe@4 = tempo:validate_time( Hour, Minute, Second, Microsecond ), gleam@result:map_error( _pipe@4, fun(Error@1) -> {date_time_time_parse_error, Datetime, {time_out_of_bounds, gtempo@internal:taken_string( Before_time, After_time ), Error@1}} end ) end, fun(Time) -> gleam@result:map( begin _pipe@5 = parse_offset( After_time ), gleam@result:map_error( _pipe@5, fun(Error@2) -> case After_time of <<>> -> {date_time_invalid_format, Datetime}; _ -> {date_time_offset_parse_error, Datetime, Error@2} end end ) end, fun(Offset) -> new(Date, Time, Offset) end ) end ) end ) end ) end ) end ). -file("src/tempo/datetime.gleam", 90). ?DOC( " Create a new datetime value from a string literal, but will panic if\n" " the string is invalid. Accepted formats are `YYYY-MM-DDThh:mm:ss.sTZD` or\n" " `YYYYMMDDThhmmss.sTZD`\n" "\n" " Useful for declaring datetime literals that you know are valid within your\n" " program.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-13T23:04:00.009+10:00\")\n" " |> datetime.to_string\n" " // -> \"2024-06-13T23:04:00.009+10:00\"\n" " ```\n" ). -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>>, file => <>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 94}); {error, {date_time_date_parse_error, _, _}} -> erlang:error(#{gleam_error => panic, message => <<"Invalid date in datetime literal value"/utf8>>, file => <>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 96}); {error, {date_time_time_parse_error, _, _}} -> erlang:error(#{gleam_error => panic, message => <<"Invalid time in datetime literal value"/utf8>>, file => <>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 98}); {error, _} -> erlang:error(#{gleam_error => panic, message => <<"Invalid datetime literal"/utf8>>, file => <>, module => <<"tempo/datetime"/utf8>>, function => <<"literal"/utf8>>, line => 99}) end. -file("src/tempo/datetime.gleam", 472). ?DOC( " Returns the UTC datetime of a unix timestamp in microseconds.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.from_unix_micro(1_718_629_314_334_734)\n" " // -> datetime.literal(\"2024-06-17T13:01:54.334734Z\")\n" " ```\n" ). -spec from_unix_micro(integer()) -> tempo:date_time(). from_unix_micro(Unix_ts) -> new( tempo@date:from_unix_micro(Unix_ts), tempo@time:from_unix_micro(Unix_ts), {offset, 0} ). -file("src/tempo/datetime.gleam", 383). ?DOC(" Converts a core gleam time timestamp type to a datetime.\n"). -spec from_timestamp(gleam@time@timestamp:timestamp()) -> tempo:date_time(). from_timestamp(Timestamp) -> {Seconds, Nanoseconds} = gleam@time@timestamp:to_unix_seconds_and_nanoseconds( Timestamp ), from_unix_micro((Seconds * 1000000) + (Nanoseconds div 1000)). -file("src/tempo/datetime.gleam", 195). -spec from_string_fast(binary()) -> {ok, tempo:date_time()} | {error, tempo@error:date_time_parse_error()}. from_string_fast(Datetime) -> _pipe = gleam@time@timestamp:parse_rfc3339(Datetime), _pipe@1 = gleam@result:map(_pipe, fun from_timestamp/1), gleam@result:replace_error(_pipe@1, {date_time_invalid_format, Datetime}). -file("src/tempo/datetime.gleam", 212). ?DOC( " Returns a string representation of a datetime value in the ISO 8601\n" " format with millisecond precision. If a different precision is needed,\n" " use the `format` function. If serializing to send outside of Gleam and then\n" " parse back into a datetime value, use the `serialize` function.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.to_string(my_datetime)\n" " // -> \"2024-06-21T05:22:22.009534Z\"\n" " ```\n" ). -spec to_string(tempo:date_time()) -> binary(). to_string(Datetime) -> tempo:datetime_to_string(Datetime). -file("src/tempo/datetime.gleam", 229). ?DOC( " Returns the date, time, and offset parts of a datetime as a tuple of\n" " `gleam_time` types. This is useful for interop and accessing the underlying\n" " values of a datetime.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(\n" " calendar.Date(year:, month:, day:),\n" " calendar.TimeOfDay(hour:, minute:, second:, nanosecond:),\n" " offset,\n" " ) = datetime.to_calendar_parts(my_datetime)\n" " ```\n" ). -spec to_calendar_parts(tempo:date_time()) -> {gleam@time@calendar:date(), gleam@time@calendar:time_of_day(), gleam@time@duration:duration()}. to_calendar_parts(Datetime) -> {tempo:date_to_calendar_date(erlang:element(2, Datetime)), tempo:time_to_calendar_time_of_day(erlang:element(3, Datetime)), tempo:offset_to_duration(erlang:element(4, Datetime))}. -file("src/tempo/datetime.gleam", 272). ?DOC( " Parses a datetime string in the provided format. Always prefer using\n" " this over `parse_any`. All parsed formats must have all parts of a\n" " datetime (date, time, offset). Use the other modules for parsing lesser\n" " date time values.\n" "\n" " Values can be escaped by putting brackets around them, like \"[Hello!] YYYY\".\n" "\n" " Available directives: YY (two-digit year), YYYY (four-digit year), M (month),\n" " MM (two-digit month), MMM (short month name), MMMM (full month name),\n" " D (day of the month), DD (two-digit day of the month),\n" " H (hour), HH (two-digit hour), h (12-hour clock hour), hh\n" " (two-digit 12-hour clock hour), m (minute), mm (two-digit minute),\n" " s (second), ss (two-digit second), SSS (millisecond), SSSS (microsecond),\n" " Z (offset from UTC), ZZ (offset from UTC with no \":\"),\n" " z (short offset from UTC \"-04\", \"Z\"), zz (full offset from UTC as \"-04:00\"\n" " or \"Z\" if UTC), A (AM/PM), a (am/pm).\n" "\n" " ## Example\n" "\n" " ```gleam\n" " datetime.parse(\"2024/06/08, 13:42:11, -04:00\", \"YYYY/MM/DD, HH:mm:ss, Z\")\n" " // -> Ok(datetime.literal(\"2024-06-08T13:42:11-04\"))\n" " ```\n" "\n" " ```gleam\n" " datetime.parse(\"January 13, 2024. 3:42:11Z\", \"MMMM DD, YYYY. H:mm:ssz\")\n" " // -> Ok(datetime.literal(\"2024-01-13T03:42:11Z\"))\n" " ```\n" "\n" " ```gleam\n" " datetime.parse(\"Hi! 2024 11 13 12 2 am Z\", \"[Hi!] YYYY M D h m a z\")\n" " // -> Ok(datetime.literal(\"2024-11-13T00:02:00Z\"))\n" " ```\n" ). -spec parse(binary(), tempo:date_time_format()) -> {ok, tempo:date_time()} | {error, tempo@error:date_time_parse_error()}. parse(Str, Format) -> Format_str = tempo:get_datetime_format_str(Format), gleam@result:'try'( begin _pipe = tempo:consume_format(Str, Format_str), gleam@result:map_error( _pipe, fun(Field@0) -> {date_time_invalid_format, Field@0} end ) end, fun(Parts) -> gleam@result:'try'( begin _pipe@1 = tempo:find_date(Parts), gleam@result:map_error( _pipe@1, fun(_capture) -> {date_time_date_parse_error, Str, _capture} end ) end, fun(Date) -> gleam@result:'try'( begin _pipe@2 = tempo:find_time(Parts), gleam@result:map_error( _pipe@2, fun(_capture@1) -> {date_time_time_parse_error, Str, _capture@1} end ) end, fun(Time) -> gleam@result:'try'( begin _pipe@3 = tempo:find_offset(Parts), gleam@result:map_error( _pipe@3, fun(_capture@2) -> {date_time_offset_parse_error, Str, _capture@2} end ) end, fun(Offset) -> {ok, new(Date, Time, Offset)} end ) end ) end ) end ). -file("src/tempo/datetime.gleam", 316). ?DOC( " Tries to parse a given date string without a known format. It will not\n" " parse two digit years and will assume the month always comes before the\n" " day in a date.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " parse_any.parse_any(\"2024.06.21 01:32 PM -0400\")\n" " // -> Ok(datetime.literal(\"2024-06-21T13:32:00-04:00\"))\n" " ```\n" "\n" " ```gleam\n" " parse_any.parse_any(\"2024.06.21 01:32 PM\")\n" " // -> Error(tempo.ParseMissingOffset)\n" " ```\n" ). -spec parse_any(binary()) -> {ok, tempo:date_time()} | {error, tempo@error:date_time_parse_error()}. parse_any(Str) -> case tempo:parse_any(Str) of {{some, Date}, {some, Time}, {some, Offset}} -> {ok, new(Date, Time, Offset)}; {_, _, none} -> {error, {date_time_invalid_format, <<"Unable to find offset in "/utf8, Str/binary>>}}; {_, none, _} -> {error, {date_time_invalid_format, <<"Unable to find time in "/utf8, Str/binary>>}}; {none, _, _} -> {error, {date_time_invalid_format, <<"Unable to find date in "/utf8, Str/binary>>}} end. -file("src/tempo/datetime.gleam", 340). ?DOC( " Converts a datetime parse error to a human readable error message.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " datetime.parse(\"13:42:11.314-04:00\", \"YYYY-MM-DDTHH:mm:ss.SSSZ\")\n" " |> snag.map_error(with: datetime.describe_parse_error)\n" " // -> snag.error(\"Invalid date format in datetime: 13:42:11.314-04:00\")\n" ). -spec describe_parse_error(tempo@error:date_time_parse_error()) -> binary(). describe_parse_error(Error) -> tempo@error:describe_datetime_parse_error(Error). -file("src/tempo/datetime.gleam", 782). ?DOC( " Converts a datetime to the equivalent UTC time.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T05:36:11.195-04:00\")\n" " |> datetime.to_utc\n" " // -> datetime.literal(\"2024-06-21T09:36:11.195Z\")\n" " ```\n" ). -spec to_utc(tempo:date_time()) -> tempo:date_time(). to_utc(Datetime) -> tempo:datetime_to_utc(Datetime). -file("src/tempo/datetime.gleam", 371). ?DOC( " Formats a datetime value into a string using the provided format.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T13:42:11.314-04:00\")\n" " |> datetime.format(tempo.Custom(\"ddd @ h:mm A (z)\"))\n" " // -> \"Fri @ 1:42 PM (-04)\"\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-03T09:02:01-04:00\")\n" " |> datetime.format(tempo.Custom(\"YY YYYY M MM MMM MMMM D DD d dd ddd\"))\n" " // -----------:---------------> \"24 2024 6 06 Jun June 3 03 1 Mo Mon\"\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-03T09:02:01.014920202-00:00\")\n" " |> datetime.format(tempo.Custom(\"dddd SSS SSSS SSSSS Z ZZ z\"))\n" " // -> \"Monday 014 014920 014920202 -00:00 -0000 Z\"\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-03T13:02:01-04:00\")\n" " |> datetime.format(tempo.Custom(\"H HH h hh m mm s ss a A [An ant]\"))\n" " // --------------------------> \"13 13 1 01 2 02 1 01 pm PM An ant\"\n" " ```\n" ). -spec format(tempo:date_time(), tempo:date_time_format()) -> binary(). format(Datetime, Format) -> _pipe = case Format of h_t_t_p -> to_utc(Datetime); _ -> Datetime end, tempo:datetime_format(_pipe, Format). -file("src/tempo/datetime.gleam", 485). ?DOC( " Returns the UTC unix timestamp in microseconds of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-17T13:01:54.334734Z\")\n" " |> datetime.to_unix_micro\n" " // -> 1_718_629_314_334_734\n" " ```\n" ). -spec to_unix_micro(tempo:date_time()) -> integer(). to_unix_micro(Datetime) -> tempo:datetime_to_unix_micro(Datetime). -file("src/tempo/datetime.gleam", 391). ?DOC(" Converts a datetime to a core gleam time timestamp type.\n"). -spec to_timestamp(tempo:date_time()) -> gleam@time@timestamp:timestamp(). to_timestamp(Datetime) -> Unix_us = to_unix_micro(Datetime), Seconds = Unix_us div 1000000, Nanoseconds = (Unix_us rem 1000000) * 1000, gleam@time@timestamp:from_unix_seconds_and_nanoseconds(Seconds, Nanoseconds). -file("src/tempo/datetime.gleam", 407). ?DOC( " Returns the UTC datetime of a unix timestamp.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.from_unix_seconds(1_718_829_191)\n" " // -> datetime.literal(\"2024-06-17T12:59:51Z\")\n" " ```\n" ). -spec from_unix_seconds(integer()) -> tempo:date_time(). from_unix_seconds(Unix_ts) -> new( tempo@date:from_unix_seconds(Unix_ts), tempo@time:from_unix_seconds(Unix_ts), {offset, 0} ). -file("src/tempo/datetime.gleam", 769). ?DOC( " Applies the offset of a datetime to the date and time values, resulting\n" " in a new naive datetime value that represents the original datetime in\n" " UTC time.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T05:36:11.195-04:00\")\n" " |> datetime.apply_offset\n" " // -> naive_datetime.literal(\"2024-06-21T09:36:11.195\")\n" " ```\n" ). -spec apply_offset(tempo:date_time()) -> tempo:naive_date_time(). apply_offset(Datetime) -> tempo:datetime_apply_offset(Datetime). -file("src/tempo/datetime.gleam", 424). ?DOC( " Returns the UTC unix timestamp of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-17T12:59:51Z\")\n" " |> datetime.to_unix_seconds\n" " // -> 1_718_829_191\n" " ```\n" ). -spec to_unix_seconds(tempo:date_time()) -> integer(). to_unix_seconds(Datetime) -> Utc_dt = begin _pipe = Datetime, apply_offset(_pipe) end, tempo@date:to_unix_seconds( begin _pipe@1 = Utc_dt, tempo:naive_datetime_get_date(_pipe@1) end ) + (tempo:time_to_microseconds( begin _pipe@2 = Utc_dt, tempo:naive_datetime_get_time(_pipe@2) end ) div 1000000). -file("src/tempo/datetime.gleam", 442). ?DOC( " Returns the UTC datetime of a unix timestamp in milliseconds.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.from_unix_milli(1_718_629_314_334)\n" " // -> datetime.literal(\"2024-06-17T13:01:54.334Z\")\n" " ```\n" ). -spec from_unix_milli(integer()) -> tempo:date_time(). from_unix_milli(Unix_ts) -> new( tempo@date:from_unix_milli(Unix_ts), tempo@time:from_unix_milli(Unix_ts), {offset, 0} ). -file("src/tempo/datetime.gleam", 455). ?DOC( " Returns the UTC unix timestamp in milliseconds of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-17T13:01:54.334Z\")\n" " |> datetime.to_unix_milli\n" " // -> 1_718_629_314_334\n" " ```\n" ). -spec to_unix_milli(tempo:date_time()) -> integer(). to_unix_milli(Datetime) -> Utc_dt = begin _pipe = Datetime, apply_offset(_pipe) end, tempo@date:to_unix_milli( begin _pipe@1 = Utc_dt, tempo:naive_datetime_get_date(_pipe@1) end ) + (tempo:time_to_microseconds( begin _pipe@2 = Utc_dt, tempo:naive_datetime_get_time(_pipe@2) end ) div 1000). -file("src/tempo/datetime.gleam", 511). ?DOC( " Checks if a dynamic value is a valid datetime string, and returns the\n" " datetime if it is.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " dynamic.string(\"2024-06-13T13:42:11.195Z\")\n" " |> datetime.from_dynamic_string\n" " // -> Ok(datetime.literal(\"2024-06-13T13:42:11.195Z\"))\n" " ```\n" "\n" " ```gleam\n" " dynamic.string(\"24-06-13,13:42:11.195\")\n" " |> datetime.from_dynamic_string\n" " // -> Error([\n" " // decode.DecodeError(\n" " // expected: \"tempo.DateTime\",\n" " // found: \"Invalid format: 24-06-13,13:42:11.195\",\n" " // path: [],\n" " // ),\n" " // ])\n" " ```\n" ). -spec from_dynamic_string(gleam@dynamic:dynamic_()) -> {ok, tempo:date_time()} | {error, list(gleam@dynamic@decode:decode_error())}. from_dynamic_string(Dynamic_string) -> gleam@result:'try'( begin _pipe = gleam@dynamic@decode:run( Dynamic_string, {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@result:map_error( _pipe, fun(Errs) -> gleam@list:map( Errs, fun(Err) -> {decode_error, erlang:element(2, Err), erlang:element(3, Err), erlang:element(4, Err)} end ) end ) end, fun(Datetime) -> case from_string(Datetime) of {ok, Datetime@1} -> {ok, Datetime@1}; {error, Tempo_error} -> {error, [{decode_error, <<"tempo.DateTime"/utf8>>, case Tempo_error of {date_time_invalid_format, Msg} -> Msg; {date_time_time_parse_error, Msg@1, _} -> Msg@1; {date_time_date_parse_error, Msg@2, _} -> Msg@2; {date_time_offset_parse_error, Msg@3, _} -> Msg@3 end, []}]} end end ). -file("src/tempo/datetime.gleam", 565). ?DOC( " Checks if a dynamic value is a valid unix timestamp in seconds, and\n" " returns the datetime representation if it is.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " dynamic.int(1_718_629_314)\n" " |> datetime.from_dynamic_unix_utc\n" " // -> Ok(datetime.literal(\"2024-06-17T13:01:54Z\"))\n" " ```\n" "\n" " ```gleam\n" " dynamic.string(\"hello\")\n" " |> datetime.from_dynamic_unix_utc\n" " // -> Error([\n" " // decode.DecodeError(\n" " // expected: \"Int\",\n" " // found: \"String\",\n" " // path: [],\n" " // ),\n" " // ])\n" " ```\n" ). -spec from_dynamic_unix_utc(gleam@dynamic:dynamic_()) -> {ok, tempo:date_time()} | {error, list(gleam@dynamic@decode:decode_error())}. from_dynamic_unix_utc(Dynamic_ts) -> gleam@result:map( begin _pipe = gleam@dynamic@decode:run( Dynamic_ts, {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@result:map_error( _pipe, fun(Errs) -> gleam@list:map( Errs, fun(Err) -> {decode_error, erlang:element(2, Err), erlang:element(3, Err), erlang:element(4, Err)} end ) end ) end, fun(Unix_seconds) -> from_unix_seconds(Unix_seconds) end ). -file("src/tempo/datetime.gleam", 604). ?DOC( " Checks if a dynamic value is a valid unix timestamp in milliseconds, and\n" " returns the datetime if it is.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " dynamic.int(1_718_629_314_334)\n" " |> datetime.from_dynamic_unix_milli_utc\n" " // -> Ok(datetime.literal(\"2024-06-17T13:01:54.334Z\"))\n" " ```\n" "\n" " ```gleam\n" " dynamic.string(\"hello\")\n" " |> datetime.from_dynamic_unix_milli_utc\n" " // -> Error([\n" " // decode.DecodeError(\n" " // expected: \"Int\",\n" " // found: \"String\",\n" " // path: [],\n" " // ),\n" " // ])\n" " ```\n" ). -spec from_dynamic_unix_milli_utc(gleam@dynamic:dynamic_()) -> {ok, tempo:date_time()} | {error, list(gleam@dynamic@decode:decode_error())}. from_dynamic_unix_milli_utc(Dynamic_ts) -> gleam@result:map( begin _pipe = gleam@dynamic@decode:run( Dynamic_ts, {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@result:map_error( _pipe, fun(Errs) -> gleam@list:map( Errs, fun(Err) -> {decode_error, erlang:element(2, Err), erlang:element(3, Err), erlang:element(4, Err)} end ) end ) end, fun(Unix_milli) -> from_unix_milli(Unix_milli) end ). -file("src/tempo/datetime.gleam", 643). ?DOC( " Checks if a dynamic value is a valid unix timestamp in microseconds, and\n" " returns the datetime if it is.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " dynamic.int(1_718_629_314_334_734)\n" " |> datetime.from_dynamic_unix_micro_utc\n" " // -> Ok(datetime.literal(\"2024-06-17T13:01:54.334734Z\"))\n" " ```\n" "\n" " ```gleam\n" " dynamic.string(\"hello\")\n" " |> datetime.from_dynamic_unix_micro_utc\n" " // -> Error([\n" " // decode.DecodeError(\n" " // expected: \"Int\",\n" " // found: \"String\",\n" " // path: [],\n" " // ),\n" " // ])\n" " ```\n" ). -spec from_dynamic_unix_micro_utc(gleam@dynamic:dynamic_()) -> {ok, tempo:date_time()} | {error, list(gleam@dynamic@decode:decode_error())}. from_dynamic_unix_micro_utc(Dynamic_ts) -> gleam@result:map( begin _pipe = gleam@dynamic@decode:run( Dynamic_ts, {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@result:map_error( _pipe, fun(Errs) -> gleam@list:map( Errs, fun(Err) -> {decode_error, erlang:element(2, Err), erlang:element(3, Err), erlang:element(4, Err)} end ) end ) end, fun(Unix_micro) -> from_unix_micro(Unix_micro) end ). -file("src/tempo/datetime.gleam", 669). ?DOC( " Gets the date of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T13:42:11.195Z\")\n" " |> datetime.get_date\n" " // -> date.literal(\"2024-06-21\")\n" " ```\n" ). -spec get_date(tempo:date_time()) -> tempo:date(). get_date(Datetime) -> erlang:element(2, Datetime). -file("src/tempo/datetime.gleam", 682). ?DOC( " Gets the core gleam time package calendar date of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T13:42:11.195Z\")\n" " |> datetime.get_calendar_date\n" " // -> calendar.Date(2024, calendar.June, 21)\n" " ```\n" ). -spec get_calendar_date(tempo:date_time()) -> gleam@time@calendar:date(). get_calendar_date(Datetime) -> _pipe = erlang:element(2, Datetime), tempo@date:to_calendar_date(_pipe). -file("src/tempo/datetime.gleam", 695). ?DOC( " Gets the time of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T13:42:11.195Z\")\n" " |> datetime.get_time\n" " // -> time.literal(\"13:42:11.195\")\n" " ```\n" ). -spec get_time(tempo:date_time()) -> tempo:time(). get_time(Datetime) -> erlang:element(3, Datetime). -file("src/tempo/datetime.gleam", 708). ?DOC( " Gets the core gleam time package calendar time of day of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T13:42:11.195Z\")\n" " |> datetime.get_calendar_time_of_day\n" " // -> calendar.TimeOfDay(13, 42, 11, 195_000_000)\n" " ```\n" ). -spec get_calendar_time_of_day(tempo:date_time()) -> gleam@time@calendar:time_of_day(). get_calendar_time_of_day(Datetime) -> _pipe = erlang:element(3, Datetime), tempo@time:to_calendar_time_of_day(_pipe). -file("src/tempo/datetime.gleam", 723). ?DOC( " Gets the offset of a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-12T13:42:11.195-04:00\")\n" " |> datetime.get_offset\n" " // -> offset.literal(\"+04:00\")\n" " ```\n" ). -spec get_offset(tempo:date_time()) -> tempo:offset(). get_offset(Datetime) -> _pipe = Datetime, tempo:datetime_get_offset(_pipe). -file("src/tempo/datetime.gleam", 736). ?DOC( " Drops the time of a datetime, leaving the date and time values unchanged.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-13T13:42:11.195Z\")\n" " |> datetime.drop_offset\n" " // -> naive_datetime.literal(\"2024-06-13T13:42:11\")\n" " ```\n" ). -spec drop_offset(tempo:date_time()) -> tempo:naive_date_time(). drop_offset(Datetime) -> tempo:datetime_drop_offset(Datetime). -file("src/tempo/datetime.gleam", 749). ?DOC( " Drops the time of a datetime, leaving the date value unchanged.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-18T13:42:11.195Z\")\n" " |> datetime.drop_time\n" " // -> naive_datetime.literal(\"2024-06-18T00:00:00Z\")\n" " ```\n" ). -spec drop_time(tempo:date_time()) -> tempo:date_time(). drop_time(Datetime) -> Naive = tempo@naive_datetime:drop_time( begin _pipe = Datetime, tempo:datetime_get_naive(_pipe) end ), tempo:datetime( erlang:element(2, Naive), erlang:element(3, Naive), begin _pipe@1 = Datetime, tempo:datetime_get_offset(_pipe@1) end ). -file("src/tempo/datetime.gleam", 795). ?DOC( " Converts a datetime to the equivalent time in an offset.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T05:36:11.195-04:00\")\n" " |> datetime.to_offset(offset.literal(\"+10:00\"))\n" " // -> datetime.literal(\"2024-06-21T19:36:11.195+10:00\")\n" " ```\n" ). -spec to_offset(tempo:date_time(), tempo:offset()) -> tempo:date_time(). to_offset(Datetime, Offset) -> tempo:datetime_to_offset(Datetime, Offset). -file("src/tempo/datetime.gleam", 831). ?DOC( " Converts a datetime to the equivalent local datetime. Prefer to either\n" " design your application to not need this, or add an external timezone\n" " provider to use with the `to_timezone` function.\n" "\n" " Conversion is based on the host's current offset. We can not be\n" " sure the current host offset is applicable to the given datetime, and so\n" " an imprecise conversion will be performed. The imprecise conversion can be\n" " inaccurate to the degree the local offset changes throughout the year.\n" " For example, in North America where Daylight Savings Time is observed with\n" " a one-hour time shift, the imprecise conversion can be off by up to an hour,\n" " depending on the time of year.\n" "\n" " If the date of the given datetime matches the date of the host, then the\n" " conversion will actually be precise all but during the hour(s) when the\n" " time zone offset is shifting.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T09:57:11.195Z\")\n" " |> datetime.to_local_imprecise\n" " // -> datetime.literal(\"2024-06-21T05:57:11.195-04:00\")\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"1998-08-23T09:57:11.195Z\")\n" " |> datetime.to_local_imprecise\n" " // -> datetime.literal(\"1998-08-23T05:57:11.195-04:00\")\n" " ```\n" ). -spec to_local_imprecise(tempo:date_time()) -> tempo:date_time(). to_local_imprecise(Datetime) -> _pipe = Datetime, to_offset(_pipe, tempo@offset:local()). -file("src/tempo/datetime.gleam", 868). ?DOC(false). -spec to_local_time_imprecise(tempo:date_time()) -> tempo:time(). to_local_time_imprecise(Datetime) -> erlang:element(3, to_local_imprecise(Datetime)). -file("src/tempo/datetime.gleam", 905). ?DOC(false). -spec to_local_date_imprecise(tempo:date_time()) -> tempo:date(). to_local_date_imprecise(Datetime) -> erlang:element(2, to_local_imprecise(Datetime)). -file("src/tempo/datetime.gleam", 931). ?DOC( " Converts a datetime to the specified timezone. Relies on an external\n" " package like `gtz` to provide timezone information.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import gtz\n" " let assert Ok(tz) = gtz.timezone(\"America/New_York\")\n" " datetime.literal(\"2024-06-21T06:30:02.334Z\")\n" " |> datetime.to_timezone(tz)\n" " |> datetime.to_string\n" " // -> \"2024-01-03T02:30:02.334-04:00\"\n" " ```\n" "\n" " ```gleam\n" " import gtz\n" " let assert Ok(local_tz) = gtz.local_name() |> gtz.timezone\n" " datetime.from_unix_seconds(1_729_257_776)\n" " |> datetime.to_timezone(local_tz)\n" " |> datetime.to_string\n" " // -> \"2024-10-18T14:22:56.000+01:00\"\n" " ```\n" ). -spec to_timezone(tempo:date_time(), tempo:time_zone_provider()) -> tempo:date_time(). to_timezone(Datetime, Tz) -> tempo:datetime_to_tz(Datetime, Tz). -file("src/tempo/datetime.gleam", 955). ?DOC( " Gets the name of the timezone the datetime is in.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T06:30:02.334Z\")\n" " |> datetime.get_timezone_name\n" " // -> None\n" " ```\n" "\n" " ```gleam\n" " import gtz\n" " let assert Ok(tz) = gtz.timezone(\"Europe/London\")\n" " datetime.to_timezone(my_datetime, tz)\n" " |> datetime.get_timezone_name\n" " // -> Some(\"Europe/London\")\n" " ```\n" ). -spec get_timezone_name(tempo:date_time()) -> gleam@option:option(binary()). get_timezone_name(Datetime) -> tempo:datetime_get_tz(Datetime). -file("src/tempo/datetime.gleam", 980). ?DOC( " Compares two datetimes.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T23:47:00+09:05\")\n" " |> datetime.compare(to: datetime.literal(\"2024-06-21T23:47:00+09:05\"))\n" " // -> order.Eq\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2023-05-11T13:30:00-04:00\")\n" " |> datetime.compare(to: datetime.literal(\"2023-05-11T13:15:00Z\"))\n" " // -> order.Lt\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-12T23:47:00+09:05\")\n" " |> datetime.compare(to: datetime.literal(\"2022-04-12T00:00:00\"))\n" " // -> order.Gt\n" " ```\n" ). -spec compare(tempo:date_time(), tempo:date_time()) -> gleam@order:order(). compare(A, B) -> tempo:datetime_compare(A, B). -file("src/tempo/datetime.gleam", 1003). ?DOC( " Checks if the first datetime is earlier than the second datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T23:47:00+09:05\")\n" " |> datetime.is_earlier(\n" " than: datetime.literal(\"2024-06-21T23:47:00+09:05\"),\n" " )\n" " // -> False\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2023-05-11T13:30:00-04:00\")\n" " |> datetime.is_earlier(\n" " than: datetime.literal(\"2023-05-11T13:15:00Z\"),\n" " )\n" " // -> True\n" " ```\n" ). -spec is_earlier(tempo:date_time(), tempo:date_time()) -> boolean(). is_earlier(A, B) -> tempo:datetime_is_earlier(A, B). -file("src/tempo/datetime.gleam", 1025). ?DOC( " Checks if the first datetime is earlier or equal to the second datetime.\n" "\n" " ## Examples\n" " ```gleam\n" " datetime.literal(\"2024-06-21T23:47:00+09:05\")\n" " |> datetime.is_earlier_or_equal(\n" " to: datetime.literal(\"2024-06-21T23:47:00+09:05\"),\n" " )\n" " // -> True\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-07-15T23:40:00-04:00\")\n" " |> datetime.is_earlier_or_equal(\n" " to: datetime.literal(\"2023-05-11T13:15:00Z\"),\n" " )\n" " // -> False\n" " ```\n" ). -spec is_earlier_or_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_earlier_or_equal(A, B) -> tempo:datetime_is_earlier_or_equal(A, B). -file("src/tempo/datetime.gleam", 1047). ?DOC( " Checks if the first datetime is equal to the second datetime.\n" "\n" " ## Examples\n" " ```gleam\n" " datetime.literal(\"2024-06-21T09:44:00Z\")\n" " |> datetime.is_equal(\n" " to: datetime.literal(\"2024-06-21T05:44:00-04:00\"),\n" " )\n" " // -> True\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T09:44:00Z\")\n" " |> datetime.is_equal(\n" " to: datetime.literal(\"2024-06-21T09:44:00.045Z\"),\n" " )\n" " // -> False\n" " ```\n" ). -spec is_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_equal(A, B) -> tempo:datetime_is_equal(A, B). -file("src/tempo/datetime.gleam", 1070). ?DOC( " Checks if the first datetime is later than the second datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T23:47:00+09:05\")\n" " |> datetime.is_later(\n" " than: datetime.literal(\"2024-06-21T23:47:00+09:05\"),\n" " )\n" " // -> False\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2023-05-11T13:00:00+04:00\")\n" " |> datetime.is_later(\n" " than: datetime.literal(\"2023-05-11T13:15:00.534Z\"),\n" " )\n" " // -> True\n" " ```\n" ). -spec is_later(tempo:date_time(), tempo:date_time()) -> boolean(). is_later(A, B) -> tempo:datetime_is_later(A, B). -file("src/tempo/datetime.gleam", 1092). ?DOC( " Checks if the first datetime is later or equal to the second datetime.\n" "\n" " ## Examples\n" " ```gleam\n" " datetime.literal(\"2016-01-11T03:47:00+09:05\")\n" " |> datetime.is_later_or_equal(\n" " to: datetime.literal(\"2024-06-21T23:47:00+09:05\"),\n" " )\n" " // -> False\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-07-15T23:40:00-04:00\")\n" " |> datetime.is_later_or_equal(\n" " to: datetime.literal(\"2023-05-11T13:15:00Z\"),\n" " )\n" " // -> True\n" " ```\n" ). -spec is_later_or_equal(tempo:date_time(), tempo:date_time()) -> boolean(). is_later_or_equal(A, B) -> tempo:datetime_is_later_or_equal(A, B). -file("src/tempo/datetime.gleam", 1118). ?DOC( " Returns the difference between two datetimes as a duration between their\n" " equivalent UTC times.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-12T23:17:00Z\")\n" " |> datetime.difference(\n" " to: datetime.literal(\"2024-06-16T01:16:12Z\"),\n" " )\n" " |> duration.as_days\n" " // -> 3\n" " ```\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-12T23:17:00Z\")\n" " |> datetime.difference(\n" " to: datetime.literal(\"2024-06-16T01:18:12Z\"),\n" " )\n" " |> duration.format\n" " // -> \"3 days, 2 hours, and 1 minutes\"\n" " ```\n" ). -spec difference(tempo:date_time(), tempo:date_time()) -> gleam@time@duration:duration(). difference(A, B) -> tempo@naive_datetime:difference( tempo:datetime_apply_offset(A), tempo:datetime_apply_offset(B) ). -file("src/tempo/datetime.gleam", 1152). ?DOC( " Creates a period between two datetimes, where the start and end times are\n" " the equivalent UTC times of the provided datetimes. The specified start\n" " and end datetimes will be swapped if the start datetime is later than the\n" " end datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.to_period(\n" " start: datetime.literal(\"2024-06-12T23:17:00Z\")\n" " end: datetime.literal(\"2024-06-16T01:16:12Z\"),\n" " )\n" " |> period.as_days\n" " // -> 3\n" " ```\n" "\n" " ```gleam\n" " datetime.to_period(\n" " start: datetime.literal(\"2024-06-12T23:17:00Z\")\n" " end: datetime.literal(\"2024-06-16T01:18:12Z\"),\n" " )\n" " |> period.format\n" " // -> \"3 days, 2 hours, and 1 minute\"\n" " ```\n" ). -spec as_period(tempo:date_time(), tempo:date_time()) -> tempo:period(). as_period(Start, End) -> tempo:period_new(Start, End). -file("src/tempo/datetime.gleam", 1168). ?DOC( " Adds a duration to a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-12T23:17:00Z\")\n" " |> datetime.add(duration |> tempo.offset_get_minutes(3))\n" " // -> datetime.literal(\"2024-06-12T23:20:00Z\")\n" " ```\n" ). -spec add(tempo:date_time(), gleam@time@duration:duration()) -> tempo:date_time(). add(Datetime, Duration_to_add) -> tempo:datetime_add(Datetime, Duration_to_add). -file("src/tempo/datetime.gleam", 1184). ?DOC( " Subtracts a duration from a datetime.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " datetime.literal(\"2024-06-21T23:17:00Z\")\n" " |> datetime.subtract(duration.days(3))\n" " // -> datetime.literal(\"2024-06-18T23:17:00Z\")\n" " ```\n" ). -spec subtract(tempo:date_time(), gleam@time@duration:duration()) -> tempo:date_time(). subtract(Datetime, Duration_to_subtract) -> tempo:datetime_subtract(Datetime, Duration_to_subtract). -file("src/tempo/datetime.gleam", 1208). ?DOC( " Gets the time left in the day.\n" "\n" " Does **not** account for leap seconds like the rest of the package.\n" "\n" " ## Examples\n" "\n" " ```gleam\n" " naive_datetime.literal(\"2015-06-30T23:59:03Z\")\n" " |> naive_datetime.time_left_in_day\n" " // -> time.literal(\"00:00:57\")\n" " ```\n" "\n" " ```gleam\n" " naive_datetime.literal(\"2024-06-18T08:05:20-04:00\")\n" " |> naive_datetime.time_left_in_day\n" " // -> time.literal(\"15:54:40\")\n" " ```\n" ). -spec time_left_in_day(tempo:date_time()) -> tempo:time(). time_left_in_day(Datetime) -> _pipe = Datetime, _pipe@1 = tempo:datetime_get_naive(_pipe), _pipe@2 = tempo:naive_datetime_get_time(_pipe@1), tempo@time:left_in_day(_pipe@2).