Current section
Files
Jump to
Current section
Files
src/ephp_datetime.erl
-module(ephp_datetime).
-author('manuel@altenwald.com').
-include("ephp.hrl").
-export([get_tz_version/0, get_tz/2, set_tz/1, get_abbr_weekday/1, get_abbr_month/1,
get_timestamp/1, get_month/1, get_weekday/1, posix_time/0, posix_time_ms/0, timestamp/0,
is_dst/2, to_zone/2, get_datetime/1, to_bmt/1, get_tz_time/3]).
-type month() :: 1..12.
-type daynum() :: 1..7.
get_tz_version(Name) when Name =:= "rebar3" orelse Name =:= undefined ->
Filename = "tzdata/version",
FullFilename =
filename:join(
code:priv_dir(ezic), Filename),
{ok, Content} = file:read_file(FullFilename),
Content;
get_tz_version(Name) ->
{ok, Sections} = escript:extract(Name, []),
Zip = proplists:get_value(archive, Sections),
Opts = [{file_list, ["ezic/priv/tzdata/version"]}, memory],
{ok, [{_, ZipContent}]} = zip:extract(Zip, Opts),
ZipContent.
-spec get_tz_version() -> binary().
get_tz_version() ->
try
Name =
filename:basename(
escript:script_name()),
get_tz_version(Name)
catch
error:{badmatch, []} ->
get_tz_version(undefined)
end.
-spec get_tz(ephp:context_id(), line()) -> binary().
get_tz(Context, Line) ->
case ephp_config:get(<<"date.timezone">>) of
undefined ->
File = ephp_context:get_active_file(Context),
ephp_error:handle_error(Context,
{error, enotimezone, Line, File, ?E_WARNING, {<<"date">>}}),
?PHP_DEFAULT_TIMEZONE;
Timezone ->
Timezone
end.
-spec set_tz(binary()) -> boolean().
set_tz(TZ) ->
case ephp_timezone:is_valid(TZ) of
true ->
ephp_config:set(<<"date.timezone">>, TZ),
true;
false ->
false
end.
-spec get_timestamp(TS :: integer() | float()) -> erlang:timestamp().
get_timestamp(Timestamp) ->
M = trunc(Timestamp) div 1000000,
S = trunc(Timestamp) rem 1000000,
U = trunc(Timestamp * 1000000) rem 1000000,
{M, S, U}.
-spec get_abbr_month(month()) -> binary().
get_abbr_month(1) ->
<<"Jan">>;
get_abbr_month(2) ->
<<"Feb">>;
get_abbr_month(3) ->
<<"Mar">>;
get_abbr_month(4) ->
<<"Apr">>;
get_abbr_month(5) ->
<<"May">>;
get_abbr_month(6) ->
<<"Jun">>;
get_abbr_month(7) ->
<<"Jul">>;
get_abbr_month(8) ->
<<"Aug">>;
get_abbr_month(9) ->
<<"Sep">>;
get_abbr_month(10) ->
<<"Oct">>;
get_abbr_month(11) ->
<<"Nov">>;
get_abbr_month(12) ->
<<"Dec">>.
-spec get_month(month()) -> binary().
get_month(1) ->
<<"January">>;
get_month(2) ->
<<"February">>;
get_month(3) ->
<<"March">>;
get_month(4) ->
<<"April">>;
get_month(5) ->
<<"May">>;
get_month(6) ->
<<"June">>;
get_month(7) ->
<<"July">>;
get_month(8) ->
<<"August">>;
get_month(9) ->
<<"September">>;
get_month(10) ->
<<"October">>;
get_month(11) ->
<<"November">>;
get_month(12) ->
<<"December">>.
-spec get_abbr_weekday(daynum()) -> binary().
get_abbr_weekday(1) ->
<<"Mon">>;
get_abbr_weekday(2) ->
<<"Tue">>;
get_abbr_weekday(3) ->
<<"Wed">>;
get_abbr_weekday(4) ->
<<"Thu">>;
get_abbr_weekday(5) ->
<<"Fri">>;
get_abbr_weekday(6) ->
<<"Sat">>;
get_abbr_weekday(7) ->
<<"Sun">>.
-spec get_weekday(daynum()) -> binary().
get_weekday(1) ->
<<"Monday">>;
get_weekday(2) ->
<<"Tuesday">>;
get_weekday(3) ->
<<"Wednesday">>;
get_weekday(4) ->
<<"Thursday">>;
get_weekday(5) ->
<<"Friday">>;
get_weekday(6) ->
<<"Saturday">>;
get_weekday(7) ->
<<"Sunday">>.
-spec posix_time() -> integer().
posix_time() ->
{MS, S, _} = timestamp(),
MS * 1000000 + S.
-spec posix_time_ms() -> integer().
posix_time_ms() ->
{MS, S, MiS} = timestamp(),
(MS * 1000000 + S) * 1000 + MiS div 1000.
-spec timestamp() -> erlang:timestamp().
-ifndef(TEST).
%% @doc Show timestamp. This function makes possible to overload the normal
%% Erlang behaviour to make tests reliable.
%% @end
timestamp() ->
os:timestamp().
-else.
%% @private
timestamp() ->
{1474, 806235, 701464}.
-endif.
-spec normalize_tz(string() | binary()) -> string().
normalize_tz(TZ) when is_binary(TZ) ->
normalize_tz(binary_to_list(TZ));
normalize_tz("UTC") ->
"Etc/UTC";
normalize_tz("GMT") ->
"Etc/GMT";
%% TODO: normalize more timezones and throw error...
normalize_tz(Zone) ->
Zone.
-spec is_dst(calendar:datetime(), string() | binary()) -> boolean().
is_dst(Datetime, RawTZ) ->
TZ = normalize_tz(RawTZ),
ezic:has_dst_local(Datetime, TZ).
-spec to_zone(calendar:date(), string() | binary()) -> calendar:datetime().
to_zone(Date, RawTZ) ->
TZ = normalize_tz(RawTZ),
ezic:utc_to_local(
calendar:now_to_universal_time(Date), TZ).
-spec get_datetime(pos_integer()) -> calendar:datetime().
get_datetime(Timestamp) when is_number(Timestamp) ->
{_, _, _} = T = get_timestamp(Timestamp),
calendar:now_to_datetime(T).
-spec to_bmt(calendar:datetime()) -> pos_integer().
to_bmt(DateTime) ->
{_, {H, M, S}} = ezic:utc_to_local(DateTime, "Etc/GMT-1"),
trunc(((H * 60 + M) * 60 + S) / 86.4).
-spec get_tz_time(calendar:datetime(), string() | binary(), binary()) -> binary().
get_tz_time(DateTime, TZ, Sep) ->
UTCDateTime = ezic:local_to_utc(DateTime, normalize_tz(TZ)),
UTCTime = calendar:datetime_to_gregorian_seconds(UTCDateTime),
Time = calendar:datetime_to_gregorian_seconds(DateTime),
case UTCTime - Time of
Diff when Diff =< 0 ->
<<"+",
(ephp_data:pad_to_bin(abs(Diff div 3600), 2))/binary,
Sep/binary,
(ephp_data:pad_to_bin(abs(Diff rem 3600), 2))/binary>>;
Diff when Diff > 0 ->
<<"-",
(ephp_data:pad_to_bin(Diff div 3600, 2))/binary,
Sep/binary,
(ephp_data:pad_to_bin(Diff rem 3600, 2))/binary>>
end.