numru-units 1.7.0
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/ChangeLog +111 -0
- data/LICENSE.txt +34 -0
- data/Makefile +14 -0
- data/Rakefile +39 -0
- data/doc/Makefile +5 -0
- data/doc/units.html +241 -0
- data/doc/units.rd +232 -0
- data/install.rb +104 -0
- data/lib/numru/units.rb +3505 -0
- data/src/Makefile +35 -0
- data/src/dcunits.txt +212 -0
- data/src/lex.rb +434 -0
- data/src/makeutab.rb +87 -0
- data/src/mulnode.rb +150 -0
- data/src/namenode.rb +63 -0
- data/src/node.rb +210 -0
- data/src/numbernode.rb +53 -0
- data/src/pownode.rb +98 -0
- data/src/rules.rb +65 -0
- data/src/shiftnode.rb +63 -0
- data/src/test.rb +122 -0
- data/src/timenode.rb +136 -0
- data/src/units.racc +2728 -0
- data/src/units.rb +3505 -0
- data/src/units.rd +139 -0
- data/src/utab.rb +1456 -0
- metadata +96 -0
data/src/numbernode.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
class NumberNode < TerminalNode
|
2
|
+
|
3
|
+
def initialize(arg)
|
4
|
+
raise TypeError unless Numeric === arg
|
5
|
+
@a = arg
|
6
|
+
end
|
7
|
+
|
8
|
+
UNITY = NumberNode.new(1)
|
9
|
+
ZERO = NumberNode.new(0)
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
if @a == @a.to_i
|
13
|
+
sprintf("%d",@a)
|
14
|
+
else
|
15
|
+
String(@a)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :a
|
20
|
+
|
21
|
+
alias :value :a
|
22
|
+
alias :factor :a
|
23
|
+
|
24
|
+
def == (other)
|
25
|
+
case other
|
26
|
+
when NumberNode
|
27
|
+
@a == other.a
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_eval(another)
|
34
|
+
raise TypeError unless NumberNode === another
|
35
|
+
NumberNode.new(@a + another.value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def mul_eval(another)
|
39
|
+
case another
|
40
|
+
when NumberNode then NumberNode.new(@a * another.a)
|
41
|
+
when PowNode
|
42
|
+
raise TypeError unless NumberNode === another.lhs
|
43
|
+
raise TypeError unless NumberNode === another.rhs
|
44
|
+
NumberNode.new(@a * Units::pow_f(another.lhs.value, another.rhs.value))
|
45
|
+
else raise TypeError
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def name; "1"; end
|
50
|
+
|
51
|
+
def power; UNITY; end
|
52
|
+
|
53
|
+
end
|
data/src/pownode.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
class PowNode < ContainerNode
|
2
|
+
|
3
|
+
include BinaryNode
|
4
|
+
|
5
|
+
def initialize(lhs, rhs)
|
6
|
+
@lhs, @rhs = lhs, rhs
|
7
|
+
raise TypeError unless NumberNode === @rhs
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
lhs = @lhs.to_s
|
12
|
+
case lhs
|
13
|
+
when /\d$/, /[\d\.]/
|
14
|
+
lhs = "(#{lhs})"
|
15
|
+
end
|
16
|
+
rhs = @rhs.to_s
|
17
|
+
if rhs == '1'
|
18
|
+
lhs
|
19
|
+
else
|
20
|
+
rhs = "^(#{rhs})" if (/\./ =~ rhs)
|
21
|
+
lhs + rhs
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :lhs, :rhs
|
26
|
+
alias :power :rhs
|
27
|
+
|
28
|
+
def pow_eval(other)
|
29
|
+
case other
|
30
|
+
when NumberNode
|
31
|
+
PowNode.new(@lhs, @rhs.mul_eval(other))
|
32
|
+
else
|
33
|
+
super(other)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def flatten2
|
38
|
+
x = @lhs.flatten2
|
39
|
+
case x
|
40
|
+
when NumberNode
|
41
|
+
a = @lhs.pow_eval(@rhs)
|
42
|
+
when TerminalNode
|
43
|
+
a = self
|
44
|
+
when PowNode
|
45
|
+
a = PowNode.new(x.lhs, x.rhs.mul_eval(@rhs))
|
46
|
+
when MulNode, MultiNode
|
47
|
+
a = MultiNode.new()
|
48
|
+
for gc in x
|
49
|
+
a.append(gc.pow_eval(@rhs))
|
50
|
+
end
|
51
|
+
else
|
52
|
+
raise "internal error"
|
53
|
+
end
|
54
|
+
return a
|
55
|
+
end
|
56
|
+
|
57
|
+
def name
|
58
|
+
case @lhs
|
59
|
+
when NumberNode, NameNode
|
60
|
+
@lhs.name
|
61
|
+
else
|
62
|
+
raise "internal error"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def value
|
67
|
+
case @lhs
|
68
|
+
when NumberNode
|
69
|
+
Units::pow_f(@lhs.value, @rhs.value)
|
70
|
+
else
|
71
|
+
raise(format('%s#value: internal error', self.class.to_s))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def mul_eval(another)
|
76
|
+
raise "internal error (#{name}, #{another.name})" if name != another.name
|
77
|
+
case @lhs
|
78
|
+
when NumberNode
|
79
|
+
NumberNode.new(Units::pow_f(@lhs.value, @rhs.value) * another.value)
|
80
|
+
else
|
81
|
+
self.class.new(@lhs, @rhs.add_eval(another.power))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def sort
|
86
|
+
case @lhs
|
87
|
+
when NumberNode
|
88
|
+
NumberNode.new(Units::pow_f(@lhs.value, @rhs.value))
|
89
|
+
else
|
90
|
+
self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def factor
|
95
|
+
Units::pow_f(@lhs.factor, @rhs.value)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
data/src/rules.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
class Units
|
2
|
+
|
3
|
+
token INT ERR SHIFT SPACE MULTIPLY DIVIDE EXPONENT REAL NAME DATE TIME ZONE
|
4
|
+
options no_result_var
|
5
|
+
|
6
|
+
rule
|
7
|
+
|
8
|
+
unit_spec:
|
9
|
+
/* { yyaccept; } */ /* <-- to acccept empty unit_spec */
|
10
|
+
| origin_exp { yyaccept; }
|
11
|
+
| error { yyerrok }
|
12
|
+
;
|
13
|
+
|
14
|
+
origin_exp:
|
15
|
+
unit_exp
|
16
|
+
| unit_exp SHIFT value_exp { val[0].shift(val[2]) }
|
17
|
+
| unit_exp SHIFT timestamp { val[0].shift(val[2]) }
|
18
|
+
;
|
19
|
+
|
20
|
+
unit_exp:
|
21
|
+
power_exp
|
22
|
+
| number_exp
|
23
|
+
| unit_exp power_exp { val[0].mul(val[1]) }
|
24
|
+
| unit_exp MULTIPLY power_exp { val[0].mul(val[2]) }
|
25
|
+
| unit_exp DIVIDE power_exp { val[0].divide(val[2]) }
|
26
|
+
| unit_exp MULTIPLY number_exp { val[0].mul(val[2]) }
|
27
|
+
| unit_exp DIVIDE number_exp { val[0].divide(val[2]) }
|
28
|
+
;
|
29
|
+
|
30
|
+
power_exp:
|
31
|
+
NAME { NameNode.new(val[0]) }
|
32
|
+
| power_exp number_exp { val[0].pow(val[1]) }
|
33
|
+
| power_exp EXPONENT value_exp { val[0].pow(val[2]) }
|
34
|
+
| '(' origin_exp ')' { val[1] }
|
35
|
+
;
|
36
|
+
|
37
|
+
value_exp:
|
38
|
+
number_exp
|
39
|
+
| '(' value_exp ')' { val[1] }
|
40
|
+
;
|
41
|
+
|
42
|
+
number_exp:
|
43
|
+
INT { NumberNode.new(val[0]) }
|
44
|
+
| REAL { NumberNode.new(val[0]) }
|
45
|
+
;
|
46
|
+
|
47
|
+
timestamp:
|
48
|
+
time_exp
|
49
|
+
| '(' timestamp ')' { val[1] }
|
50
|
+
;
|
51
|
+
|
52
|
+
time_exp:
|
53
|
+
DATE { TimeNode.new(val[0], 0.0, 0) }
|
54
|
+
| DATE TIME { TimeNode.new(val[0], val[1], 0) }
|
55
|
+
| DATE TIME ZONE { TimeNode.new(val[0], val[1], val[2]) }
|
56
|
+
;
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
---- header
|
61
|
+
|
62
|
+
require 'date'
|
63
|
+
|
64
|
+
---- inner
|
65
|
+
|
data/src/shiftnode.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
class ShiftNode < ContainerNode
|
2
|
+
|
3
|
+
include BinaryNode
|
4
|
+
|
5
|
+
def initialize(lhs, rhs)
|
6
|
+
@lhs, @rhs = lhs, rhs
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :lhs, :rhs
|
10
|
+
alias :ref :rhs
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"(#{@lhs.to_s} @ #{@rhs.to_s})"
|
14
|
+
end
|
15
|
+
|
16
|
+
def trim2; @lhs; end
|
17
|
+
def trim
|
18
|
+
self.class.new(@lhs.trim, @rhs.trim2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def flatten2; @lhs; end
|
22
|
+
def flatten
|
23
|
+
lf = @lhs.flatten
|
24
|
+
case lf
|
25
|
+
when ShiftNode
|
26
|
+
rf = lf.rhs.add_eval(@rhs)
|
27
|
+
self.class.new(lf.lhs, rf)
|
28
|
+
else
|
29
|
+
self.class.new(lf, @rhs.flatten)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def sort
|
34
|
+
self.class.new(@lhs.sort, @rhs.sort)
|
35
|
+
end
|
36
|
+
|
37
|
+
def ref
|
38
|
+
case @lhs
|
39
|
+
when ShiftNode
|
40
|
+
@lhs.ref.add_eval(@rhs)
|
41
|
+
else
|
42
|
+
@rhs
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def deref
|
47
|
+
case @lhs
|
48
|
+
when ShiftNode
|
49
|
+
@lhs.deref
|
50
|
+
else
|
51
|
+
@lhs
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def name
|
56
|
+
@lhs.name
|
57
|
+
end
|
58
|
+
|
59
|
+
def factor
|
60
|
+
@lhs.factor
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/src/test.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'units' # Use require "numru/units" after installation.
|
2
|
+
include NumRu
|
3
|
+
|
4
|
+
def assert(test, seikai)
|
5
|
+
raise "#{test.inspect} != #{seikai.inspect}" if test != seikai
|
6
|
+
puts "ok #{seikai.inspect}"
|
7
|
+
end
|
8
|
+
|
9
|
+
puts "=== reduce1 ==="
|
10
|
+
|
11
|
+
assert Units.new('').reduce1.to_s, ""
|
12
|
+
assert Units.new('m').reduce1.to_s, "m"
|
13
|
+
assert Units.new('3').reduce1.to_s, "3"
|
14
|
+
assert Units.new('3.14').reduce1.to_s, "3.14"
|
15
|
+
assert Units.new('m2').reduce1.to_s, "m2"
|
16
|
+
assert Units.new('m.s').reduce1.to_s, "m.s"
|
17
|
+
assert Units.new('m/s').reduce1.to_s, "m.s-1"
|
18
|
+
assert Units.new('kg.m/s2').reduce1.to_s, "kg.m.(s2)-1"
|
19
|
+
assert Units.new('s @ 2003-11-29').reduce1.to_s,
|
20
|
+
"(s @ 2003-11-29T00:00:00.00 +00:00)"
|
21
|
+
assert Units.new('s @ 2003-11-29T11:24').reduce1.to_s,
|
22
|
+
"(s @ 2003-11-29T11:24:00.00 +00:00)"
|
23
|
+
assert Units.new('s @ 2003-11-29T11:24:11 -09:00').reduce1.to_s,
|
24
|
+
"(s @ 2003-11-29T11:24:11.00 -09:00)"
|
25
|
+
|
26
|
+
assert Units.new('100').reduce1.to_s, "100"
|
27
|
+
assert Units.new('(10)^2').reduce1.to_s, "(10)2"
|
28
|
+
assert Units.new('(10)^2/100').reduce1.to_s, "(10)2.(100)-1"
|
29
|
+
|
30
|
+
puts "=== reduce2 ==="
|
31
|
+
|
32
|
+
assert Units.new('s @ 2003-11-29').reduce2.to_s,
|
33
|
+
"(s @ 2003-11-29T00:00:00.00 +00:00)"
|
34
|
+
assert Units.new('m/(s @ 2003-11-29)').reduce2.to_s, "m.s-1"
|
35
|
+
assert Units.new('m/((K @ 273.15) (s from 2003-11-29))').reduce2.to_s, "m.(K.s)-1"
|
36
|
+
|
37
|
+
assert Units.new('(10)^2/100').reduce2.to_s, "(10)2.(100)-1"
|
38
|
+
|
39
|
+
puts "=== reduce3 ==="
|
40
|
+
|
41
|
+
assert Units::MultiNode.new(Units::NameNode.new('a'), \
|
42
|
+
Units::NumberNode.new(1), \
|
43
|
+
Units::NameNode.new('b')).to_s, 'a.1 b'
|
44
|
+
|
45
|
+
assert Units.new('kg').reduce3.inspect, "Units[Name[kg]]"
|
46
|
+
assert Units.new('kg.m').reduce3.inspect, "Units[Multi[Name[kg], Name[m]]]"
|
47
|
+
assert Units.new('kg.m.s').reduce3.inspect,
|
48
|
+
"Units[Multi[Name[kg], Name[m], Name[s]]]"
|
49
|
+
|
50
|
+
assert Units.new('(m.s)^2').reduce3.inspect,
|
51
|
+
"Units[Multi[Pow[Name[m], Number[2]], Pow[Name[s], Number[2]]]]"
|
52
|
+
assert Units.new('K @ 273.15').reduce3.inspect,
|
53
|
+
"Units[Shift[Name[K], Number[273.15]]]"
|
54
|
+
assert Units.new('((a.b)^2)^2').reduce3.inspect,
|
55
|
+
"Units[Multi[Pow[Name[a], Number[4]], Pow[Name[b], Number[4]]]]"
|
56
|
+
assert Units.new('((a.b)^2 c4 d)^2').reduce3.inspect,
|
57
|
+
"Units[Multi[Pow[Name[a], Number[4]], Pow[Name[b], Number[4]], Pow[Name[c], Number[8]], Pow[Name[d], Number[2]]]]"
|
58
|
+
assert Units.new('((a.b)^2 c4 d)^2').reduce3.to_s,
|
59
|
+
"a4 b4 c8 d2"
|
60
|
+
assert Units.new('((a.b)^2 a4 b)^2').reduce3.to_s,
|
61
|
+
"a4 b4 a8 b2"
|
62
|
+
|
63
|
+
assert Units.new('s @ 2003-11-29').reduce3.to_s,
|
64
|
+
"(s @ 2003-11-29T00:00:00.00 +00:00)"
|
65
|
+
assert Units.new('m/(s @ 2003-11-29)').reduce3.to_s, "m.s-1"
|
66
|
+
assert Units.new('m/((K @ 273.15) (s from 2003-11-29))').reduce3.to_s, "m.K-1 s-1"
|
67
|
+
|
68
|
+
assert Units.new('(10)^2/100').reduce3.to_s, "(10)2.(100)-1"
|
69
|
+
|
70
|
+
puts "=== reduce4 ==="
|
71
|
+
|
72
|
+
assert Units.new('((a.b)^2 a4 b @ now)^2 @ 273.15').reduce4.to_s,
|
73
|
+
"(a12 b6 @ 273.15)"
|
74
|
+
|
75
|
+
assert Units.new('km2').reduce4.to_s, "km2"
|
76
|
+
assert Units.new('hours.hour').reduce4.to_s, "hour2"
|
77
|
+
assert Units.new('(10)^2').reduce4.to_s, "100"
|
78
|
+
assert Units.new('100/10').reduce4.to_s, "10.0"
|
79
|
+
assert Units.new('(10)^2/100').reduce4.to_s, "1.0"
|
80
|
+
|
81
|
+
puts "=== reduce5 ==="
|
82
|
+
|
83
|
+
assert Units.new('km2').reduce5.to_s, "1000000 m2"
|
84
|
+
assert Units.new('(10)^2/100').reduce5.to_s, "1.0"
|
85
|
+
|
86
|
+
assert Units.new('hPa').reduce5.to_s, "100 kg.m-1 s-2"
|
87
|
+
assert Units.new('mb').reduce5.to_s, "100.0 kg.m-1 s-2"
|
88
|
+
|
89
|
+
assert Units.new('hPa/mb').reduce5.to_s, "1.0"
|
90
|
+
|
91
|
+
assert Units.new('(K @ 273.15)@ 10').reduce5.to_s, "(K @ 283.15)"
|
92
|
+
|
93
|
+
puts "=== APPLICATIONS ==="
|
94
|
+
|
95
|
+
assert Units.new('km @ 2').convert(3, Units.new('m @ 100')), 4900
|
96
|
+
assert Units.new('degree_F').convert(32, Units.new('K')).to_s, "273.15"
|
97
|
+
|
98
|
+
u1 = Units.new('m/s')
|
99
|
+
u2 = Units.new('mm/s')
|
100
|
+
assert((u1/u2).to_s, "m.mm-1")
|
101
|
+
assert((u1*u2).to_s, "m.mm.s-2")
|
102
|
+
|
103
|
+
u1 = Units.new('years since 1999-01-01 00:00').reduce4
|
104
|
+
u2 = Units.new('hours since 2001-01-01 00:00').reduce4
|
105
|
+
assert u1.convert(3, u2), 24 * 365
|
106
|
+
u3 = Units.new('months since 2001-01-01 00:00').reduce4
|
107
|
+
assert u1.convert(3, u3), 12.0
|
108
|
+
|
109
|
+
Units.reduce_level = 3
|
110
|
+
assert((Units.new('hours') ** 2).to_s, "hours2")
|
111
|
+
Units.reduce_level = 4
|
112
|
+
assert((Units.new('hours') ** 2).to_s, "hour2")
|
113
|
+
Units.reduce_level = 5
|
114
|
+
assert((Units.new('hours') ** 2).to_s, "12960000 s2")
|
115
|
+
|
116
|
+
assert(Units.new('day') =~ Units.new('s since 2002-01-01'), true)
|
117
|
+
assert(Units.new('m') =~ Units.new('1'), false)
|
118
|
+
|
119
|
+
un1 = Units['day since 2000-01-01']
|
120
|
+
un2 = Units['s since 2000-01-01']
|
121
|
+
assert(un1.convert(0, un2), 0.0)
|
122
|
+
assert(un1.convert(1, un2), 86400.0)
|
data/src/timenode.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
class XDate
|
2
|
+
|
3
|
+
def initialize(year, month, day)
|
4
|
+
@year, @month, @day = year.to_i, month.to_i, day.to_i
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :year, :month, :day
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
format('%04d-%02d-%02d', @year, @month, @day)
|
11
|
+
end
|
12
|
+
|
13
|
+
alias :inspect :to_s
|
14
|
+
|
15
|
+
def to_time
|
16
|
+
Time.gm(@year, @month, @day)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_date
|
20
|
+
Date.new(@year, @month, @day)
|
21
|
+
end
|
22
|
+
|
23
|
+
def -(other)
|
24
|
+
case other
|
25
|
+
when XDate
|
26
|
+
(to_date - other.to_date)
|
27
|
+
when Time
|
28
|
+
to_time - other
|
29
|
+
when Date
|
30
|
+
(to_date - other.to_date)
|
31
|
+
else
|
32
|
+
to_date - other
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def +(other)
|
37
|
+
t = to_date + other
|
38
|
+
self.class.new(t.year, t.month, t.mday)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class TimeNode < TerminalNode
|
44
|
+
|
45
|
+
def initialize(date, time, zone)
|
46
|
+
@date, @time, @zone = date, time, zone
|
47
|
+
if :now === @date then
|
48
|
+
now = Time.now.utc
|
49
|
+
@date = XDate.new(now.year, now.month, now.day)
|
50
|
+
@time = ((now.hour * 60 + now.min) * 60 + Float(now.sec))
|
51
|
+
else
|
52
|
+
qdays = (@time / 86400).floor
|
53
|
+
if not qdays.zero?
|
54
|
+
@date += qdays
|
55
|
+
@time -= (qdays * 86400)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
raise TypeError unless XDate === @date
|
59
|
+
@time = 0.0 unless @time
|
60
|
+
raise TypeError unless Float === @time
|
61
|
+
@zone = 0 unless @zone
|
62
|
+
raise TypeError unless Integer === @zone
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :date, :time, :zone
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
hr = @time.floor / 3600
|
69
|
+
mi = (@time.floor / 60) % 60
|
70
|
+
sc = @time % 60
|
71
|
+
tzm = @zone.abs
|
72
|
+
tzh = tzm / 60
|
73
|
+
tzm %= 60
|
74
|
+
tzh = -tzh if @zone < 0
|
75
|
+
format("%sT%02d:%02d:%05.2f %+03d:%02d", \
|
76
|
+
@date.to_s, hr, mi, sc, tzh, tzm)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self::pentad(d)
|
80
|
+
(d > 25) ? 5 : ((d - 1) / 5)
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_time(increment)
|
84
|
+
inc = increment.reduce5
|
85
|
+
case inc.name
|
86
|
+
when 's'
|
87
|
+
t2 = @time + inc.factor
|
88
|
+
d2 = @date + (t2 / 86400)
|
89
|
+
t2 = t2 % 86400
|
90
|
+
self.class.new(d2, t2, @zone)
|
91
|
+
when 'pentad'
|
92
|
+
ifac = Integer(inc.factor)
|
93
|
+
ipen = ifac % 6
|
94
|
+
imon = ifac / 6
|
95
|
+
spen = self.class.pentad(@date.day)
|
96
|
+
smon = @date.month + imon + spen / 6
|
97
|
+
spen = spen % 6
|
98
|
+
sday = spen * 5 + (@date.day - 1) % 5 + 1
|
99
|
+
syear = @date.year + (smon - 1) / 12
|
100
|
+
smon = (smon - 1) % 12 + 1
|
101
|
+
sdate = XDate.new(syear, smon, sday)
|
102
|
+
self.class.new(sdate, @time, @zone)
|
103
|
+
else
|
104
|
+
raise "bad time unit '#{inc.name}'"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def utcsod
|
109
|
+
@time - @zone * 60
|
110
|
+
end
|
111
|
+
|
112
|
+
def div_time(units)
|
113
|
+
base = units.ref
|
114
|
+
inc = units.deref.reduce5
|
115
|
+
begin
|
116
|
+
incname = inc.name
|
117
|
+
rescue Exception
|
118
|
+
incname = "(undefined)"
|
119
|
+
end
|
120
|
+
case incname
|
121
|
+
when 's'
|
122
|
+
dif = (@date - base.date) * 86400 + (utcsod - base.utcsod)
|
123
|
+
dif / inc.factor
|
124
|
+
when 'pentad'
|
125
|
+
dif = (@date.year - base.date.year) * 72
|
126
|
+
dif += (@date.month - base.date.month) * 6
|
127
|
+
dif += self.class.pentad(@date.day)
|
128
|
+
dif -= self.class.pentad(base.date.day)
|
129
|
+
dif = Float(dif) if dif % inc.factor != 0
|
130
|
+
dif / inc.factor
|
131
|
+
else
|
132
|
+
raise "bad time unit '#{incname}'"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|