iso8601 0.2 → 0.4.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/.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
|