cross_time_calculation 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ *.swp
2
+ .DS_Store
3
+ *.gem
@@ -0,0 +1,26 @@
1
+ Cross Time calculation
2
+ ==================================================
3
+ If you want to compute the same user's online time from server log, who comes from multiple clients, so you need to remove duplicate parts.
4
+
5
+ Installation
6
+ --------------------------------------------------
7
+ ```zsh
8
+ gem install cross_time_calculation
9
+ ```
10
+
11
+ Usage
12
+ --------------------------------------------------
13
+
14
+ ```ruby
15
+ require 'time'
16
+ require 'cross_time_calculation'
17
+
18
+ @t1 = DateTime.parse("20130512").to_time
19
+ @t2 = @t1 + 33
20
+ @ctc = CrossTimeCalculation.new
21
+ @ctc.add @t1, @t2
22
+
23
+ @ctc.total_seconds # => 33
24
+ ```
25
+
26
+ See more complicated example in unit test
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ desc "Run tests"
10
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'cross_time_calculation'
5
+ s.version = File.read("VERSION").strip
6
+ s.date = '2013-06-09'
7
+ s.summary = "Cross Time calculation"
8
+ s.description = File.read("README.markdown").split("\n\n")[0].split(/====+/)[1].strip
9
+ s.authors = ["David Chen"]
10
+ s.email = 'mvjome@gmail.com'
11
+ s.homepage = 'http://github.com/mvj3/cross_time_calculation'
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = Dir.glob("test/**/*.rb")
15
+ s.require_paths = ["lib"]
16
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: UTF-8
2
+
3
+ class CrossTimeCalculation
4
+ TimePoint = Struct.new(:t, :status) if not defined? TimePoint
5
+ attr_accessor :time_points
6
+
7
+ def initialize
8
+ self.time_points = Array.new
9
+ end
10
+
11
+ def add *time_begin_and_end
12
+ # init TimePoint pair
13
+ tb = TimePoint.new(time_begin_and_end[0], :started_at)
14
+ te = TimePoint.new(time_begin_and_end[1], :finished_at)
15
+
16
+ # validate data
17
+ raise "At least the begin time should exist" if not tb.t
18
+ raise "The begin time should not larger than the end time" if te.t && (tb.t > te.t)
19
+
20
+ # insert it and sort
21
+ self.time_points << tb
22
+ self.time_points << te if te.t
23
+ self.time_points = self.time_points.uniq {|i| "#{i.t}#{i.status}" }.sort {|a, b| a.t.to_i <=> b.t.to_i }
24
+
25
+ # TODO optimize search with idx
26
+ loop do
27
+ to_removes = []
28
+ self.time_points.each_with_index do |tp, idx|
29
+ post_tp = self.time_points[idx+1]
30
+ next if post_tp.nil?
31
+ # delete the first one if they are all finished_at
32
+ to_removes << tp if (tp.status == :finished_at) && (post_tp.status == :finished_at)
33
+ # delete the later one if they are all started_at
34
+ to_removes << post_tp if (tp.status == :started_at) && (post_tp.status == :started_at)
35
+ end
36
+ self.time_points -= to_removes
37
+
38
+ break if data_valid?
39
+ end
40
+
41
+ return self
42
+ end
43
+
44
+ def total_seconds
45
+ result = 0
46
+ self.time_points.each_slice(2) do |a|
47
+ end_time = a[1] ? a[1].t : Time.now
48
+ if a[0] && a[0].t
49
+ t = (end_time - a[0].t)
50
+ result += t
51
+ end
52
+ end
53
+ result
54
+ end
55
+
56
+ # start time and end time interval is supposed to exist
57
+ def data_valid?
58
+ valids = []
59
+ self.time_points.each_slice(2) do |tp_start, tp_finish|
60
+ next if tp_finish.nil?
61
+ valids << (tp_start.status != tp_finish.status)
62
+ end
63
+ valids.count(false).zero?
64
+ end
65
+
66
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test/unit'
4
+ require 'time'
5
+ require 'cross_time_calculation'
6
+
7
+ class TestCrossTimeCalculation < Test::Unit::TestCase
8
+ def setup
9
+ # the first pair
10
+ @t1 = DateTime.parse("20130512").to_time
11
+ @t2 = @t1 + 33
12
+
13
+ @ctc = CrossTimeCalculation.new
14
+ @ctc.add @t1, @t2
15
+
16
+ # the second pair
17
+ @t3 = DateTime.parse("20130512 10:51:03").to_time
18
+ @t4 = DateTime.parse("20130512 14:21:24").to_time
19
+
20
+ # the third pair
21
+ @t5 = DateTime.parse("20130512 18:32:28").to_time
22
+ @t6 = DateTime.parse("20130512 23:19:31").to_time
23
+
24
+ # the forth pair crossed with the third pair
25
+ @t7 = DateTime.parse("20130512 20").to_time
26
+ @t8 = DateTime.parse("20130513 13").to_time
27
+ end
28
+
29
+ def test_empty
30
+ assert_equal CrossTimeCalculation.new.total_seconds, 0
31
+ end
32
+
33
+ def test_no_time_end
34
+ assert_nothing_raised do
35
+ @ctc.add Time.now
36
+ end
37
+ end
38
+
39
+ def test_one_time_point
40
+ assert_equal @ctc.total_seconds, 33
41
+ end
42
+
43
+ def test_more_time_points
44
+ @ctc.add @t3, @t4
45
+ @ctc.add @t5, @t6
46
+ compute = (@t2 - @t1) + (@t4 - @t3) + (@t6 - @t5)
47
+ compare = (@ctc.total_seconds - compute).abs < 1
48
+ assert_equal compare, true
49
+ end
50
+
51
+ def test_more_time_points_with_cross
52
+ assert_equal load_more_time_points, true
53
+ end
54
+
55
+ def test_dup_time_points_with_cross
56
+ assert_equal load_more_time_points(true), true
57
+ end
58
+
59
+ private
60
+ def load_more_time_points dup = false
61
+ @ctc.add @t3, @t4
62
+ @ctc.add @t5, @t6
63
+ @ctc.add @t7, @t8
64
+ @ctc.add @t7, @t8 if dup
65
+
66
+ # user array to count appeared second
67
+ @seconds = []
68
+ [[@t1, @t2], [@t3, @t4], [@t5, @t6], [@t7, @t8], (dup ? [@t7, @t8] : nil)].compact.each do |tb, te|
69
+ next if tb.nil?
70
+ new_idx = tb - @t1
71
+ (te-tb).to_i.times {|idx| @seconds[new_idx+idx] = 1 }
72
+ end
73
+
74
+ (@seconds.count(1) - @ctc.total_seconds).abs < 3
75
+ end
76
+
77
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cross_time_calculation
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Chen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-09 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: If you want to compute the same user's online time from server log, who
15
+ comes from multiple clients, so you need to remove duplicate parts.
16
+ email: mvjome@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - README.markdown
23
+ - Rakefile
24
+ - VERSION
25
+ - cross_time_calculation.gemspec
26
+ - lib/cross_time_calculation.rb
27
+ - test/test_cross_time_calculation.rb
28
+ homepage: http://github.com/mvj3/cross_time_calculation
29
+ licenses: []
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.25
49
+ signing_key:
50
+ specification_version: 3
51
+ summary: Cross Time calculation
52
+ test_files:
53
+ - test/test_cross_time_calculation.rb