Time Formatting Parsing in Erlang

-module(time_formatting_parsing).
-export([main/0]).

main() ->
    P = fun(X) -> io:format("~p~n", [X]) end,

    % Here's a basic example of formatting a time
    % according to RFC3339, using the corresponding format string.
    T = calendar:universal_time(),
    P(format_time(T, "~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ")),

    % Time parsing uses the same format strings as formatting.
    {ok, T1} = parse_time("2012-11-01T22:08:41Z", "~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ"),
    P(T1),

    % Erlang doesn't have built-in support for as many time formats as Go,
    % but we can create custom formatting functions.
    P(format_time(T, "~2..0B:~2..0B ~s")),
    P(format_time(T, "~s ~s ~2..0B ~2..0B:~2..0B:~2..0B ~4..0B")),
    P(format_time(T, "~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B.~6..0BZ")),

    Form = "~2..0B ~2..0B ~s",
    {ok, T2} = parse_time("8 41 PM", Form),
    P(T2),

    % For purely numeric representations you can also use 
    % standard string formatting with the extracted components of the time value.
    {{Year, Month, Day}, {Hour, Minute, Second}} = T,
    io:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B-00:00~n",
              [Year, Month, Day, Hour, Minute, Second]),

    % parse_time will return an error on malformed input
    % explaining the parsing problem.
    Ansic = "~s ~s ~2..0B ~2..0B:~2..0B:~2..0B ~4..0B",
    case parse_time("8:41PM", Ansic) of
        {error, Reason} -> P(Reason);
        _ -> ok
    end.

format_time({{Year, Month, Day}, {Hour, Minute, Second}}, Format) ->
    DayNames = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    MonthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
    DayName = lists:nth(calendar:day_of_the_week(Year, Month, Day), DayNames),
    MonthName = lists:nth(Month, MonthNames),
    AMPM = if Hour >= 12 -> "PM"; true -> "AM" end,
    Hour12 = (Hour - 1) rem 12 + 1,
    io_lib:format(Format, [Year, Month, Day, Hour, Minute, Second, Hour12, AMPM, DayName, MonthName]).

parse_time(TimeString, Format) ->
    try
        {ok, [Year, Month, Day, Hour, Minute, Second]} = io_lib:fread(Format, TimeString),
        {ok, {{Year, Month, Day}, {Hour, Minute, Second}}}
    catch
        _:_ -> {error, "Parsing error"}
    end.

This Erlang code demonstrates time formatting and parsing, which is conceptually similar to the Go example. However, Erlang doesn’t have as extensive built-in support for time formatting and parsing as Go does, so we’ve had to implement some custom functions to achieve similar functionality.

The format_time/2 function takes a time tuple and a format string, and returns a formatted string. The parse_time/2 function takes a time string and a format string, and returns a time tuple.

We use these functions to demonstrate various time formatting and parsing operations, similar to the original Go example. Note that Erlang uses its own date-time representation (tuples) instead of a dedicated time type like in Go.

The error handling for parsing is also implemented, although it’s more basic than Go’s error handling.

To run this program, save it as time_formatting_parsing.erl and use:

$ erlc time_formatting_parsing.erl
$ erl -noshell -s time_formatting_parsing main -s init stop

This will compile the Erlang file and then run the main/0 function, displaying the results.