iso8601 0.12.2 → 0.12.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63fc30058203b81b163c0e43e6752493988e104a76b2fcd6c52eba5905cd5ec3
4
- data.tar.gz: 990d117c3c06599abf7306da203fa23efadc1215d40eebf0f9a54da8dd30cf97
3
+ metadata.gz: b974875d177ceceff7f8d892867990e27f46718e57d7a8bb0119b8ccbddd77eb
4
+ data.tar.gz: 0b4e786f4abde832af5f5ceefb53c2478cffa0c3e8d9e997762ca54787fbf70a
5
5
  SHA512:
6
- metadata.gz: b84622859b9da1598fe29879aff66aeed4aaa560af9ecade7d48fbf4ae6e40a0668dadd528690f0c1039317f726925f3656414a6a4ac38658509edfbf8c793b3
7
- data.tar.gz: 9719addba3e3536ecec660b791f65203332610eed991db6ca97cabf25ae186569ee82bb5ca63fc52ee76de15cd2e76c27bc403af0a1844978c377194b06c3907
6
+ metadata.gz: e295765af84738b2bc1dc80ad2509a7e8bc065e61e32151ad979eb332cb5afe9b0042dd7072674be8259d985684616e8a0c9890c88cc29eefee9391ffd248924
7
+ data.tar.gz: 5ef627990b4f2c1ec2bcb98ec4caddc23928612a6b2895080cdcc84fd8a9295e7ce8564c04303d37b3c3ab934922cf9b1cdf8ced23571777f8c57ab2067a6ac5
@@ -0,0 +1,86 @@
1
+ # Date Time, Date, Time
2
+
3
+
4
+ ## Interface with core classes
5
+
6
+ ISO8601 classes provide a method `to_*` to convert to its core equivalent:
7
+
8
+ ```ruby
9
+ ISO8601::DateTime#to_datetime # => #<DateTime: ...>
10
+ ISO8601::Date#to_date # => #<Date: ...>
11
+ ISO8601::Time#to_time # => #<Time: ...>
12
+ ```
13
+
14
+ ## Differences with core Date, Time and DateTime
15
+
16
+ ### Reduced precision
17
+
18
+ Core `Date.parse` and `DateTime.parse` don't allow reduced precision. For
19
+ example:
20
+
21
+ ```ruby
22
+ DateTime.parse('2014-05') # => ArgumentError: invalid date
23
+ ```
24
+
25
+ But the standard covers this situation assuming any missing token as its lower
26
+ value:
27
+
28
+ ```ruby
29
+ ISO8601::DateTime.new('2014-05').to_s # => "2014-05-01T00:00:00+00:00"
30
+ ISO8601::DateTime.new('2014').to_s # => "2014-01-01T00:00:00+00:00"
31
+ ```
32
+
33
+ The same assumption happens in core classes with `.new`:
34
+
35
+ ```ruby
36
+ DateTime.new(2014,5) # => #<DateTime: 2014-05-01T00:00:00+00:00 ((2456779j,0s,0n),+0s,2299161j)>
37
+ DateTime.new(2014) # => #<DateTime: 2014-01-01T00:00:00+00:00 ((2456659j,0s,0n),+0s,2299161j)>
38
+ ```
39
+
40
+ ### Unmatched precision
41
+
42
+ Unmatched precison is handled strongly. Notice the time fragment is lost in
43
+ `DateTime.parse` with no warning only if the loose precision is in the time
44
+ component.
45
+
46
+ ```ruby
47
+ ISO8601::DateTime.new('2014-05-06T101112') # => ISO8601::Errors::UnknownPattern
48
+ DateTime.parse('2014-05-06T101112') # => #<DateTime: 2014-05-06T00:00:00+00:00 ((2456784j,0s,0n),+0s,2299161j)>
49
+
50
+ ISO8601::DateTime.new('20140506T10:11:12') # => ISO8601::Errors::UnknownPattern
51
+ DateTime.parse('20140506T10:11:12') # => #<DateTime: 2014-05-06T10:11:12+00:00 ((2456784j,0s,0n),+0s,2299161j)>
52
+ ```
53
+
54
+ ### Strong pattern matching
55
+
56
+ Week dates raise an error when two digit days provied instead of return monday:
57
+
58
+ ```ruby
59
+ ISO8601::DateTime.new('2014-W15-02') # => ISO8601::Errors::UnknownPattern
60
+ DateTime.new('2014-W15-02') # => #<Date: 2014-04-07 ((2456755j,0s,0n),+0s,2299161j)>
61
+ ```
62
+
63
+
64
+ ## Atomization
65
+
66
+ `DateTime#to_a` allows decomposing to an array of atoms:
67
+
68
+ ```ruby
69
+ atoms = ISO8601::DateTime.new('2014-05-31T10:11:12Z').to_a # => [2014, 5, 31, 10, 11, 12, '+00:00']
70
+ dt = DateTime.new(*atoms)
71
+ ```
72
+
73
+ ## Sign
74
+
75
+ Ordinal dates keep the sign. `2014-001` is not the same as `-2014-001`.
76
+
77
+
78
+ ## Fractional seconds precision
79
+
80
+ Fractional seconds for `ISO8601::DateTime` and `ISO8601::Time` are rounded to
81
+ one decimal.
82
+
83
+ ```ruby
84
+ ISO8601::DateTime.new('2015-02-03T10:11:12.12').second #=> 12.1
85
+ ISO8601::Time.new('T10:11:12.16').second #=> 12.2
86
+ ```
@@ -0,0 +1,76 @@
1
+ # Duration
2
+
3
+ > Durations are a component of time intervals and define the amount of
4
+ > intervening time in a time interval. Source: [Wikipedia ISO8601](https://en.wikipedia.org/wiki/ISO_8601#Durations)
5
+
6
+ See [Time Interval](time-interval.md) for working with specific intervals of
7
+ time.
8
+
9
+ ## Supported patterns
10
+
11
+ ```
12
+ PnYnMnDTnHnMnS
13
+ PnW
14
+ ```
15
+
16
+ `P<date>T<time>` will not be implemented.
17
+
18
+
19
+ ## Usage
20
+
21
+ Some times using durations might be more convenient than using time intervals:
22
+
23
+ ```ruby
24
+ duration = ISO8601::Duration.new('PT10H')
25
+ duration.to_seconds # => 36000.0
26
+ ```
27
+
28
+ You can reuse the duration with a time interval:
29
+
30
+ ```ruby
31
+ start_time = ISO8601::DateTime.new('2015-01-01T10:11:12Z')
32
+ time_interval = ISO8601::TimeInterval.from_duration(start_time, duration)
33
+ time_interval.size # => 36000.0
34
+ end_time = ISO8601::DateTime.new('2015-01-01T10:11:12Z')
35
+ time_interval = ISO8601::TimeInterval.from_duration(duration, end_time)
36
+ ```
37
+
38
+ Or use an ad-hoc base:
39
+
40
+ ```ruby
41
+ base = ISO8601::DateTime.new('2015-01-01T10:11:12Z')
42
+ duration = ISO8601::Duration.new('PT10H')
43
+ duration.to_seconds(base) # => 36000.0
44
+ ```
45
+
46
+ **Warning**: When using durations without base, the result of `#to_seconds` is
47
+ an _average_. See the atoms' implementation for details.
48
+
49
+
50
+ # Operate with durations
51
+
52
+ The `ISO8601::Duration` has the concept of sign to be able to represent negative
53
+ values:
54
+
55
+ ```ruby
56
+ (ISO8601::Duration.new('PT10S') - ISO8601::Duration.new('PT12S')).to_s #=> '-PT2S'
57
+ (ISO8601::Duration.new('-PT10S') + ISO8601::Duration.new('PT12S')).to_s #=> 'PT2S'
58
+ ```
59
+
60
+ You can also inspect a duration by atom:
61
+
62
+ ```
63
+ duration = ISO8601::Duration.new('P2Y1MT2H')
64
+ duration.years # => #<ISO8601::Years ... @atom=2.0>
65
+ duration.months # => #<ISO8601::Months ... @atom=1.0>
66
+ duration.days # => #<ISO8601::Days ... @atom=0>
67
+ duration.hours # => #<ISO8601::Hours ... @atom=2.0>
68
+ duration.minutes # => #<ISO8601::Hours ... @atom=0.0>
69
+ duration.seconds # => #<ISO8601::Hours ... @atom=0.0>
70
+ ```
71
+
72
+ Or get back the pattern:
73
+
74
+ ```ruby
75
+ duration.to_s # => 'P2Y1MT2H'
76
+ ```
@@ -0,0 +1,120 @@
1
+ # Time Interval
2
+
3
+ > A time interval is the intervening time between two time points.
4
+ Source: [Wikipedia ISO8601](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals)
5
+
6
+ This library implements the Time Interval type via [`ISO8601::TimeInterval`](../lib/iso8601/time_interval.rb)
7
+ with the following constructors:
8
+
9
+ * `TimeInterval.new(String)` (or `TimeInterval.parse(String)`)
10
+ * `TimeInterval.from_duration(Duration, Hash<DateTime>)`
11
+ * `TimeInterval.from_datetime(DateTime, DateTime)`
12
+
13
+
14
+ ## Supported patterns
15
+
16
+ ```
17
+ <start>/<end>
18
+ <start>/<duration>
19
+ <duration>/<end>
20
+ ```
21
+
22
+ Where `<start>` and `<end>` are points in time and `<duration>` is an amount of
23
+ time.
24
+
25
+ The pattern `<duration>` is not implemented; instead, you can use
26
+ [`TimeInterval.from_duration`](../lib/iso8601/time_interval.rb#L70).
27
+
28
+
29
+ ## Usage
30
+
31
+ ### `<start>/<end>`
32
+
33
+ The resulting time interval will have a starting point based on the provided
34
+ `<start>` pattern and an ending point based on the provided `<end>` pattern.
35
+
36
+ ```ruby
37
+ ti = ISO8601::TimeInterval.parse('2015-12-12T19:53:00Z/2015-12-13T19:53:00Z')
38
+ ti.start_time.to_s # => '2015-12-12T19:53:00Z'
39
+ ti.end_time.to_s # => '2015-12-13T19:53:00Z'
40
+ ti.size # => 86_400.0
41
+ ```
42
+
43
+ ### `<start>/<duration>`
44
+
45
+ The resulting time interval will have a starting point based on the provided
46
+ `<start>` pattern and an ending point result of `<start> + <duration>`.
47
+
48
+ ```ruby
49
+ ti = ISO8601::TimeInterval.parse('2015-12-12T19:53:00Z/P1D')
50
+ ti.start_time.to_s # => '2015-12-12T19:53:00Z'
51
+ ti.end_time.to_s # => '2015-12-13T19:53:00Z'
52
+ ti.size # => 86_400.0
53
+ ```
54
+
55
+ ### `<duration>/<end>`
56
+
57
+ The resulting time interval will have a starting point result of
58
+ `<end> - <duration>` and an ending point based on the provided `<end>` pattern.
59
+
60
+ ```ruby
61
+ ti = ISO8601::TimeInterval.parse('P1D/2015-12-13T19:53:00Z')
62
+ ti.start_time.to_s # => '2015-12-12T19:53:00Z'
63
+ ti.end_time.to_s # => '2015-12-13T19:53:00Z'
64
+ ti.size # => 86_400.0
65
+ ```
66
+
67
+
68
+ ### `TimeInterval.from_duration`
69
+
70
+ ```ruby
71
+ duration = ISO8601::Duration.new('P1D`)
72
+ start_time = ISO8601::DateTime.new('2015-12-12T19:53:00Z')
73
+ ti = ISO8601::TimeInterval.from_duration(start_time, duration)
74
+ ti.start_time.to_s # => '2015-12-12T19:53:00Z'
75
+ ti.end_time.to_s # => '2015-12-13T19:53:00Z'
76
+ ti.size # => 86_400.0
77
+
78
+
79
+ end_time = ISO8601::DateTime.new('2015-12-13T19:53:00Z')
80
+ ti2 = ISO8601::TimeInterval.from_duration(duration, end_time)
81
+ ti2.start_time.to_s # => '2015-12-12T19:53:00Z'
82
+ ti2.end_time.to_s # => '2015-12-13T19:53:00Z'
83
+ ti2.size # => 86_400.0
84
+ ```
85
+
86
+ ### `TimeInterval.from_datetime`
87
+
88
+ This constructor is an alternative way to `<start>/<end>` via Ruby objects.
89
+
90
+ ```ruby
91
+ start_time = ISO8601::DateTime.new('2015-12-12T19:53:00Z')
92
+ end_time = ISO8601::DateTime.new('2015-12-13T19:53:00Z')
93
+ ti2 = ISO8601::TimeInterval.from_duration(start_time, end_time)
94
+ ti2.start_time.to_s # => '2015-12-12T19:53:00Z'
95
+ ti2.end_time.to_s # => '2015-12-13T19:53:00Z'
96
+ ti2.size # => 86_400.0
97
+ ```
98
+
99
+ ## Operate with time intervals
100
+
101
+ `TimeInterval` is `Comparable`, so you can use the usual `<`, `>`, `<=`, `>=`,
102
+ `==` to compare against another `TimeInterval`. Is equivalent to get the
103
+ amount of seconds via `#to_f` and compare the resulting numbers.
104
+
105
+ A time interval can be viewed as an ordered set of datetime elements:
106
+
107
+ * `#empty?` checks if an interval is empty.
108
+ * `#include?` checks if a `DateTime` is part of the time interval.
109
+ * `#intersect?` checks if two time intervals overlap.
110
+ * `#intersection` returns the intersected time interval if the two intervals intersect.
111
+ * `#disjoint?` checks if two time intervals don't intersect.
112
+ * `#subset?` checks if a time interval is included in another one.
113
+ * `#superset?` checks if a time interval is included in another one.
114
+ * `#first` is the lower bound.
115
+ * `#last` is the upper bound.
116
+ * `#size` is the total amount of seconds.
117
+
118
+
119
+ You can convert a time interval into a string with `#to_s` or into a float via
120
+ `#to_f`.
@@ -1,5 +1,5 @@
1
1
  module ISO8601
2
2
  ##
3
3
  # The gem version
4
- VERSION = '0.12.2'.freeze
4
+ VERSION = '0.12.3'.freeze
5
5
  end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe ISO8601::Date do
4
+ it "should raise an error for any unknown pattern" do
5
+ expect { ISO8601::Date.new('') }.to raise_error(ISO8601::Errors::UnknownPattern)
6
+ expect { ISO8601::Date.new('2') }.to raise_error(ISO8601::Errors::UnknownPattern)
7
+ expect { ISO8601::Date.new('20') }.to raise_error(ISO8601::Errors::UnknownPattern)
8
+ expect { ISO8601::Date.new('201') }.to raise_error(ISO8601::Errors::UnknownPattern)
9
+ expect { ISO8601::Date.new('2010-') }.to raise_error(ISO8601::Errors::UnknownPattern)
10
+ expect { ISO8601::Date.new('2010-') }.to raise_error(ISO8601::Errors::UnknownPattern)
11
+ expect { ISO8601::Date.new('20-05') }.to raise_error(ISO8601::Errors::UnknownPattern)
12
+ expect { ISO8601::Date.new('2010-0') }.to raise_error(ISO8601::Errors::UnknownPattern)
13
+ expect { ISO8601::Date.new('2010-0-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
14
+ expect { ISO8601::Date.new('2010-1-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
15
+ expect { ISO8601::Date.new('201001-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
16
+ expect { ISO8601::Date.new('201-0109') }.to raise_error(ISO8601::Errors::UnknownPattern)
17
+ expect { ISO8601::Date.new('2014-W15-02') }.to raise_error(ISO8601::Errors::UnknownPattern)
18
+ end
19
+
20
+ it "should raise an error for a correct pattern but an invalid date" do
21
+ expect { ISO8601::Date.new('2010-01-32') }.to raise_error(ISO8601::Errors::RangeError)
22
+ expect { ISO8601::Date.new('2010-02-30') }.to raise_error(ISO8601::Errors::RangeError)
23
+ expect { ISO8601::Date.new('2010-13-30') }.to raise_error(ISO8601::Errors::RangeError)
24
+ end
25
+
26
+ it "should parse any allowed pattern" do
27
+ expect { ISO8601::Date.new('2010') }.to_not raise_error
28
+ expect { ISO8601::Date.new('2010-05') }.to_not raise_error
29
+ expect { ISO8601::Date.new('2010-05-09') }.to_not raise_error
30
+ expect { ISO8601::Date.new('2014-001') }.to_not raise_error
31
+ expect { ISO8601::Date.new('2014121') }.to_not raise_error
32
+ expect { ISO8601::Date.new('2014-W15') }.to_not raise_error
33
+ expect { ISO8601::Date.new('2014-W15-2') }.to_not raise_error
34
+ expect { ISO8601::Date.new('2014W15') }.to_not raise_error
35
+ expect { ISO8601::Date.new('2014W152') }.to_not raise_error
36
+ end
37
+
38
+ context 'reduced patterns' do
39
+ it "should parse correctly reduced dates" do
40
+ reduced_date = ISO8601::Date.new('20100509')
41
+ expect(reduced_date.year).to eq(2010)
42
+ expect(reduced_date.month).to eq(5)
43
+ expect(reduced_date.day).to eq(9)
44
+ end
45
+ end
46
+
47
+ it "should return the right sign for the given year" do
48
+ expect(ISO8601::Date.new('-2014-05-31').year).to eq(-2014)
49
+ expect(ISO8601::Date.new('+2014-05-31').year).to eq(2014)
50
+ end
51
+
52
+ it "should respond to delegated casting methods" do
53
+ expect(ISO8601::Date.new('2014-12-11')).to respond_to(:to_s, :to_time, :to_date, :to_datetime)
54
+ end
55
+
56
+ describe '#+' do
57
+ it "should return the result of the addition of a number" do
58
+ expect((ISO8601::Date.new('2012-07-07') + 7).to_s).to eq('2012-07-14')
59
+ end
60
+ end
61
+
62
+ describe '#-' do
63
+ it "should return the result of the subtraction" do
64
+ expect((ISO8601::Date.new('2012-07-07') - 7).to_s).to eq('2012-06-30')
65
+ end
66
+ end
67
+
68
+ describe '#to_a' do
69
+ it "should return an array of atoms" do
70
+ expect(ISO8601::Date.new('2014-05-31').to_a).to eq([2014, 5, 31])
71
+ end
72
+ end
73
+
74
+ describe '#atoms' do
75
+ it "should return an array of original atoms" do
76
+ expect(ISO8601::Date.new('2014-05-02').atoms).to eq([2014, 5, 2])
77
+ expect(ISO8601::Date.new('2014-05').atoms).to eq([2014, 5])
78
+ expect(ISO8601::Date.new('2014').atoms).to eq([2014])
79
+ end
80
+ end
81
+
82
+ describe '#hash' do
83
+ it "should return the date hash" do
84
+ subject = ISO8601::Date.new('2014-08-16')
85
+ contrast = ISO8601::Date.new('2014-08-16')
86
+
87
+ expect(subject).to respond_to(:hash)
88
+ expect(subject.hash).to eq(contrast.hash)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe ISO8601::DateTime do
4
+ it "should raise a ISO8601::Errors::UnknownPattern for any unknown pattern" do
5
+ expect { ISO8601::DateTime.new('') }.to raise_error(ISO8601::Errors::UnknownPattern)
6
+ expect { ISO8601::DateTime.new('2') }.to raise_error(ISO8601::Errors::UnknownPattern)
7
+ expect { ISO8601::DateTime.new('20') }.to raise_error(ISO8601::Errors::UnknownPattern)
8
+ expect { ISO8601::DateTime.new('201') }.to raise_error(ISO8601::Errors::UnknownPattern)
9
+ expect { ISO8601::DateTime.new('2010-') }.to raise_error(ISO8601::Errors::UnknownPattern)
10
+ expect { ISO8601::DateTime.new('2010-') }.to raise_error(ISO8601::Errors::UnknownPattern)
11
+ expect { ISO8601::DateTime.new('20-05') }.to raise_error(ISO8601::Errors::UnknownPattern)
12
+ expect { ISO8601::DateTime.new('2010-0') }.to raise_error(ISO8601::Errors::UnknownPattern)
13
+ expect { ISO8601::DateTime.new('2010-0-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
14
+ expect { ISO8601::DateTime.new('2010-1-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
15
+ expect { ISO8601::DateTime.new('201001-09') }.to raise_error(ISO8601::Errors::UnknownPattern)
16
+ expect { ISO8601::DateTime.new('201-0109') }.to raise_error(ISO8601::Errors::UnknownPattern)
17
+ expect { ISO8601::DateTime.new('2010-05-09T103012+0400') }.to raise_error(ISO8601::Errors::UnknownPattern)
18
+ expect { ISO8601::DateTime.new('20100509T10:30:12+04:00') }.to raise_error(ISO8601::Errors::UnknownPattern)
19
+ expect { ISO8601::DateTime.new('2010-05T10:30:12Z') }.to raise_error(ISO8601::Errors::UnknownPattern)
20
+ expect { ISO8601::DateTime.new('2010T10:30:12Z') }.to raise_error(ISO8601::Errors::UnknownPattern)
21
+ expect { ISO8601::DateTime.new('2014-W15-02T10:11:12Z') }.to raise_error(ISO8601::Errors::UnknownPattern)
22
+ end
23
+
24
+ it "should raise a RangeError for a correct pattern but an invalid date" do
25
+ expect { ISO8601::DateTime.new('2010-01-32') }.to raise_error(ISO8601::Errors::RangeError)
26
+ expect { ISO8601::DateTime.new('2010-02-30') }.to raise_error(ISO8601::Errors::RangeError)
27
+ expect { ISO8601::DateTime.new('2010-13-30') }.to raise_error(ISO8601::Errors::RangeError)
28
+ expect { ISO8601::DateTime.new('2010-12-30T25:00:00') }.to raise_error(ISO8601::Errors::RangeError)
29
+ end
30
+
31
+ it "should parse any allowed pattern" do
32
+ expect { ISO8601::DateTime.new('2010') }.to_not raise_error
33
+ expect { ISO8601::DateTime.new('2010-05') }.to_not raise_error
34
+ expect { ISO8601::DateTime.new('2010-05-09') }.to_not raise_error
35
+ expect { ISO8601::DateTime.new('2010-05-09T10') }.to_not raise_error
36
+ expect { ISO8601::DateTime.new('2010-05-09T10:30') }.to_not raise_error
37
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12') }.to_not raise_error
38
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12Z') }.to_not raise_error
39
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12+04') }.to_not raise_error
40
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12+04:00') }.to_not raise_error
41
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12-04:00') }.to_not raise_error
42
+ expect { ISO8601::DateTime.new('2010-05-09T10:30:12-00:00') }.to_not raise_error
43
+ expect { ISO8601::DateTime.new('-2014-05-31T16:26:00Z') }.to_not raise_error
44
+ expect { ISO8601::DateTime.new('2014-05-31T16:26:10.5Z') }.to_not raise_error
45
+ expect { ISO8601::DateTime.new('2014-05-31T16:26:10,5Z') }.to_not raise_error
46
+ expect { ISO8601::DateTime.new('T10:30:12Z') }.to_not raise_error
47
+ expect { ISO8601::DateTime.new('2014-001') }.to_not raise_error
48
+ expect { ISO8601::DateTime.new('2014121') }.to_not raise_error
49
+ expect { ISO8601::DateTime.new('2014-121T10:11:12Z') }.to_not raise_error
50
+ expect { ISO8601::DateTime.new('20100509T103012+0400') }.to_not raise_error
51
+ expect { ISO8601::DateTime.new('20100509') }.to_not raise_error
52
+ expect { ISO8601::DateTime.new('T103012+0400') }.to_not raise_error
53
+ expect { ISO8601::DateTime.new('T103012+04') }.to_not raise_error
54
+ expect { ISO8601::DateTime.new('T103012+04') }.to_not raise_error
55
+ end
56
+
57
+ context 'reduced patterns' do
58
+ it "should parse correctly reduced dates" do
59
+ reduced_date = ISO8601::DateTime.new('20100509')
60
+ expect(reduced_date.year).to eq(2010)
61
+ expect(reduced_date.month).to eq(5)
62
+ expect(reduced_date.day).to eq(9)
63
+ end
64
+ it "should parse correctly reduced times" do
65
+ reduced_time = ISO8601::DateTime.new('T101112Z')
66
+ expect(reduced_time.hour).to eq(10)
67
+ expect(reduced_time.minute).to eq(11)
68
+ expect(reduced_time.second).to eq(12)
69
+ end
70
+ it "should parse correctly reduced date times" do
71
+ reduced_datetime = ISO8601::DateTime.new('20140531T101112Z')
72
+ expect(reduced_datetime.year).to eq(2014)
73
+ expect(reduced_datetime.month).to eq(5)
74
+ expect(reduced_datetime.day).to eq(31)
75
+ expect(reduced_datetime.hour).to eq(10)
76
+ expect(reduced_datetime.minute).to eq(11)
77
+ expect(reduced_datetime.second).to eq(12)
78
+ end
79
+ end
80
+
81
+ it "should return each atomic value" do
82
+ dt = ISO8601::DateTime.new('2010-05-09T12:02:01+04:00')
83
+ expect(dt.year).to eq(2010)
84
+ expect(dt.month).to eq(5)
85
+ expect(dt.day).to eq(9)
86
+ expect(dt.hour).to eq(12)
87
+ expect(dt.minute).to eq(2)
88
+ expect(dt.second).to eq(1)
89
+ expect(dt.zone).to eq('+04:00')
90
+ end
91
+
92
+ it "should return the right sign for the given year" do
93
+ expect(ISO8601::DateTime.new('-2014-05-31T16:26:00Z').year).to eq(-2014)
94
+ expect(ISO8601::DateTime.new('+2014-05-31T16:26:00Z').year).to eq(2014)
95
+ end
96
+
97
+ it "should respond to delegated casting methods" do
98
+ dt = ISO8601::DateTime.new('2014-12-11T10:09:08Z')
99
+ expect(dt).to respond_to(:to_s, :to_time, :to_date, :to_datetime)
100
+ end
101
+
102
+ describe '#+' do
103
+ it "should return the result of the addition of a number" do
104
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20Z') + 10).to_s).to eq('2012-07-07T20:20:30+00:00')
105
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20.5Z') + 10).to_s).to eq('2012-07-07T20:20:30.5+00:00')
106
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20+02:00') + 10.09).to_s).to eq('2012-07-07T20:20:30.1+02:00')
107
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20+02:00') + 10.1).to_s).to eq('2012-07-07T20:20:30.1+02:00')
108
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20+02:00') + 10).second).to eq(30)
109
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20.5Z') + 10).second).to eq(30.5)
110
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20+02:00') + 10.09).second).to eq(30.1)
111
+ end
112
+ end
113
+
114
+ describe '#-' do
115
+ it "should return the result of the subtraction of a number" do
116
+ expect((ISO8601::DateTime.new('2012-07-07T20:20:20Z') - 10).to_s).to eq('2012-07-07T20:20:10+00:00')
117
+ end
118
+ end
119
+
120
+ describe '#to_a' do
121
+ it "should return an array of atoms" do
122
+ dt = ISO8601::DateTime.new('2014-05-31T19:29:39Z').to_a
123
+ expect(dt).to be_kind_of(Array)
124
+ expect(dt).to eq([2014, 5, 31, 19, 29, 39, '+00:00'])
125
+ end
126
+ end
127
+
128
+ describe '#hash' do
129
+ it "should return the datetime hash" do
130
+ subject = ISO8601::DateTime.new('2014-08-16T20:11:10Z')
131
+ contrast = ISO8601::DateTime.new('2014-08-16T20:11:10Z')
132
+
133
+ expect(subject.hash == contrast.hash).to be_truthy
134
+ expect(subject.hash).to eq(contrast.hash)
135
+ end
136
+ end
137
+
138
+ describe '#==' do
139
+ it "should identify loose precision datetimes" do
140
+ expect(ISO8601::DateTime.new('2014') == ISO8601::DateTime.new('2014')).to be_truthy
141
+ expect(ISO8601::DateTime.new('2014') == ISO8601::DateTime.new('2015')).to be_falsy
142
+ expect(ISO8601::DateTime.new('2014-10') == ISO8601::DateTime.new('2014-11')).to be_falsy
143
+ expect(ISO8601::DateTime.new('2014-10') == ISO8601::DateTime.new('2014-11')).to be_falsy
144
+ expect(ISO8601::DateTime.new('2014-10-11T12') == ISO8601::DateTime.new('2014-10-11T13')).to be_falsy
145
+ expect(ISO8601::DateTime.new('2014-10-11T12:13') == ISO8601::DateTime.new('2014-10-11T12:14')).to be_falsy
146
+ expect(ISO8601::DateTime.new('2014-10-11T12:13:10') == ISO8601::DateTime.new('2014-10-11T12:13:10.0')).to be_truthy
147
+ expect(ISO8601::DateTime.new('2014-10-11T12:13:10.1') == ISO8601::DateTime.new('2014-10-11T12:13:10.2')).to be_falsy
148
+ end
149
+
150
+ it "should identify as the same when two dates with different timezones are the same timestamp" do
151
+ expect(ISO8601::DateTime.new('2014-10-11T12:13:14Z') == ISO8601::DateTime.new('2014-10-11T13:13:14+01:00')).to be_truthy
152
+ end
153
+ end
154
+ end