cross_time_calculation 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/README.markdown +26 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/cross_time_calculation.gemspec +16 -0
- data/lib/cross_time_calculation.rb +66 -0
- data/test/test_cross_time_calculation.rb +77 -0
- metadata +53 -0
data/.gitignore
ADDED
data/README.markdown
ADDED
@@ -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
|
data/Rakefile
ADDED
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
|