iso8601 0.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -2
- data/.rspec +2 -0
- data/Gemfile +6 -2
- data/LICENSE +22 -503
- data/README.md +26 -5
- data/Rakefile +2 -1
- data/iso8601.gemspec +24 -20
- data/lib/iso8601.rb +8 -6
- data/lib/iso8601/atoms.rb +65 -32
- data/lib/iso8601/dateTime.rb +45 -22
- data/lib/iso8601/duration.rb +113 -57
- data/lib/iso8601/errors.rb +3 -2
- data/spec/iso8601/atoms_spec.rb +176 -0
- data/spec/iso8601/dateTime_spec.rb +120 -0
- data/spec/iso8601/duration_spec.rb +163 -0
- data/spec/spec_helper.rb +4 -0
- metadata +62 -54
- data/test/iso8601/test_atoms.rb +0 -100
- data/test/iso8601/test_dateTime.rb +0 -72
- data/test/iso8601/test_duration.rb +0 -95
- data/test/test_iso8601.rb +0 -4
data/README.md
CHANGED
@@ -6,10 +6,27 @@ times) standard.
|
|
6
6
|
|
7
7
|
## Comments
|
8
8
|
|
9
|
-
|
9
|
+
### Duration sign
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
Because Durations and DateTime has a substraction method, Durations has sign to be able to represent a negative value:
|
12
|
+
|
13
|
+
(ISO8601::Duration.new('PT10S') - ISO8601::Duration.new('PT12S')).to_s #=> '-PT2S'
|
14
|
+
(ISO8601::Duration.new('-PT10S') + ISO8601::Duration.new('PT12S')).to_s #=> 'PT2S'
|
15
|
+
|
16
|
+
### Separators
|
17
|
+
|
18
|
+
Although, the spec allows three separator types: period (.), comma (,), and raised period (·) by now I keep just the period option.
|
19
|
+
|
20
|
+
### Century treatment
|
21
|
+
|
22
|
+
The specification says that you can express a reduced precision year
|
23
|
+
just giving the century (i.e. '20' to refer the inclusive range 2000-2999).
|
24
|
+
|
25
|
+
This implementation expands the century to the first value for its range
|
26
|
+
so:
|
27
|
+
|
28
|
+
ISO8601::DateTime.new('20').century # => 20
|
29
|
+
ISO8601::DateTime.new('20').year # => 2000
|
13
30
|
|
14
31
|
|
15
32
|
## TODO
|
@@ -18,12 +35,16 @@ Because Durations and DateTime has substract method, Durations has sign to repre
|
|
18
35
|
* Recurring time intervals
|
19
36
|
* Ordinal date pattern (YYYY-DDD)
|
20
37
|
* Week date pattern (YYYY-Www-D)
|
38
|
+
* Treat the `201005` as `2000-10-05` instead of `2010-05`
|
21
39
|
|
22
40
|
## Contributors
|
23
41
|
|
24
42
|
* [Nick Lynch](https://github.com/njlynch)
|
25
43
|
* [Pelle Braendgaard](https://github.com/pelle)
|
26
44
|
* [Takahiro Noda](https://github.com/tnoda)
|
45
|
+
* [Porras](https://github.com/porras)
|
46
|
+
|
47
|
+
## License
|
48
|
+
|
49
|
+
Arnau Siches under the [MIT License](https://github.com/arnau/ISO8601/blob/master/LICENSE)
|
27
50
|
|
28
|
-
## Credits
|
29
|
-
Arnau Siches under [LGPL](http://www.gnu.org/licenses/lgpl.html) license. LICENSE file for details.
|
data/Rakefile
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
data/iso8601.gemspec
CHANGED
@@ -1,26 +1,30 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.push File.expand_path('../lib', __FILE__)
|
4
|
+
require 'iso8601'
|
4
5
|
|
5
6
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.
|
9
|
-
s.
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
|
14
|
-
|
7
|
+
s.name = 'iso8601'
|
8
|
+
s.version = ISO8601::VERSION
|
9
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
10
|
+
s.authors = ['Arnau Siches']
|
11
|
+
s.email = 'arnau.siches@gmail.com'
|
12
|
+
s.homepage = 'https://github.com/arnau/ISO8601'
|
13
|
+
s.summary = "Ruby parser to work with ISO 8601 dateTimes and durations - http://en.wikipedia.org/wiki/ISO_8601"
|
14
|
+
s.description = <<-EOD
|
15
|
+
ISO8601 is a simple implementation in Ruby of the ISO 8601 (Data elements and
|
16
|
+
interchange formats - Information interchange - Representation of dates
|
17
|
+
and times) standard.
|
18
|
+
EOD
|
19
|
+
s.license = 'MIT'
|
20
|
+
s.rubyforge_project = 'iso8601'
|
15
21
|
|
16
|
-
s.
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = s.files.grep(%r{^(spec|features)/})
|
24
|
+
s.require_paths = ['lib']
|
17
25
|
|
18
|
-
s.
|
19
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
-
s.require_paths = ["lib"]
|
26
|
+
s.has_rdoc = 'yard'
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
# s.add_runtime_dependency "rest-client"
|
28
|
+
s.add_development_dependency 'rspec', '~> 2.0'
|
29
|
+
s.add_development_dependency 'ZenTest', '~> 4.8'
|
26
30
|
end
|
data/lib/iso8601.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module ISO8601
|
2
|
-
VERSION =
|
4
|
+
VERSION = '0.4.0'
|
3
5
|
end
|
4
6
|
|
5
|
-
require
|
7
|
+
require 'time'
|
6
8
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
9
|
+
require 'iso8601/errors'
|
10
|
+
require 'iso8601/atoms'
|
11
|
+
require 'iso8601/dateTime'
|
12
|
+
require 'iso8601/duration'
|
data/lib/iso8601/atoms.rb
CHANGED
@@ -1,35 +1,51 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
-
|
3
|
+
module ISO8601
|
4
|
+
##
|
5
|
+
# A generic atom in a {ISO8601::Duration}
|
6
|
+
#
|
7
|
+
# @abstract
|
4
8
|
class Atom
|
9
|
+
##
|
10
|
+
# @param [Numeric] atom The atom value
|
11
|
+
# @param [ISO8601::DateTime, nil] base (nil) The base datetime to
|
12
|
+
# compute the atom factor.
|
5
13
|
def initialize(atom, base=nil)
|
6
|
-
|
14
|
+
raise TypeError, "The atom argument for #{self.inspect} should be a Numeric value." unless atom.kind_of? Numeric
|
15
|
+
raise TypeError, "The base argument for #{self.inspect} should be a ISO8601::DateTime instance or nil." unless base.kind_of? ISO8601::DateTime or base.nil?
|
7
16
|
@atom = atom
|
8
17
|
@base = base
|
9
18
|
end
|
10
|
-
|
19
|
+
##
|
20
|
+
# The integer representation of the atom
|
11
21
|
def to_i
|
12
|
-
@atom
|
22
|
+
@atom.to_i
|
13
23
|
end
|
24
|
+
##
|
25
|
+
# The amount of seconds of the atom
|
14
26
|
def to_seconds
|
15
27
|
@atom * self.factor
|
16
28
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
29
|
+
##
|
30
|
+
# The atom factor to compute the amount of seconds for the atom
|
31
|
+
def factor
|
32
|
+
raise NotImplementedError, "The #factor method should be implemented for each subclass"
|
33
|
+
end
|
22
34
|
end
|
23
|
-
|
35
|
+
##
|
36
|
+
# A Years atom in a {ISO8601::Duration}
|
37
|
+
#
|
24
38
|
# A “calendar year” is the cyclic time interval in a calendar which is
|
25
39
|
# required for one revolution of the Earth around the Sun and approximated to
|
26
40
|
# an integral number of “calendar days”.
|
27
|
-
|
28
|
-
#A “duration year” is the duration of 365 or 366 “calendar days” depending on
|
41
|
+
#
|
42
|
+
# A “duration year” is the duration of 365 or 366 “calendar days” depending on
|
29
43
|
# the start and/or the end of the corresponding time interval within the
|
30
44
|
# specific “calendar year”.
|
31
45
|
class Years < ISO8601::Atom
|
32
|
-
|
46
|
+
##
|
47
|
+
# The Year factor
|
48
|
+
#
|
33
49
|
# The “duration year” average is calculated through time intervals of 400
|
34
50
|
# “duration years”. Each cycle of 400 “duration years” has 303 “common
|
35
51
|
# years” of 365 “calendar days” and 97 “leap years” of 366 “calendar days”.
|
@@ -37,22 +53,27 @@ module ISO8601
|
|
37
53
|
if @base.nil?
|
38
54
|
((365 * 303 + 366 * 97) / 400) * 86400
|
39
55
|
elsif @atom == 0
|
40
|
-
|
56
|
+
year = (@base.year).to_i
|
57
|
+
(Time.utc(year) - Time.utc(@base.year))
|
41
58
|
else
|
42
59
|
year = (@base.year + @atom).to_i
|
43
60
|
(Time.utc(year) - Time.utc(@base.year)) / @atom
|
44
61
|
end
|
45
62
|
end
|
46
63
|
end
|
47
|
-
|
64
|
+
##
|
65
|
+
# A Months atom in a {ISO8601::Duration}
|
66
|
+
#
|
48
67
|
# A “calendar month” is the time interval resulting from the division of a
|
49
68
|
# “calendar year” in 12 time intervals.
|
50
|
-
|
69
|
+
#
|
51
70
|
# A “duration month” is the duration of 28, 29, 30 or 31 “calendar days”
|
52
71
|
# depending on the start and/or the end of the corresponding time interval
|
53
72
|
# within the specific “calendar month”.
|
54
73
|
class Months < ISO8601::Atom
|
55
|
-
|
74
|
+
##
|
75
|
+
# The Month factor
|
76
|
+
#
|
56
77
|
# The “duration month” average is calculated through time intervals of 400
|
57
78
|
# “duration years”. Each cycle of 400 “duration years” has 303 “common
|
58
79
|
# years” of 365 “calendar days” and 97 “leap years” of 366 “calendar days”.
|
@@ -60,7 +81,9 @@ module ISO8601
|
|
60
81
|
if @base.nil?
|
61
82
|
(((365 * 303 + 366 * 97) / 400) * 86400) / 12
|
62
83
|
elsif @atom == 0
|
63
|
-
|
84
|
+
month = (@base.month <= 12) ? (@base.month) : ((@base.month) % 12)
|
85
|
+
year = @base.year + ((@base.month) / 12).to_i
|
86
|
+
(Time.utc(year, month) - Time.utc(@base.year, @base.month))
|
64
87
|
else
|
65
88
|
month = (@base.month + @atom <= 12) ? (@base.month + @atom) : ((@base.month + @atom) % 12)
|
66
89
|
year = @base.year + ((@base.month + @atom) / 12).to_i
|
@@ -68,47 +91,57 @@ module ISO8601
|
|
68
91
|
end
|
69
92
|
end
|
70
93
|
end
|
71
|
-
|
94
|
+
##
|
95
|
+
# A Weeks atom in a {ISO8601::Duration}
|
72
96
|
class Weeks < ISO8601::Atom
|
73
|
-
|
74
|
-
#
|
97
|
+
##
|
98
|
+
# The Week factor
|
75
99
|
def factor
|
76
100
|
604800
|
77
101
|
end
|
78
102
|
end
|
79
|
-
|
103
|
+
##
|
104
|
+
# The Days atom in a {ISO8601::Duration}
|
105
|
+
#
|
80
106
|
# A “calendar day” is the time interval which starts at a certain time of day
|
81
107
|
# at a certain “calendar day” and ends at the same time of day at the next
|
82
108
|
# “calendar day”.
|
83
109
|
class Days < ISO8601::Atom
|
84
|
-
|
85
|
-
#
|
110
|
+
##
|
111
|
+
# The Day factor
|
86
112
|
def factor
|
87
113
|
86400
|
88
114
|
end
|
89
115
|
end
|
90
|
-
|
116
|
+
##
|
117
|
+
# The Hours atom in a {ISO8601::Duration}
|
91
118
|
class Hours < ISO8601::Atom
|
92
|
-
|
93
|
-
#
|
119
|
+
##
|
120
|
+
# The Hour factor
|
94
121
|
def factor
|
95
122
|
3600
|
96
123
|
end
|
97
124
|
end
|
125
|
+
##
|
126
|
+
# The Minutes atom in a {ISO8601::Duration}
|
98
127
|
class Minutes < ISO8601::Atom
|
99
|
-
|
100
|
-
#
|
128
|
+
##
|
129
|
+
# The Minute factor
|
101
130
|
def factor
|
102
131
|
60
|
103
132
|
end
|
104
133
|
end
|
105
|
-
|
134
|
+
##
|
135
|
+
# The Seconds atom in a {ISO8601::Duration}
|
136
|
+
#
|
106
137
|
# The second is the base unit of measurement of time in the International
|
107
138
|
# System of Units (SI) as defined by the International Committee of Weights
|
108
139
|
# and Measures (CIPM, i.e. Comité International des Poids et Mesures)
|
109
140
|
class Seconds < ISO8601::Atom
|
141
|
+
##
|
142
|
+
# The Second factor
|
110
143
|
def factor
|
111
144
|
1
|
112
145
|
end
|
113
146
|
end
|
114
|
-
end
|
147
|
+
end
|
data/lib/iso8601/dateTime.rb
CHANGED
@@ -1,32 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module ISO8601
|
4
|
+
##
|
5
|
+
# A DateTime representation
|
6
|
+
#
|
7
|
+
# @todo Review the pattern `201005`. It has to be `20-10-05` instead of `2010-05`.
|
8
|
+
# The specification doesn't allow a YYYYMM. It should be always
|
9
|
+
# YYYY-MM.
|
2
10
|
class DateTime
|
3
|
-
attr_reader :
|
11
|
+
attr_reader :century, :year, :month, :day, :hour, :minute, :second, :timezone
|
12
|
+
##
|
13
|
+
# @param [String] date_time The datetime pattern
|
4
14
|
def initialize(date_time)
|
5
15
|
@dt = /^(?:
|
6
|
-
(\d{2})(\d{2})?
|
16
|
+
(\d{2})(\d{2})? # Year. It can be either two digits (the century) or four digits (the full year)
|
7
17
|
(?:
|
8
18
|
(-)?(\d{2})
|
9
|
-
)?
|
19
|
+
)? # Month with an optional separator
|
10
20
|
(?:
|
11
|
-
(\3)?(\d{2})
|
21
|
+
(\3)?(\d{2}) # Day with an optional separator which is the same for the Month
|
12
22
|
)?
|
13
|
-
)?
|
23
|
+
)? # Date
|
14
24
|
(?:
|
15
|
-
T(\d{2})
|
25
|
+
T(\d{2}) # Hour
|
16
26
|
(?:
|
17
|
-
(:)?(\d{2})
|
27
|
+
(:)?(\d{2}) # Minute with an optional separator
|
18
28
|
)?
|
19
29
|
(?:
|
20
|
-
(\8)?(\d{2})
|
21
|
-
)?
|
30
|
+
(\8)?(\d{2}) # Second with an optional separator which is the same that for the Minute
|
31
|
+
)? # Time
|
22
32
|
(
|
23
33
|
Z|([+-])
|
24
|
-
(\d{2})
|
34
|
+
(\d{2}) # Timezone hour
|
25
35
|
(?:
|
26
|
-
(\8)?
|
27
|
-
(\d{2})
|
36
|
+
(\8)? # Separator which should be the same that for the Minute
|
37
|
+
(\d{2}) # Timezone minute
|
28
38
|
)?
|
29
|
-
)?
|
39
|
+
)? # Timezone
|
30
40
|
)?
|
31
41
|
$/x.match(date_time) or raise ISO8601::Errors::UnknownPattern.new(date_time)
|
32
42
|
|
@@ -52,12 +62,21 @@ module ISO8601
|
|
52
62
|
:full => @dt[12].nil? ? (Time.now.gmt_offset / 3600) : (@dt[12] == "Z" ? 0 : @dt[12]),
|
53
63
|
:sign => @dt[13],
|
54
64
|
:hour => @dt[12].nil? ? (Time.now.gmt_offset / 3600) : (@dt[12] == "Z" ? 0 : @dt[14].to_i),
|
55
|
-
:minute => (@dt[12].nil? or @dt[12] == "Z") ? 0 : @dt[
|
65
|
+
:minute => (@dt[12].nil? or @dt[12] == "Z") ? 0 : @dt[13].to_i
|
56
66
|
}
|
57
67
|
|
58
68
|
valid_pattern?
|
59
69
|
valid_range?
|
60
70
|
end
|
71
|
+
##
|
72
|
+
# Returns the datetime string representation
|
73
|
+
def to_s
|
74
|
+
@date_time
|
75
|
+
end
|
76
|
+
##
|
77
|
+
# Converts the object to a Time instance
|
78
|
+
#
|
79
|
+
# @return [Time] The object converted
|
61
80
|
def to_time
|
62
81
|
raise RangeError if @year.nil?
|
63
82
|
if @month.nil?
|
@@ -69,17 +88,21 @@ module ISO8601
|
|
69
88
|
Time.parse(@date_time).getutc
|
70
89
|
end
|
71
90
|
end
|
91
|
+
##
|
92
|
+
# Addition
|
93
|
+
#
|
94
|
+
# @param [ISO8601::DateTime] The seconds to add
|
72
95
|
def +(d)
|
73
|
-
raise TypeError unless
|
74
|
-
Time.utc(@year, @month, @day, @hour, @minute, @second) + d
|
96
|
+
raise TypeError unless d.kind_of? Numeric
|
97
|
+
ISO8601::DateTime.new((Time.utc(@year, @month, @day, @hour, @minute, @second) + d).iso8601)
|
75
98
|
end
|
99
|
+
##
|
100
|
+
# Substraction
|
101
|
+
#
|
102
|
+
# @param [ISO8601::DateTime] The seconds to substract
|
76
103
|
def -(d)
|
77
|
-
raise TypeError unless
|
78
|
-
|
79
|
-
Time.utc(@year, @month, @day, @hour, @minute, @second) - Time.utc(d.year, d.month, d.day, d.hour, d.minute, d.second)
|
80
|
-
else
|
81
|
-
Time.utc(@year, @month, @day, @hour, @minute, @second) - d
|
82
|
-
end
|
104
|
+
raise TypeError unless d.kind_of? Numeric
|
105
|
+
ISO8601::DateTime.new((Time.utc(@year, @month, @day, @hour, @minute, @second) - d).iso8601)
|
83
106
|
end
|
84
107
|
private
|
85
108
|
def valid_pattern?
|
data/lib/iso8601/duration.rb
CHANGED
@@ -1,11 +1,37 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
+
module ISO8601
|
4
|
+
##
|
3
5
|
# Represents a duration in ISO 8601 format
|
6
|
+
#
|
7
|
+
# @todo Support fraction values for years, months, days, weeks, hours
|
8
|
+
# and minutes
|
4
9
|
class Duration
|
5
10
|
attr_reader :base, :atoms
|
6
|
-
|
7
|
-
|
8
|
-
|
11
|
+
##
|
12
|
+
# @param [String, Numeric] pattern The duration pattern
|
13
|
+
# @param [ISO8601::DateTime, nil] base (nil) The base datetime to
|
14
|
+
# calculate the duration properly
|
15
|
+
def initialize(pattern, base = nil)
|
16
|
+
# we got seconds instead of an ISO8601 duration
|
17
|
+
pattern = "PT#{pattern}S" if (pattern.kind_of? Numeric)
|
18
|
+
@duration = /^(\+|-)? # Sign
|
19
|
+
P(
|
20
|
+
(
|
21
|
+
(\d+Y)? # Years
|
22
|
+
(\d+M)? # Months
|
23
|
+
(\d+D)? # Days
|
24
|
+
(T
|
25
|
+
(\d+H)? # Hours
|
26
|
+
(\d+M)? # Minutes
|
27
|
+
(\d+(?:\.\d+)?S)? # Seconds
|
28
|
+
)? # Time
|
29
|
+
)
|
30
|
+
|(\d+W) # Weeks
|
31
|
+
) # Duration
|
32
|
+
$/x.match(pattern) or raise ISO8601::Errors::UnknownPattern.new(pattern)
|
33
|
+
|
34
|
+
@base = base
|
9
35
|
valid_pattern?
|
10
36
|
valid_base?
|
11
37
|
@atoms = {
|
@@ -18,86 +44,117 @@ module ISO8601
|
|
18
44
|
:seconds => @duration[10].nil? ? 0 : @duration[10].chop.to_f * sign
|
19
45
|
}
|
20
46
|
end
|
21
|
-
|
47
|
+
##
|
48
|
+
# Assigns a new base datetime
|
49
|
+
#
|
50
|
+
# @return [ISO8601::DateTime, nil]
|
22
51
|
def base=(value)
|
23
52
|
@base = value
|
53
|
+
valid_base?
|
24
54
|
return @base
|
25
55
|
end
|
26
|
-
|
27
|
-
#
|
56
|
+
##
|
57
|
+
# @return [String] The string representation of the duration
|
28
58
|
def to_s
|
29
59
|
@duration[0]
|
30
60
|
end
|
31
|
-
|
32
|
-
#
|
61
|
+
##
|
62
|
+
# @return [ISO8601::Years] The years of the duration
|
33
63
|
def years
|
34
64
|
ISO8601::Years.new(@atoms[:years], @base)
|
35
65
|
end
|
36
|
-
|
37
|
-
#
|
66
|
+
##
|
67
|
+
# @return [ISO8601::Months] The months of the duration
|
38
68
|
def months
|
39
|
-
|
69
|
+
# Changes the base to compute the months for the right base year
|
70
|
+
base = @base.nil? ? nil : @base + self.years.to_seconds
|
40
71
|
ISO8601::Months.new(@atoms[:months], base)
|
41
72
|
end
|
42
|
-
|
43
|
-
#
|
73
|
+
##
|
74
|
+
# @return [ISO8601::Weeks] The weeks of the duration
|
44
75
|
def weeks
|
45
76
|
ISO8601::Weeks.new(@atoms[:weeks], @base)
|
46
77
|
end
|
47
|
-
|
48
|
-
#
|
78
|
+
##
|
79
|
+
# @return [ISO8601::Days] The days of the duration
|
49
80
|
def days
|
50
81
|
ISO8601::Days.new(@atoms[:days], @base)
|
51
82
|
end
|
52
|
-
|
53
|
-
#
|
83
|
+
##
|
84
|
+
# @return [ISO8601::Hours] The hours of the duration
|
54
85
|
def hours
|
55
86
|
ISO8601::Hours.new(@atoms[:hours], @base)
|
56
87
|
end
|
57
|
-
|
58
|
-
#
|
88
|
+
##
|
89
|
+
# @return [ISO8601::Minutes] The minutes of the duration
|
59
90
|
def minutes
|
60
91
|
ISO8601::Minutes.new(@atoms[:minutes], @base)
|
61
92
|
end
|
62
|
-
|
63
|
-
#
|
93
|
+
##
|
94
|
+
# @return [ISO8601::Seconds] The seconds of the duration
|
64
95
|
def seconds
|
65
96
|
ISO8601::Seconds.new(@atoms[:seconds], @base)
|
66
97
|
end
|
67
|
-
|
68
|
-
#
|
98
|
+
##
|
99
|
+
# @return [Numeric] The duration in seconds
|
69
100
|
def to_seconds
|
70
101
|
years, months, weeks, days, hours, minutes, seconds = self.years.to_seconds, self.months.to_seconds, self.weeks.to_seconds, self.days.to_seconds, self.hours.to_seconds, self.minutes.to_seconds, self.seconds.to_seconds
|
71
102
|
return years + months + weeks + days + hours + minutes + seconds
|
72
103
|
end
|
73
|
-
|
74
|
-
#
|
104
|
+
##
|
105
|
+
# @return [ISO8601::Duration] The absolute representation of the duration
|
75
106
|
def abs
|
76
|
-
|
77
|
-
|
78
|
-
|
107
|
+
absolute = self.to_s.sub(/^[-+]/, '')
|
108
|
+
return ISO8601::Duration.new(absolute)
|
109
|
+
end
|
110
|
+
##
|
111
|
+
# Addition
|
112
|
+
#
|
113
|
+
# @param [ISO8601::Duration] duration The duration to add
|
114
|
+
#
|
115
|
+
# @raise [ISO8601::Errors::DurationBaseError] If bases doesn't match
|
116
|
+
# @return [ISO8601::Duration]
|
79
117
|
def +(duration)
|
80
|
-
raise ISO8601::Errors::DurationBaseError.new(duration) if
|
81
|
-
d1 =
|
118
|
+
raise ISO8601::Errors::DurationBaseError.new(duration) if @base.to_s != duration.base.to_s
|
119
|
+
d1 = to_seconds
|
82
120
|
d2 = duration.to_seconds
|
83
|
-
return
|
84
|
-
end
|
121
|
+
return seconds_to_iso(d1 + d2)
|
122
|
+
end
|
123
|
+
##
|
124
|
+
# Substraction
|
125
|
+
#
|
126
|
+
# @param [ISO8601::Duration] duration The duration to substract
|
127
|
+
#
|
128
|
+
# @raise [ISO8601::Errors::DurationBaseError] If bases doesn't match
|
129
|
+
# @return [ISO8601::Duration]
|
85
130
|
def -(duration)
|
86
|
-
raise ISO8601::Errors::DurationBaseError.new(duration) if
|
87
|
-
d1 =
|
131
|
+
raise ISO8601::Errors::DurationBaseError.new(duration) if @base.to_s != duration.base.to_s
|
132
|
+
d1 = to_seconds
|
88
133
|
d2 = duration.to_seconds
|
89
|
-
|
90
|
-
|
134
|
+
duration = d1 - d2
|
135
|
+
if duration == 0
|
136
|
+
return ISO8601::Duration.new('PT0S')
|
137
|
+
else
|
138
|
+
return seconds_to_iso(duration)
|
139
|
+
end
|
91
140
|
end
|
92
|
-
|
93
|
-
#
|
94
|
-
#
|
95
|
-
|
96
|
-
|
141
|
+
##
|
142
|
+
# @param [ISO8601::Duration] duration The duration to compare
|
143
|
+
#
|
144
|
+
# @raise [ISO8601::Errors::DurationBaseError] If bases doesn't match
|
145
|
+
# @return [Boolean]
|
146
|
+
def ==(duration)
|
147
|
+
raise ISO8601::Errors::DurationBaseError.new(duration) if @base.to_s != duration.base.to_s
|
148
|
+
(self.to_seconds == duration.to_seconds)
|
97
149
|
end
|
98
150
|
|
151
|
+
private
|
152
|
+
##
|
153
|
+
# @param [Numeric] duration The seconds to promote
|
154
|
+
#
|
155
|
+
# @return [ISO8601::Duration]
|
99
156
|
def seconds_to_iso(duration)
|
100
|
-
sign =
|
157
|
+
sign = '-' if (duration < 0)
|
101
158
|
duration = duration.abs
|
102
159
|
years, y_mod = (duration / self.years.factor).to_i, (duration % self.years.factor)
|
103
160
|
months, m_mod = (y_mod / self.months.factor).to_i, (y_mod % self.months.factor)
|
@@ -119,22 +176,21 @@ module ISO8601
|
|
119
176
|
return ISO8601::Duration.new(date_time)
|
120
177
|
end
|
121
178
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
raise TypeError
|
129
|
-
end
|
179
|
+
def sign
|
180
|
+
(@duration[1].nil? or @duration[1] == "+") ? 1 : -1
|
181
|
+
end
|
182
|
+
def valid_base?
|
183
|
+
if !(@base.nil? or @base.kind_of? ISO8601::DateTime)
|
184
|
+
raise TypeError
|
130
185
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
186
|
+
end
|
187
|
+
def valid_pattern?
|
188
|
+
if @duration.nil? or
|
189
|
+
(@duration[4].nil? and @duration[5].nil? and @duration[6].nil? and @duration[7].nil? and @duration[11].nil?) or
|
190
|
+
(!@duration[7].nil? and @duration[8].nil? and @duration[9].nil? and @duration[10].nil? and @duration[11].nil?)
|
135
191
|
|
136
|
-
|
137
|
-
end
|
192
|
+
raise ISO8601::Errors::UnknownPattern.new(@duration)
|
138
193
|
end
|
194
|
+
end
|
139
195
|
end
|
140
196
|
end
|