Skip to content

Instantly share code, notes, and snippets.

@auxiliaire
Created May 2, 2021 17:18
Show Gist options
  • Select an option

  • Save auxiliaire/d01c2e496beec6d189a6b8a78d162ca5 to your computer and use it in GitHub Desktop.

Select an option

Save auxiliaire/d01c2e496beec6d189a6b8a78d162ca5 to your computer and use it in GitHub Desktop.
Some basic functions for a Gregorian calendar
-module(gregorian).
-export([
days/0,
months/0,
dayTuples/0,
monthTuples/0,
dayOfWeek/1,
monthOfYear/1,
isLeap/1,
daysOfMonth/2,
daysOfYear/1,
prev/2,
next/2,
prevMonth/1,
nextMonth/1,
toDays/1,
toDays/2,
toDays/3,
daysBetween/2,
daysSince/3
]).
days() -> [ mon, tue, wed, thu, fri, sat, sun ].
months() -> [ jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec ].
dayTuples() -> lists:zip(lists:seq(1, 7), days()).
monthTuples() -> lists:zip(lists:seq(1, 12), months()).
dayOfWeek(N) when is_integer(N) -> lists:keyfind(N, 1, dayTuples());
dayOfWeek(N) when is_atom(N) -> lists:keyfind(N, 2, dayTuples()).
monthOfYear(N) when is_integer(N) -> lists:keyfind(N, 1, monthTuples());
monthOfYear(N) when is_atom(N) -> lists:keyfind(N, 2, monthTuples()).
isLeap(Y) ->
if Y rem 400 =:= 0 -> true
; Y rem 100 =:= 0 -> false
; Y rem 4 =:= 0 -> true
; true -> false
end.
daysOfMonth(M, Y) when M =:= feb ->
case isLeap(Y) of
true -> 29;
false -> 28
end;
daysOfMonth(M, _) when true ->
case lists:member(M, [ apr, jun, sep, nov ]) of
true -> 30;
false -> 31
end.
daysOfYear(Y) -> lists:sum([ daysOfMonth(M, Y) || M <- months() ]).
prev(E, [ H | T ]) ->
case E =:= H of
true -> lists:last(T);
false -> lists:last(lists:takewhile(fun(X) -> X =/= E end, [ H | T ]))
end.
next(E, L) ->
case E =:= lists:last(L) of
true -> hd(L);
false -> hd(tl(lists:dropwhile(fun(X) -> X =/= E end, L)))
end.
prevMonth(M) -> prev(M, months()).
nextMonth(M) -> next(M, months()).
%% Real Gregorian days, not ISO standard Year 0 BS!
toDays(Y, M, D) -> D - 1 + toDays(Y, M).
toDays(Y, M) when M =:= jan -> toDays(Y);
toDays(Y, M) when true ->
P = prevMonth(M),
daysOfMonth(P, Y) + toDays(Y, P).
toDays(Y) when Y =< 1 -> 0;
toDays(Y) when true -> daysOfYear(Y) + toDays(Y - 1).
daysBetween({Y1, M1, D1}, {Y2, M2, D2}) -> toDays(Y2, M2, D2) - toDays(Y1, M1, D1).
daysSince(Y, M, D) ->
{{CY, CMN, CD}, _} = calendar:now_to_local_time(erlang:timestamp()),
CM = element(2, monthOfYear(CMN)),
daysBetween({Y, M, D}, {CY, CM, CD}).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment