%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% 测试计算日期跨度的两种接口效率
%%% @end
%%% -------------------------------------------------------
-module(test_day_span).
-export([
        test/1
    ]).

-include("common.hrl").

%% 测试运行100w次，
%% 结果表明，使用格里高利历天数对比效率更高，大约耗时是另一种方法的70%
%% test_day_span:test(300000).
%% "my calc day_span1" [total: 266(266)ms avg: 0.887(0.887)us]
%% "use gregorian_days" [total: 172(187)ms avg: 0.573(0.623)us]
%% ========================================================================
%%    my calc day_span1 =    266.00ms [  100.00%]    266.00ms [  100.00%]
%%   use gregorian_days =    172.00ms [   64.66%]    187.00ms [   70.30%]
%% ========================================================================
test(N) ->
    T1 = utime:unixtime(),
    T2 = utime:unixtime() - urand:rand(1000000, 9000000),
    Fun1 = fun(_) -> day_span1(T1, T2) end,
    Fun2 = fun(_) -> day_span2(T1, T2) end,
    ptester:run(N, [
            {"my calc day_span1", Fun1},
            {"use gregorian_days", Fun2}
        ]).

day_span1(Unixtime1, Unixtime2) ->
    get_diff_day(Unixtime1, Unixtime2) + 1.

day_span2(Unixtime1, Unixtime2) ->
    {D1, _} = utime:unixtime_to_localtime(Unixtime1),
    {D2, _} = utime:unixtime_to_localtime(Unixtime2),
    calendar:date_to_gregorian_days(D1) - calendar:date_to_gregorian_days(D2).

%% 原utime中的get_diff_day
%% 早期不兼容夏令时的时候，少一次unixdate及相关调用，测试过比用格里高利历的稍快，
%% 加上针对夏令时的逻辑处理，重新测试结果已经不及格里高利历天数的计算方式）
get_diff_day(Seconds, Seconds) -> 0;
get_diff_day(Seconds1, Seconds2) ->
    Midnight1 = utime:unixdate(Seconds1),
    Midnight2 = utime:unixdate(Seconds2),
    DiffSecs  = Midnight1 - Midnight2,
    DiffDays  = abs(DiffSecs div ?ONE_DAY_SECONDS),
    Remainder = DiffSecs rem ?ONE_DAY_SECONDS,
    case Remainder =:= 0 of
        true  ->    % 整除意味着两个时刻同处于夏令时、非夏令时或地区无夏令时制
            DiffDays;
        false ->    % 两个时刻中有一个处于夏令时中
            %% 由于各地夏令时规定的调整时长不明确，
            %% 有半小时有一小时，总之不可能太长，所以以3小时为界。
            %% 余数少于3小时说明跨越“结束夏令时”的时间点，应向下取整
            %% 余数多于3小时说明跨越“进入夏令时”的时间点，应向上取整
            case abs(Remainder) < 10800 of
                true  -> DiffDays;
                false -> DiffDays + 1
            end
    end.

% %% 此方法存在夏令时问题
% %% 返回结果为两个UNIX时间戳的日期跨度，例如：同一天和相邻2天，返回结果为1和2（而非0和1）
% %% 经测试，与分别使用calendar:date_to_gregorian_days/1转换为两个格里高利历天数进行比较，
% %% 运行30w次，这个方法耗时约0.175秒，转换为格里高历利天数计算约需0.198秒
% get_diff_day(Seconds, Seconds) -> 0;
% get_diff_day(Seconds1, Seconds2) ->
%     {_Date, Time} = unixtime_to_localtime(Seconds1),
%     DiffSecs = Seconds1 - calendar:time_to_seconds(Time) - Seconds2,
%     DiffDays = DiffSecs div ?ONE_DAY_SECONDS,
%     Remainder = DiffSecs rem ?ONE_DAY_SECONDS,
%     case DiffSecs > 0 of
%         true  -> % 第一个时间的0点比第二个时间大
%             case Remainder =:= 0 of
%                 true  -> 0;
%                 false -> 1 % 并且不整除(第二个时间非0点)，diff days少算了一天，要加1
%             end
%             + DiffDays;
%         false ->
%             - DiffDays
%     end.

