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