源战役
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 line
3.7 KiB

  1. %%% -------------------------------------------------------
  2. %%% @author huangyongxing@yeah.net
  3. %%% @doc
  4. %%% 测试计算日期跨度的两种接口效率
  5. %%% @end
  6. %%% -------------------------------------------------------
  7. -module(test_day_span).
  8. -export([
  9. test/1
  10. ]).
  11. -include("common.hrl").
  12. %% 测试运行100w次,
  13. %% 结果表明,使用格里高利历天数对比效率更高,大约耗时是另一种方法的70%
  14. %% test_day_span:test(300000).
  15. %% "my calc day_span1" [total: 266(266)ms avg: 0.887(0.887)us]
  16. %% "use gregorian_days" [total: 172(187)ms avg: 0.573(0.623)us]
  17. %% ========================================================================
  18. %% my calc day_span1 = 266.00ms [ 100.00%] 266.00ms [ 100.00%]
  19. %% use gregorian_days = 172.00ms [ 64.66%] 187.00ms [ 70.30%]
  20. %% ========================================================================
  21. test(N) ->
  22. T1 = utime:unixtime(),
  23. T2 = utime:unixtime() - urand:rand(1000000, 9000000),
  24. Fun1 = fun(_) -> day_span1(T1, T2) end,
  25. Fun2 = fun(_) -> day_span2(T1, T2) end,
  26. ptester:run(N, [
  27. {"my calc day_span1", Fun1},
  28. {"use gregorian_days", Fun2}
  29. ]).
  30. day_span1(Unixtime1, Unixtime2) ->
  31. get_diff_day(Unixtime1, Unixtime2) + 1.
  32. day_span2(Unixtime1, Unixtime2) ->
  33. {D1, _} = utime:unixtime_to_localtime(Unixtime1),
  34. {D2, _} = utime:unixtime_to_localtime(Unixtime2),
  35. calendar:date_to_gregorian_days(D1) - calendar:date_to_gregorian_days(D2).
  36. %% 原utime中的get_diff_day
  37. %% 早期不兼容夏令时的时候,少一次unixdate及相关调用,测试过比用格里高利历的稍快,
  38. %% 加上针对夏令时的逻辑处理,重新测试结果已经不及格里高利历天数的计算方式)
  39. get_diff_day(Seconds, Seconds) -> 0;
  40. get_diff_day(Seconds1, Seconds2) ->
  41. Midnight1 = utime:unixdate(Seconds1),
  42. Midnight2 = utime:unixdate(Seconds2),
  43. DiffSecs = Midnight1 - Midnight2,
  44. DiffDays = abs(DiffSecs div ?ONE_DAY_SECONDS),
  45. Remainder = DiffSecs rem ?ONE_DAY_SECONDS,
  46. case Remainder =:= 0 of
  47. true -> % 整除意味着两个时刻同处于夏令时、非夏令时或地区无夏令时制
  48. DiffDays;
  49. false -> % 两个时刻中有一个处于夏令时中
  50. %% 由于各地夏令时规定的调整时长不明确,
  51. %% 有半小时有一小时,总之不可能太长,所以以3小时为界。
  52. %% 余数少于3小时说明跨越“结束夏令时”的时间点,应向下取整
  53. %% 余数多于3小时说明跨越“进入夏令时”的时间点,应向上取整
  54. case abs(Remainder) < 10800 of
  55. true -> DiffDays;
  56. false -> DiffDays + 1
  57. end
  58. end.
  59. % %% 此方法存在夏令时问题
  60. % %% 返回结果为两个UNIX时间戳的日期跨度,例如:同一天和相邻2天,返回结果为1和2(而非0和1)
  61. % %% 经测试,与分别使用calendar:date_to_gregorian_days/1转换为两个格里高利历天数进行比较,
  62. % %% 运行30w次,这个方法耗时约0.175秒,转换为格里高历利天数计算约需0.198秒
  63. % get_diff_day(Seconds, Seconds) -> 0;
  64. % get_diff_day(Seconds1, Seconds2) ->
  65. % {_Date, Time} = unixtime_to_localtime(Seconds1),
  66. % DiffSecs = Seconds1 - calendar:time_to_seconds(Time) - Seconds2,
  67. % DiffDays = DiffSecs div ?ONE_DAY_SECONDS,
  68. % Remainder = DiffSecs rem ?ONE_DAY_SECONDS,
  69. % case DiffSecs > 0 of
  70. % true -> % 第一个时间的0点比第二个时间大
  71. % case Remainder =:= 0 of
  72. % true -> 0;
  73. % false -> 1 % 并且不整除(第二个时间非0点),diff days少算了一天,要加1
  74. % end
  75. % + DiffDays;
  76. % false ->
  77. % - DiffDays
  78. % end.