-module(ephp_datetime). -author('manuel@altenwald.com'). -compile([warnings_as_errors]). -include("ephp.hrl"). -export([ 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 ]). -spec get_tz(context(), 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()) -> timer: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(calendar: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(calendar: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(calendar: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(calendar: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() -> os: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:date(), string() | binary()) -> boolean(). is_dst(Date, RawTZ) -> TZ = normalize_tz(RawTZ), ezic:has_dst_local(Date, TZ). -spec to_zone(calendar:datetime(), 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.