%%% -------------------------------------------------------
|
|
%%% @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.
|
|
|