Current section
Files
Jump to
Current section
Files
src/tempo@date.erl
-module(tempo@date).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/tempo/date.gleam").
-export([new/3, from_tuple/1, from_string/1, literal/1, from_unix_micro/1, current_local/0, current_utc/0, get_year/1, get_month/1, get_day/1, get_month_year/1, to_string/1, parse/2, parse_any/1, describe_parse_error/1, format/2, describe_out_of_bounds_error/1, to_tuple/1, to_calendar_date/1, from_calendar_date/1, from_dynamic_string/1, from_unix_seconds/1, to_unix_seconds/1, from_unix_milli/1, to_unix_milli/1, to_unix_micro/1, from_rata_die/1, to_rata_die/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, to_day_of_week_number/1, to_day_of_week/1, day_of_week_to_short_string/1, day_of_week_to_long_string/1, next_day_of_week/2, prior_day_of_week/2, is_weekend/1, first_of_month/1, last_of_month/1]).
-export_type([day_of_week/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.
?MODULEDOC(
" Functions to use with the `Date` type in Tempo.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import tempo/date\n"
"\n"
" pub fn main() {\n"
" date.literal(\"2024-06-21\")\n"
" |> date.to_string\n"
" // -> \"2024-06-21\"\n"
"\n"
" date.parse(\"06/21/2024\", tempo.CustomDate(\"MM/DD/YYYY\"))\n"
" |> date.to_string\n"
" // -> \"2024-06-21\"\n"
"\n"
" date.current_local()\n"
" |> date.to_string\n"
" // -> \"2024-10-09\"\n"
" }\n"
" ```\n"
"\n"
" ```gleam\n"
" import tempo/date\n"
"\n"
" pub fn is_older_than_a_week(date_str: String) {\n"
" let date = date.from_string(date_str)\n"
"\n"
" date\n"
" |> date.is_earlier(\n"
" than: date |> date.subtract(days: 7)\n"
" )\n"
" }\n"
" ```\n"
"\n"
" ## Calendar\n"
"\n"
" Dates in this module are\n"
" [proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar)\n"
" dates. Every year-month-day these functions accept or produce is a\n"
" Gregorian one, with Gregorian month lengths and the Gregorian leap year\n"
" rule (divisible by 4, except century years, which must be divisible by\n"
" 400). \"Proleptic\" means those rules are applied to dates before the\n"
" calendar was adopted in 1582 as well, so a date such as `1500-01-01` is not\n"
" the day that was recorded as such at the time, when the Julian calendar was\n"
" in use. No other calendar system is supported.\n"
"\n"
" ## Range of valid dates\n"
"\n"
" Constructing a date from calendar parts is limited to **years 1000 through\n"
" 9999**, so that a year is always four digits. `new`, `from_tuple`,\n"
" `from_calendar_date`, `from_string`, `parse`, `parse_any` and `literal` all\n"
" reject years outside that range.\n"
"\n"
" Date arithmetic is not range checked. `add`, `subtract` and `from_rata_die`\n"
" will happily produce dates outside 1000 to 9999, including year zero and\n"
" negative years. Such dates still compare and do arithmetic correctly, but\n"
" `to_string` and `format` will render their years without four-digit zero\n"
" padding, which is not valid ISO 8601. Keep results within 1000 to 9999 if\n"
" you intend to format them.\n"
).
-type day_of_week() :: sun | mon | tue | wed | thu | fri | sat.
-file("src/tempo/date.gleam", 121).
?DOC(
" Creates a new proleptic Gregorian calendar date and validates it.\n"
"\n"
" The year must be between 1000 and 9999, the month between 1 and 12, and the\n"
" day between 1 and the number of days that month has in that Gregorian year.\n"
" Anything else returns an error.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.new(2024, 6, 13)\n"
" // -> Ok(date.literal(\"2024-06-13\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.new(2024, 6, 31)\n"
" // -> Error(tempo_error.DateOutOfBounds)\n"
" ```\n"
"\n"
" ```gleam\n"
" // 2024 is a Gregorian leap year, 2023 is not\n"
" date.new(2024, 2, 29)\n"
" // -> Ok(date.literal(\"2024-02-29\"))\n"
" date.new(2023, 2, 29)\n"
" // -> Error(tempo_error.DateOutOfBounds)\n"
" ```\n"
"\n"
" ```gleam\n"
" // Years outside 1000 to 9999 are rejected\n"
" date.new(999, 1, 1)\n"
" // -> Error(tempo_error.DateOutOfBounds)\n"
" ```\n"
).
-spec new(integer(), integer(), integer()) -> {ok, tempo:date()} |
{error, tempo@error:date_out_of_bounds_error()}.
new(Year, Month, Day) ->
tempo:new_date(Year, Month, Day).
-file("src/tempo/date.gleam", 490).
?DOC(
" Returns a date value from a tuple of ints if the values represent the\n"
" year, month, and day of a valid proleptic Gregorian calendar date. The year\n"
" must be between 1000 and 9999, the month between 1 and 12, and the day\n"
" between 1 and the number of days that month has in that Gregorian year.\n"
"\n"
" Years less than 1000 are technically valid years, but are not common\n"
" and usually indicate that either a non-year value was passed as the year\n"
" or a two digit year was passed (which are too abiguous to be confidently\n"
" accepted). Years above 9999 are rejected so that a year is always four\n"
" digits.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.from_tuple(#(2024, 6, 13))\n"
" // -> Ok(date.literal(\"2024-06-13\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.from_tuple(#(98, 6, 13))\n"
" // -> Error(tempo_error.DateOutOfBounds)\n"
" ```\n"
"\n"
" ```gleam\n"
" // Feb 29 exists in Gregorian leap years only\n"
" date.from_tuple(#(2023, 2, 29))\n"
" // -> Error(tempo_error.DateOutOfBounds)\n"
" ```\n"
).
-spec from_tuple({integer(), integer(), integer()}) -> {ok, tempo:date()} |
{error, tempo@error:date_out_of_bounds_error()}.
from_tuple(Date) ->
tempo:date_from_tuple(Date).
-file("src/tempo/date.gleam", 289).
-spec parse_date_parts(bitstring()) -> {ok, {integer(), integer(), integer()}} |
{error, nil}.
parse_date_parts(Input) ->
gleam@result:'try'(
gtempo@internal:take_date_parts(Input),
fun(_use0) ->
{Parts, Input@1} = _use0,
gleam@result:map(
gtempo@internal:accept_empty(Input@1),
fun(_use0@1) ->
nil = _use0@1,
Parts
end
)
end
).
-file("src/tempo/date.gleam", 277).
?DOC(
" Parses a date string in the format `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`, `YYYY MM DD`,\n"
" `YYYY M D`, or `YYYYMMDD`.\n"
"\n"
" The string is read as a proleptic Gregorian calendar date. The year must be\n"
" between 1000 and 9999, and the day must exist in that Gregorian month, so\n"
" `\"2023-02-29\"` is an error while `\"2024-02-29\"` is not.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.from_string(\"2024-06-13\")\n"
" // -> Ok(date.literal(\"2024-06-13\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.from_string(\"20240613\")\n"
" // -> Ok(date.literal(\"2024-06-13\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.from_string(\"2409\")\n"
" // -> Error(tempo_error.DateInvalidFormat)\n"
" ```\n"
).
-spec from_string(binary()) -> {ok, tempo:date()} |
{error, tempo@error:date_parse_error()}.
from_string(Date) ->
gleam@result:'try'(
begin
_pipe = parse_date_parts(gleam_stdlib:identity(Date)),
gleam@result:replace_error(_pipe, {date_invalid_format, Date})
end,
fun(Parts) -> _pipe@1 = from_tuple(Parts),
gleam@result:map_error(
_pipe@1,
fun(_capture) -> {date_out_of_bounds, Date, _capture} end
) end
).
-file("src/tempo/date.gleam", 159).
?DOC(
" Creates a new date value from a string literal, but will panic if\n"
" the string is invalid. Accepted formats are `YYYY-MM-DD`, `YYYY-M-D`,\n"
" `YYYY/MM/DD`, `YYYY/M/D`, `YYYY.MM.DD`, `YYYY.M.D`, `YYYY_MM_DD`,\n"
" `YYYY_M_D`, `YYYY MM DD`, `YYYY M D`, or `YYYYMMDD`.\n"
"\n"
" Useful for declaring date literals that you know are valid within your\n"
" program.\n"
"\n"
" The string is read as a proleptic Gregorian calendar date, and must have a\n"
" year between 1000 and 9999. A year outside that range panics, as does a day\n"
" that does not exist in that Gregorian month, such as `\"2023-02-29\"`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.to_string\n"
" // -> \"2024-06-13\"\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"20240613\")\n"
" |> date.to_string\n"
" // -> \"2024-06-13\"\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2409\")\n"
" // -> panic\n"
" ```\n"
).
-spec literal(binary()) -> tempo:date().
literal(Date) ->
case from_string(Date) of
{ok, Date@1} ->
Date@1;
{error, {date_invalid_format, _}} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid date literal format"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"tempo/date"/utf8>>,
function => <<"literal"/utf8>>,
line => 163});
{error, {date_out_of_bounds, _, {date_day_out_of_bounds, _}}} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid date literal day value"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"tempo/date"/utf8>>,
function => <<"literal"/utf8>>,
line => 165});
{error, {date_out_of_bounds, _, {date_month_out_of_bounds, _}}} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid date literal month value"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"tempo/date"/utf8>>,
function => <<"literal"/utf8>>,
line => 167});
{error, {date_out_of_bounds, _, {date_year_out_of_bounds, _}}} ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid date literal year value"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"tempo/date"/utf8>>,
function => <<"literal"/utf8>>,
line => 169})
end.
-file("src/tempo/date.gleam", 712).
?DOC(false).
-spec from_unix_micro(integer()) -> tempo:date().
from_unix_micro(Unix_ts) ->
tempo:date_from_unix_micro(Unix_ts).
-file("src/tempo/date.gleam", 183).
?DOC(
" Gets the current local date of the host, as a proleptic Gregorian calendar\n"
" date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.current_local()\n"
" |> date.to_string\n"
" // -> \"2024-06-13\"\n"
" ```\n"
).
-spec current_local() -> tempo:date().
current_local() ->
_pipe = (tempo_ffi:now() + tempo:offset_local_micro()),
from_unix_micro(_pipe).
-file("src/tempo/date.gleam", 197).
?DOC(
" Gets the current UTC date of the host, as a proleptic Gregorian calendar\n"
" date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.current_utc()\n"
" |> date.to_string\n"
" // -> \"2024-06-14\"\n"
" ```\n"
).
-spec current_utc() -> tempo:date().
current_utc() ->
_pipe = tempo_ffi:now(),
from_unix_micro(_pipe).
-file("src/tempo/date.gleam", 210).
?DOC(
" Gets the proleptic Gregorian calendar year of a date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.get_year\n"
" // -> 2024\n"
" ```\n"
).
-spec get_year(tempo:date()) -> integer().
get_year(Date) ->
_pipe = Date,
tempo:date_get_year(_pipe).
-file("src/tempo/date.gleam", 223).
?DOC(
" Gets the Gregorian calendar month of a date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.get_month\n"
" // -> tempo.Jun\n"
" ```\n"
).
-spec get_month(tempo:date()) -> gleam@time@calendar:month().
get_month(Date) ->
_pipe = Date,
tempo:date_get_month(_pipe).
-file("src/tempo/date.gleam", 236).
?DOC(
" Gets the day of the Gregorian calendar month of a date, from 1 to 31.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.get_day\n"
" // -> 13\n"
" ```\n"
).
-spec get_day(tempo:date()) -> integer().
get_day(Date) ->
_pipe = Date,
tempo:date_get_day(_pipe).
-file("src/tempo/date.gleam", 249).
?DOC(
" Gets the Gregorian calendar month and year of a date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.get_month_year\n"
" // -> calendar.MonthYear(tempo.Jun, 2024)\n"
" ```\n"
).
-spec get_month_year(tempo:date()) -> tempo:month_year().
get_month_year(Date) ->
_pipe = Date,
tempo:date_get_month_year(_pipe).
-file("src/tempo/date.gleam", 320).
?DOC(
" Returns a string representation of a proleptic Gregorian calendar date in\n"
" the format `YYYY-MM-DD`.\n"
"\n"
" Dates built by the constructors always have a year between 1000 and 9999\n"
" and so always render as four digits. Date arithmetic is not range checked\n"
" though, so a date pushed outside that range by `add`, `subtract` or\n"
" `from_rata_die` renders its year without four-digit zero padding, which is\n"
" not valid ISO 8601.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.to_string\n"
" // -> \"2024-06-13\"\n"
" ```\n"
"\n"
" ```gleam\n"
" // Outside the 1000 to 9999 range the year is not padded\n"
" date.literal(\"1000-01-01\")\n"
" |> date.subtract(days: 1)\n"
" |> date.to_string\n"
" // -> \"999-12-31\"\n"
" ```\n"
).
-spec to_string(tempo:date()) -> binary().
to_string(Date) ->
tempo:date_to_string(Date).
-file("src/tempo/date.gleam", 355).
?DOC(
" Parses a date string in the provided format. Always prefer using\n"
" this over `parse_any`. All parsed formats must have all parts of a date.\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"
"\n"
" The result is a proleptic Gregorian calendar date, and the month names the\n"
" directives accept are the English Gregorian ones. The parsed year must land\n"
" between 1000 and 9999, and the day must exist in that Gregorian month, or an\n"
" error is returned. A `YY` two-digit year is resolved into the hundred years\n"
" leading up to the current date, so `\"99\"` parses as 1999 rather than 2099.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.parse(\"2024/06/08, 13:42:11\", \"YYYY/MM/DD\")\n"
" // -> Ok(date.literal(\"2024-06-08\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.parse(\"January 13, 2024\", \"MMMM DD, YYYY\")\n"
" // -> Ok(date.literal(\"2024-01-13\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.parse(\"Hi! 2024 11 13\", \"[Hi!] YYYY M D\")\n"
" // -> Ok(date.literal(\"2024-11-13\"))\n"
" ```\n"
).
-spec parse(binary(), tempo:date_format()) -> {ok, tempo:date()} |
{error, tempo@error:date_parse_error()}.
parse(Str, Format) ->
Format_str = tempo:get_date_format_str(Format),
gleam@result:'try'(
begin
_pipe = tempo:consume_format(Str, Format_str),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {date_invalid_format, Field@0} end
)
end,
fun(Parts) -> tempo:find_date(Parts) end
).
-file("src/tempo/date.gleam", 388).
?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. Will leave out any time or offset values present.\n"
"\n"
" The result is a proleptic Gregorian calendar date with a year between 1000\n"
" and 9999. Since two digit years are not parsed, the year in the string must\n"
" already be four digits.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.parse_any(\"2024.06.21 01:32 PM -04:00\")\n"
" // -> Ok(date.literal(\"2024-06-21\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" date.parse_any(\"2024.06.21\")\n"
" // -> Ok(date.literal(\"2024-06-21\"))\n"
" ```\n"
).
-spec parse_any(binary()) -> {ok, tempo:date()} |
{error, tempo@error:date_parse_error()}.
parse_any(Str) ->
case tempo:parse_any(Str) of
{{some, Date}, _, _} ->
{ok, Date};
{none, _, _} ->
{error,
{date_invalid_format,
<<"Unable to find date in "/utf8, Str/binary>>}}
end.
-file("src/tempo/date.gleam", 407).
?DOC(
" Converts a date parse error to a human readable error message.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.parse_any(\"01:32 PM\")\n"
" |> snag.map_error(with: date.describe_parse_error)\n"
" // -> snag.error(\"Invalid date format: 01:32 PM\")\n"
" ```\n"
).
-spec describe_parse_error(tempo@error:date_parse_error()) -> binary().
describe_parse_error(Error) ->
tempo@error:describe_date_parse_error(Error).
-file("src/tempo/date.gleam", 450).
?DOC(
" Formats a date value into a string using the provided date format.\n"
"\n"
" All calendar directives render proleptic Gregorian calendar values, and the\n"
" month and day names are the English Gregorian ones. Dates built by the\n"
" constructors always have a four-digit year, but a date pushed outside 1000\n"
" to 9999 by `add`, `subtract` or `from_rata_die` renders its year without\n"
" four-digit zero padding.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" datetime.literal(\"2024-12-26T13:02:01-04:00\")\n"
" |> datetime.format(tempo.ISO8601Date)\n"
" // -> \"2024-12-26\"\n"
" ```\n"
"\n"
" ```gleam\n"
" datetime.literal(\"2024-06-21T13:42:11.314-04:00\")\n"
" |> datetime.format(tempo.CustomDate(\"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.CustomDate(\"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.CustomDate(\"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.CustomDate((\"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(), tempo:date_format()) -> binary().
format(Date, Format) ->
_pipe = tempo:get_date_format_str(Format),
_pipe@1 = tempo:tokenise_format(_pipe),
_pipe@2 = gleam@list:map(_pipe@1, fun(Token) -> case Token of
{directive, Directive} ->
tempo:date_replace_format(Directive, Date);
{escaped, Literal} ->
Literal
end end),
erlang:list_to_binary(_pipe@2).
-file("src/tempo/date.gleam", 505).
?DOC(
" Converts a date out of bounds error to a human readable error message.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.from_tuple(#(98, 6, 13))\n"
" |> snag.map_error(with: date.describe_out_of_bounds_error)\n"
" // -> snag.error(\"Year out of bounds in date: 98\")\n"
" ```\n"
).
-spec describe_out_of_bounds_error(tempo@error:date_out_of_bounds_error()) -> binary().
describe_out_of_bounds_error(Error) ->
tempo@error:describe_date_out_of_bounds_error(Error).
-file("src/tempo/date.gleam", 520).
?DOC(
" Returns a tuple of ints from a date value that represent the year, month,\n"
" and day of the date on the proleptic Gregorian calendar, where the month is\n"
" 1 for January through 12 for December.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-14\")\n"
" |> date.to_tuple\n"
" // -> #(2024, 6, 14)\n"
" ```\n"
).
-spec to_tuple(tempo:date()) -> {integer(), integer(), integer()}.
to_tuple(Date) ->
{begin
_pipe = Date,
tempo:date_get_year(_pipe)
end,
tempo@month:to_int(
begin
_pipe@1 = Date,
tempo:date_get_month(_pipe@1)
end
),
begin
_pipe@2 = Date,
tempo:date_get_day(_pipe@2)
end}.
-file("src/tempo/date.gleam", 539).
?DOC(
" Converts a tempo date to a `gleam_time` calendar date. Both represent the\n"
" same proleptic Gregorian calendar year, month, and day, so no calendar\n"
" conversion takes place.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.to_calendar_date\n"
" // -> calendar.Date(2024, calendar.June, 13)\n"
" ```\n"
).
-spec to_calendar_date(tempo:date()) -> gleam@time@calendar:date().
to_calendar_date(Date) ->
tempo:date_to_calendar_date(Date).
-file("src/tempo/date.gleam", 555).
?DOC(
" Converts a `gleam_time` calendar date to a tempo date. Both represent the\n"
" same proleptic Gregorian calendar year, month, and day, so no calendar\n"
" conversion takes place, but the year must be between 1000 and 9999 or an\n"
" error is returned.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" calendar.Date(2024, calendar.June, 13)\n"
" |> date.from_calendar_date\n"
" // -> Ok(date.literal(\"2024-06-13\"))\n"
" ```\n"
).
-spec from_calendar_date(gleam@time@calendar:date()) -> {ok, tempo:date()} |
{error, tempo@error:date_out_of_bounds_error()}.
from_calendar_date(Date) ->
{date, Year, Month, Day} = Date,
from_tuple(
{Year,
begin
_pipe = Month,
tempo@month:to_int(_pipe)
end,
Day}
).
-file("src/tempo/date.gleam", 584).
?DOC(
" Checks if a dynamic value is a valid date string, and returns the\n"
" date if it is.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" dynamic.string(\"2024-06-21\")\n"
" |> date.from_dynamic_string\n"
" // -> Ok(date.literal(\"2024-06-21\"))\n"
" ```\n"
"\n"
" ```gleam\n"
" dynamic.string(\"153\")\n"
" |> datetime.from_dynamic_string\n"
" // -> Error([\n"
" // decode.DecodeError(\n"
" // expected: \"tempo.Date\",\n"
" // found: \"Invalid format: 153\",\n"
" // path: [],\n"
" // ),\n"
" // ])\n"
" ```\n"
).
-spec from_dynamic_string(gleam@dynamic:dynamic_()) -> {ok, tempo:date()} |
{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(Date) -> case from_string(Date) of
{ok, Date@1} ->
{ok, Date@1};
{error, Tempo_error} ->
{error,
[{decode_error,
<<"tempo.Date"/utf8>>,
case Tempo_error of
{date_invalid_format, Msg} ->
Msg;
{date_out_of_bounds, Msg@1, _} ->
Msg@1
end,
[]}]}
end end
).
-file("src/tempo/date.gleam", 630).
?DOC(false).
-spec from_unix_seconds(integer()) -> tempo:date().
from_unix_seconds(Unix_ts) ->
tempo:date_from_unix_seconds(Unix_ts).
-file("src/tempo/date.gleam", 650).
?DOC(false).
-spec to_unix_seconds(tempo:date()) -> integer().
to_unix_seconds(Date) ->
tempo:date_to_unix_seconds(Date).
-file("src/tempo/date.gleam", 670).
?DOC(false).
-spec from_unix_milli(integer()) -> tempo:date().
from_unix_milli(Unix_ts) ->
tempo:date_from_unix_milli(Unix_ts).
-file("src/tempo/date.gleam", 692).
?DOC(false).
-spec to_unix_milli(tempo:date()) -> integer().
to_unix_milli(Date) ->
to_unix_seconds(Date) * 1000.
-file("src/tempo/date.gleam", 732).
?DOC(false).
-spec to_unix_micro(tempo:date()) -> integer().
to_unix_micro(Date) ->
tempo:date_to_unix_micro(Date).
-file("src/tempo/date.gleam", 753).
?DOC(
" Creates a date from a Rata Die value, the number of days since the day\n"
" before `0001-01-01` on the proleptic Gregorian calendar, so Rata Die 1 is\n"
" `0001-01-01` and `1970-01-01` is 719_163.\n"
"\n"
" Adapted from the very nice Rada Gleam library!\n"
"\n"
" This is not range checked, so unlike the calendar-part constructors it will\n"
" return dates outside the 1000 to 9999 year range, including year zero and\n"
" negative years for values of 0 and below. Those dates compare and do\n"
" arithmetic correctly but do not format as valid ISO 8601.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.from_rata_die(739_050)\n"
" // -> date.literal(\"2024-06-13\")\n"
" ```\n"
).
-spec from_rata_die(integer()) -> tempo:date().
from_rata_die(Rata_die) ->
tempo:date_from_rata_die(Rata_die).
-file("src/tempo/date.gleam", 776).
?DOC(
" Returns the Rata Die value of the date as an Int, the number of days since\n"
" the day before `0001-01-01` on the proleptic Gregorian calendar, so\n"
" `0001-01-01` is 1 and `1970-01-01` is 719_163.\n"
"\n"
" Adapted from the very nice Rada Gleam library!\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-13\")\n"
" |> date.to_rata_die\n"
" // -> 739_050\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"1970-01-01\")\n"
" |> date.to_rata_die\n"
" // -> 719_163\n"
" ```\n"
).
-spec to_rata_die(tempo:date()) -> integer().
to_rata_die(Date) ->
tempo:date_to_rata_die(Date).
-file("src/tempo/date.gleam", 801).
?DOC(
" Compares two dates.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.compare(to: date.literal(\"2024-06-12\"))\n"
" // -> order.Eq\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-05-12\")\n"
" |> date.compare(to: date.literal(\"2024-06-13\"))\n"
" // -> order.Lt\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2034-06-12\")\n"
" |> date.compare(to: date.literal(\"2024-06-11\"))\n"
" // -> order.Gt\n"
" ```\n"
).
-spec compare(tempo:date(), tempo:date()) -> gleam@order:order().
compare(A, B) ->
tempo:date_compare(A, B).
-file("src/tempo/date.gleam", 820).
?DOC(
" Checks of the first date is earlier than the second date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_earlier(than: date.literal(\"2024-06-13\"))\n"
" // -> True\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_earlier(than: date.literal(\"2024-06-12\"))\n"
" // -> False\n"
" ```\n"
).
-spec is_earlier(tempo:date(), tempo:date()) -> boolean().
is_earlier(A, B) ->
tempo:date_is_earlier(A, B).
-file("src/tempo/date.gleam", 838).
?DOC(
" Checks if the first date is earlier than or equal to the second date.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_earlier_or_equal(to: date.literal(\"2024-06-12\"))\n"
" // -> True\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_earlier_or_equal(to: date.literal(\"2024-06-11\"))\n"
" // -> False\n"
" ```\n"
).
-spec is_earlier_or_equal(tempo:date(), tempo:date()) -> boolean().
is_earlier_or_equal(A, B) ->
tempo:date_is_earlier_or_equal(A, B).
-file("src/tempo/date.gleam", 851).
?DOC(
" Checks if two dates are equal.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_equal(to: date.literal(\"2024-06-12\"))\n"
" // -> True\n"
" ```\n"
).
-spec is_equal(tempo:date(), tempo:date()) -> boolean().
is_equal(A, B) ->
tempo:date_is_equal(A, B).
-file("src/tempo/date.gleam", 870).
?DOC(
" Checks if the first date is later than the second date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-14\")\n"
" |> date.is_later(than: date.literal(\"2024-06-13\"))\n"
" // -> True\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_later(than: date.literal(\"2024-06-12\"))\n"
" // -> False\n"
" ```\n"
).
-spec is_later(tempo:date(), tempo:date()) -> boolean().
is_later(A, B) ->
tempo:date_is_later(A, B).
-file("src/tempo/date.gleam", 889).
?DOC(
" Checks if the first date is later than or equal to the second date.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_later_or_equal(to: date.literal(\"2024-06-12\"))\n"
" // -> True\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.is_later_or_equal(to: date.literal(\"2024-06-13\"))\n"
" // -> False\n"
" ```\n"
).
-spec is_later_or_equal(tempo:date(), tempo:date()) -> boolean().
is_later_or_equal(A, B) ->
tempo:date_is_later_or_equal(A, B).
-file("src/tempo/date.gleam", 906).
?DOC(
" Gets the difference between two dates.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.difference(from: date.literal(\"2024-06-12\"), to: date.literal(\"2024-06-23\"))\n"
" // -> 11\n"
" ```\n"
"\n"
" ```gleam\n"
" date.difference(from: date.literal(\"2024-06-03\"), to: date.literal(\"2024-06-11\"))\n"
" // -> 8\n"
" ```\n"
).
-spec difference(tempo:date(), tempo:date()) -> integer().
difference(A, B) ->
tempo:date_days_apart(A, B).
-file("src/tempo/date.gleam", 928).
?DOC(
" Creates a period between the first date at 00:00:00 and the second date at\n"
" 24:00:00. Periods only represent positive datetime differences.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.as_period(end: date.literal(\"2024-06-23\"))\n"
" |> period.as_days\n"
" // -> 11\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.as_period(start: date.literal(\"2024-06-09\"))\n"
" |> period.comprising_dates\n"
" // -> [\"2024-06-09\", \"2024-06-10\", \"2024-06-11\", \"2024-06-12\"]\n"
" ```\n"
).
-spec as_period(tempo:date(), tempo:date()) -> tempo:period().
as_period(Start, End) ->
tempo:period_new_date(Start, End).
-file("src/tempo/date.gleam", 953).
?DOC(
" Adds a number of days to a date, rolling over month and year boundaries\n"
" according to proleptic Gregorian month lengths and leap years.\n"
"\n"
" This is not range checked. Adding enough days will push the date past year\n"
" 9999, and adding a negative number can push it below year 1000, down through\n"
" year zero into negative years. Such dates compare and do arithmetic\n"
" correctly but do not format as valid ISO 8601.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.add(days: 1)\n"
" // -> date.literal(\"2024-06-13\")\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.add(days: 12)\n"
" // -> date.literal(\"2024-06-24\")\n"
" ```\n"
).
-spec add(tempo:date(), integer()) -> tempo:date().
add(Date, Days) ->
tempo:date_add(Date, Days).
-file("src/tempo/date.gleam", 978).
?DOC(
" Subtracts a number of days from a date, rolling back over month and year\n"
" boundaries according to proleptic Gregorian month lengths and leap years.\n"
"\n"
" This is not range checked. Subtracting enough days will push the date below\n"
" year 1000, down through year zero into negative years, and subtracting a\n"
" negative number can push it past year 9999. Such dates compare and do\n"
" arithmetic correctly but do not format as valid ISO 8601.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.subtract(days: 1)\n"
" // -> date.literal(\"2024-06-11\")\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-12\")\n"
" |> date.subtract(days: 12)\n"
" // -> date.literal(\"2024-05-31\")\n"
" ```\n"
).
-spec subtract(tempo:date(), integer()) -> tempo:date().
subtract(Date, Days) ->
tempo:date_subtract(Date, Days).
-file("src/tempo/date.gleam", 995).
?DOC(
" Returns the number of the day of week a date falls on, using the US\n"
" convention of counting Sunday as `0` through Saturday as `6`.\n"
"\n"
" This does *not* follow the ISO 8601 day-of-week numbering (Monday as `1`\n"
" through Sunday as `7`).\n"
"\n"
" The result is the day of the week on the proleptic Gregorian calendar, and\n"
" is exact for every date, with no restricted range. Note though that for\n"
" dates before a region adopted the Gregorian calendar (1582 in Catholic\n"
" Europe, as late as 1923 elsewhere), the result will not match the day of the\n"
" week recorded historically, because those dates were written on the Julian\n"
" calendar and this library reads every date as Gregorian.\n"
).
-spec to_day_of_week_number(tempo:date()) -> integer().
to_day_of_week_number(Date) ->
tempo:date_to_day_of_week_number_us_convention(Date).
-file("src/tempo/date.gleam", 1015).
?DOC(
" Returns the day of week a date falls on, on the proleptic Gregorian\n"
" calendar.\n"
"\n"
" The result is exact for every date, with no restricted range. Note though\n"
" that for dates before a region adopted the Gregorian calendar (1582 in\n"
" Catholic Europe, as late as 1923 elsewhere), the result will not match the\n"
" day of the week recorded historically, because those dates were written on\n"
" the Julian calendar and this library reads every date as Gregorian.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-20\")\n"
" |> date.to_day_of_week\n"
" // -> Thur\n"
" ```\n"
).
-spec to_day_of_week(tempo:date()) -> day_of_week().
to_day_of_week(Date) ->
case tempo:date_to_day_of_week_number_us_convention(Date) of
0 ->
sun;
1 ->
mon;
2 ->
tue;
3 ->
wed;
4 ->
thu;
5 ->
fri;
6 ->
sat;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Invalid day of week found after modulo by 7"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"tempo/date"/utf8>>,
function => <<"to_day_of_week"/utf8>>,
line => 1024})
end.
-file("src/tempo/date.gleam", 1036).
?DOC(
" Returns the short string representation of a day of the week.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date|> tempo.date_get_day_of_week_to_short_string(date.Mon)\n"
" // -> \"Mon\"\n"
" ```\n"
).
-spec day_of_week_to_short_string(day_of_week()) -> binary().
day_of_week_to_short_string(Day_of_week) ->
case Day_of_week of
sun ->
<<"Sun"/utf8>>;
mon ->
<<"Mon"/utf8>>;
tue ->
<<"Tue"/utf8>>;
wed ->
<<"Wed"/utf8>>;
thu ->
<<"Thu"/utf8>>;
fri ->
<<"Fri"/utf8>>;
sat ->
<<"Sat"/utf8>>
end.
-file("src/tempo/date.gleam", 1056).
?DOC(
" Returns the long string representation of a day of the week.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date|> tempo.date_get_day_of_week_to_long_string(date.Fri)\n"
" // -> \"Friday\"\n"
" ```\n"
).
-spec day_of_week_to_long_string(day_of_week()) -> binary().
day_of_week_to_long_string(Day_of_week) ->
case Day_of_week of
sun ->
<<"Sunday"/utf8>>;
mon ->
<<"Monday"/utf8>>;
tue ->
<<"Tuesday"/utf8>>;
wed ->
<<"Wednesday"/utf8>>;
thu ->
<<"Thursday"/utf8>>;
fri ->
<<"Friday"/utf8>>;
sat ->
<<"Saturday"/utf8>>
end.
-file("src/tempo/date.gleam", 1087).
?DOC(
" Gets the date of the next specified day of the week, exclusive of\n"
" the passed date. The result is always 1 to 7 days after the given date.\n"
"\n"
" Days of the week are those of the proleptic Gregorian calendar, as\n"
" described in `to_day_of_week`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-21\")\n"
" |> date.next_day_of_week(date.Mon)\n"
" // -> date.literal(\"2024-06-24\")\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-21\")\n"
" |> date.next_day_of_week(date.Fri)\n"
" // -> date.literal(\"2024-06-28\")\n"
" ```\n"
).
-spec next_day_of_week(tempo:date(), day_of_week()) -> tempo:date().
next_day_of_week(Date, Dow) ->
Next = begin
_pipe = Date,
add(_pipe, 1)
end,
case begin
_pipe@1 = Next,
to_day_of_week(_pipe@1)
end
=:= Dow of
true ->
Next;
false ->
next_day_of_week(Next, Dow)
end.
-file("src/tempo/date.gleam", 1118).
?DOC(
" Gets the date of the prior specified day of the week, exclusive of\n"
" the passed date. The result is always 1 to 7 days before the given date.\n"
"\n"
" Days of the week are those of the proleptic Gregorian calendar, as\n"
" described in `to_day_of_week`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-21\")\n"
" |> date.prior_day_of_week(date.Mon)\n"
" // -> date.literal(\"2024-06-17\")\n"
" ```\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-21\")\n"
" |> date.prior_day_of_week(date.Fri)\n"
" // -> date.literal(\"2024-06-14\")\n"
" ```\n"
).
-spec prior_day_of_week(tempo:date(), day_of_week()) -> tempo:date().
prior_day_of_week(Date, Dow) ->
Prior = begin
_pipe = Date,
subtract(_pipe, 1)
end,
case begin
_pipe@1 = Prior,
to_day_of_week(_pipe@1)
end
=:= Dow of
true ->
Prior;
false ->
prior_day_of_week(Prior, Dow)
end.
-file("src/tempo/date.gleam", 1141).
?DOC(
" Checks if a date falls in a weekend, taking the weekend to be Saturday and\n"
" Sunday of the proleptic Gregorian calendar week. Regions that treat other\n"
" days as the weekend are not accounted for.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-22\")\n"
" |> date.is_weekend\n"
" // -> True\n"
" ```\n"
).
-spec is_weekend(tempo:date()) -> boolean().
is_weekend(Date) ->
case to_day_of_week(Date) of
sat ->
true;
sun ->
true;
_ ->
false
end.
-file("src/tempo/date.gleam", 1158).
?DOC(
" Gets the first date of the Gregorian calendar month a date occurs in, so\n"
" always day 1 of that month.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-06-21\")\n"
" |> date.first_of_month\n"
" // -> date.literal(\"2024-06-01\")\n"
" ```\n"
).
-spec first_of_month(tempo:date()) -> tempo:date().
first_of_month(Date) ->
Calendar_date = tempo:date_to_calendar_date(Date),
_pipe = {date,
erlang:element(2, Calendar_date),
erlang:element(3, Calendar_date),
1},
tempo:date_from_calendar_date(_pipe).
-file("src/tempo/date.gleam", 1175).
?DOC(
" Gets the last date of the Gregorian calendar month a date occurs in, so day\n"
" 28, 29, 30 or 31 depending on the month and whether it is a Gregorian leap\n"
" year.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" date.literal(\"2024-02-13\")\n"
" |> date.last_of_month\n"
" // -> date.literal(\"2024-02-29\")\n"
" ```\n"
).
-spec last_of_month(tempo:date()) -> tempo:date().
last_of_month(Date) ->
Calendar_date = tempo:date_to_calendar_date(Date),
_pipe = {date,
erlang:element(2, Calendar_date),
erlang:element(3, Calendar_date),
tempo@month:days(
erlang:element(3, Calendar_date),
erlang:element(2, Calendar_date)
)},
tempo:date_from_calendar_date(_pipe).