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