edtf 0.0.5 → 0.0.6
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/README.md +24 -25
- data/features/parser/dates.feature +28 -5
- data/features/print/level_0_edtf.feature +73 -0
- data/features/print/level_1_edtf.feature +9 -62
- data/features/step_definitions/edtf_steps.rb +13 -0
- data/lib/edtf/date.rb +22 -17
- data/lib/edtf/parser.y +410 -229
- data/lib/edtf/version.rb +1 -1
- data/spec/edtf/parser_spec.rb +90 -0
- metadata +69 -108
- data/features/print/level_2_edtf.feature +0 -8
data/README.md
CHANGED
|
@@ -8,20 +8,15 @@ Specification](http://www.loc.gov/standards/datetime/spec.html).
|
|
|
8
8
|
Compatibility
|
|
9
9
|
-------------
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* Level 0: fully implemented
|
|
14
|
-
* Level 1: fully implemented
|
|
15
|
-
* Level 2: implemented features 202, 203, 204, 2041, 207, 208, and 209
|
|
11
|
+
EDTF-Ruby parser fully implements all levels and features of EDTF
|
|
12
|
+
Specification DRAFT, August 4, 2011.
|
|
16
13
|
|
|
17
14
|
The level 2 list extensions (203 and 204) currently return simple Ruby arrays;
|
|
18
15
|
therefore, advanced behavior (such as 'earlier' or 'later') is parsed correctly
|
|
19
16
|
but not yet exposed by the Ruby API.
|
|
20
17
|
|
|
21
|
-
The level 2 extensions 201 and 205 are currently _not_ supported.
|
|
22
|
-
|
|
23
18
|
EDTF-Ruby has been confirmed to work on the following Ruby implementations:
|
|
24
|
-
1.9.2, 1.8.7,
|
|
19
|
+
1.9.2, 1.8.7, Rubinius, and JRuby.
|
|
25
20
|
|
|
26
21
|
|
|
27
22
|
Quickstart
|
|
@@ -37,33 +32,35 @@ given a valid EDTF string the return value will either be an (extended) `Date`,
|
|
|
37
32
|
> require 'edtf'
|
|
38
33
|
> d = Date.edtf('1984?')
|
|
39
34
|
> d.uncertain?
|
|
40
|
-
|
|
35
|
+
=> true
|
|
41
36
|
> d.certain!
|
|
42
37
|
> d.uncertain?
|
|
43
|
-
|
|
38
|
+
=> false
|
|
44
39
|
> d = Date.edtf('1999-03-uu')
|
|
45
40
|
> d.unspecified?
|
|
46
|
-
|
|
41
|
+
=> true
|
|
47
42
|
> d.unspecified? :year
|
|
48
|
-
|
|
43
|
+
=> false
|
|
49
44
|
> d.unspecified? :day
|
|
50
|
-
|
|
45
|
+
=> true
|
|
51
46
|
> Date.edtf('2003-24').winter?
|
|
52
|
-
|
|
47
|
+
=> true
|
|
53
48
|
> Date.edtf('196x')
|
|
54
|
-
|
|
49
|
+
=> #<Date: 1960-01-01>...#<Date: 1970-01-01>
|
|
55
50
|
> Date.edtf('y-17e7').year
|
|
56
|
-
|
|
51
|
+
=> -170000000
|
|
57
52
|
> d = Date.edtf('1984-06?/2004-08?')
|
|
58
53
|
> d.from.uncertain?
|
|
59
|
-
|
|
60
|
-
> d.
|
|
61
|
-
|
|
62
|
-
> Date.edtf('
|
|
63
|
-
|
|
54
|
+
=> true
|
|
55
|
+
> d.to_a.length
|
|
56
|
+
=> 7397 # days between 1984-06-01 and 2004-08-31
|
|
57
|
+
> Date.edtf('1582-10/1582-10').to_a.length
|
|
58
|
+
=> 21 # number of days in October 1582 (Gregorian calendar)
|
|
59
|
+
> Date.edtf('2004/open').open?
|
|
60
|
+
=> true
|
|
64
61
|
|
|
65
62
|
|
|
66
|
-
For additional features take a look at the
|
|
63
|
+
For additional features take a look at the RDoc and RSpec examples.
|
|
67
64
|
|
|
68
65
|
|
|
69
66
|
Development
|
|
@@ -72,16 +69,18 @@ Development
|
|
|
72
69
|
$ git clone https://inukshuk@github.com/inukshuk/edtf-ruby.git
|
|
73
70
|
$ cd edtf-ruby
|
|
74
71
|
$ bundle install
|
|
75
|
-
$ bundle exec rake
|
|
72
|
+
$ bundle exec rake racc_debug
|
|
76
73
|
$ bundle exec rspec spec
|
|
77
74
|
$ bundle exec cucumber
|
|
78
75
|
|
|
79
|
-
For extra credit, fork the project on
|
|
76
|
+
For extra credit, fork the project on GitHub: pull requests welcome!
|
|
77
|
+
|
|
80
78
|
|
|
81
79
|
Credits
|
|
82
80
|
-------
|
|
83
81
|
|
|
84
|
-
EDTF-Ruby was written by [Sylvester Keil](http://sylvester.keil.or.at)
|
|
82
|
+
EDTF-Ruby was written by [Sylvester Keil](http://sylvester.keil.or.at) and
|
|
83
|
+
[Namyra](https://github.com/namyra).
|
|
85
84
|
|
|
86
85
|
Published under the terms and conditions of the FreeBSD License; see LICENSE
|
|
87
86
|
for details.
|
|
@@ -31,11 +31,11 @@ Feature: EDTF parser parses date strings
|
|
|
31
31
|
|
|
32
32
|
@101 @level1
|
|
33
33
|
Scenarios: uncertain date examples from the specification
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
| string | year | uncertain-year | month | uncertain-month | day | uncertain-day |
|
|
35
|
+
| 1992? | 1992 | yes | 1 | no | 1 | no |
|
|
36
|
+
| 1984? | 1984 | yes | 1 | no | 1 | no |
|
|
37
|
+
| 2004-06? | 2004 | yes | 6 | yes | 1 | no |
|
|
38
|
+
| 2004-06-11? | 2004 | yes | 6 | yes | 11 | yes |
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
Scenario Outline: EDTF parses uncertain or approximate date strings
|
|
@@ -51,3 +51,26 @@ Feature: EDTF parser parses date strings
|
|
|
51
51
|
| string | year | month | day | uncertain | approximate |
|
|
52
52
|
| 1984~ | 1984 | 1 | 1 | no | yes |
|
|
53
53
|
| 1984?~ | 1984 | 1 | 1 | yes | yes |
|
|
54
|
+
|
|
55
|
+
Scenario Outline: EDTF parses uncertain or approximate dates
|
|
56
|
+
When I parse the string "<string>"
|
|
57
|
+
And the year should be uncertain? "<?-year>"
|
|
58
|
+
And the month should be uncertain? "<?-month>"
|
|
59
|
+
And the day should be uncertain? "<?-day>"
|
|
60
|
+
And the year should be approximate? "<~-year>"
|
|
61
|
+
And the month should be approximate? "<~-month>"
|
|
62
|
+
And the day should be approximate? "<~-day>"
|
|
63
|
+
|
|
64
|
+
@201 @level2
|
|
65
|
+
Scenarios: uncertain date examples from the specification
|
|
66
|
+
| string | ~-year | ?-year | ~-month | ?-month | ~-day | ?-day |
|
|
67
|
+
| 2004?-06-11 | no | yes | no | no | no | no |
|
|
68
|
+
| 2004-06~-11 | yes | no | yes | no | no | no |
|
|
69
|
+
| 2004-(06)?-11 | no | no | no | yes | no | no |
|
|
70
|
+
| 2004-06-(11)~ | no | no | no | no | yes | no |
|
|
71
|
+
| 2004-(06)?~ | no | no | yes | yes | no | no |
|
|
72
|
+
| 2004-(06-11)? | no | no | no | yes | no | yes |
|
|
73
|
+
| 2004?-06-(11)~ | no | yes | no | no | yes | no |
|
|
74
|
+
| (2004-(06)~)? | no | yes | yes | yes | no | no |
|
|
75
|
+
| 2004-06-(01)~ | no | no | no | no | yes | no |
|
|
76
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Feature: Print Date/Time objects as Level 1 EDTF strings
|
|
2
|
+
As a Ruby programmer
|
|
3
|
+
I want to convert Date/Time objects to EDTF strings
|
|
4
|
+
|
|
5
|
+
@001 @level0
|
|
6
|
+
Scenario: Convert simple dates
|
|
7
|
+
Given the date "2004-08-12"
|
|
8
|
+
When I convert the date
|
|
9
|
+
Then the EDTF string should be "2004-08-12"
|
|
10
|
+
|
|
11
|
+
@001 @level0
|
|
12
|
+
Scenario: Convert simple dates with precision
|
|
13
|
+
Given the date "1980-08-24" with precision set to "day"
|
|
14
|
+
When I convert the date
|
|
15
|
+
Then the EDTF string should be "1980-08-24"
|
|
16
|
+
Given the date "1980-08-24" with precision set to "month"
|
|
17
|
+
When I convert the date
|
|
18
|
+
Then the EDTF string should be "1980-08"
|
|
19
|
+
Given the date "1980-08-24" with precision set to "year"
|
|
20
|
+
When I convert the date
|
|
21
|
+
Then the EDTF string should be "1980"
|
|
22
|
+
|
|
23
|
+
@001 @level0
|
|
24
|
+
Scenario: Date Roundtrips
|
|
25
|
+
When I parse the string "2001-02-03"
|
|
26
|
+
When I convert the date
|
|
27
|
+
Then the EDTF string should be "2001-02-03"
|
|
28
|
+
When I parse the string "2001-02"
|
|
29
|
+
When I convert the date
|
|
30
|
+
Then the EDTF string should be "2001-02"
|
|
31
|
+
When I parse the string "2001"
|
|
32
|
+
When I convert the date
|
|
33
|
+
Then the EDTF string should be "2001"
|
|
34
|
+
When I parse the string "-9909"
|
|
35
|
+
When I convert the date
|
|
36
|
+
Then the EDTF string should be "-9909"
|
|
37
|
+
When I parse the string "0000"
|
|
38
|
+
When I convert the date
|
|
39
|
+
Then the EDTF string should be "0000"
|
|
40
|
+
|
|
41
|
+
@002 @level0
|
|
42
|
+
Scenario: DateTime Roundtrips
|
|
43
|
+
When I parse the string "2001-02-03T09:30:01"
|
|
44
|
+
When I convert the date
|
|
45
|
+
Then the EDTF string should be "2001-02-03T09:30:01+00:00"
|
|
46
|
+
When I parse the string "2004-01-01T10:10:10Z"
|
|
47
|
+
When I convert the date
|
|
48
|
+
Then the EDTF string should be "2004-01-01T10:10:10+00:00"
|
|
49
|
+
When I parse the string "2004-01-01T10:10:10+05:00"
|
|
50
|
+
When I convert the date
|
|
51
|
+
Then the EDTF string should be "2004-01-01T10:10:10+05:00"
|
|
52
|
+
|
|
53
|
+
@004 @level0
|
|
54
|
+
Scenario: Interval Roundtrips
|
|
55
|
+
When I parse the string "1964/2008"
|
|
56
|
+
When I convert the date
|
|
57
|
+
Then the EDTF string should be "1964/2008"
|
|
58
|
+
When I parse the string "2004-06/2006-08"
|
|
59
|
+
When I convert the date
|
|
60
|
+
Then the EDTF string should be "2004-06/2006-08"
|
|
61
|
+
When I parse the string "2004-02-01/2005-02-08"
|
|
62
|
+
When I convert the date
|
|
63
|
+
Then the EDTF string should be "2004-02-01/2005-02-08"
|
|
64
|
+
When I parse the string "2004-02-01/2005-02"
|
|
65
|
+
When I convert the date
|
|
66
|
+
Then the EDTF string should be "2004-02-01/2005-02"
|
|
67
|
+
When I parse the string "2004-02-01/2005"
|
|
68
|
+
When I convert the date
|
|
69
|
+
Then the EDTF string should be "2004-02-01/2005"
|
|
70
|
+
When I parse the string "2005/2006-02"
|
|
71
|
+
When I convert the date
|
|
72
|
+
Then the EDTF string should be "2005/2006-02"
|
|
73
|
+
|
|
@@ -1,68 +1,15 @@
|
|
|
1
|
-
Feature: Print Date/Time objects as Level
|
|
1
|
+
Feature: Print Date/Time objects as Level 2 EDTF strings
|
|
2
2
|
As a Ruby programmer
|
|
3
3
|
I want to convert Date/Time objects to EDTF strings
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Then the EDTF string should be "2004-08-12"
|
|
9
|
-
|
|
10
|
-
Scenario: Convert simple dates with precision
|
|
11
|
-
Given the date "1980-08-24" with precision set to "day"
|
|
5
|
+
@101 @level1
|
|
6
|
+
Scenario: Uncertain or approximate dates
|
|
7
|
+
When I parse the string "2001?"
|
|
12
8
|
When I convert the date
|
|
13
|
-
Then the EDTF string should be "
|
|
14
|
-
|
|
9
|
+
Then the EDTF string should be "2001?"
|
|
10
|
+
When I parse the string "2004-06?"
|
|
15
11
|
When I convert the date
|
|
16
|
-
Then the EDTF string should be "
|
|
17
|
-
|
|
12
|
+
Then the EDTF string should be "2004-06?"
|
|
13
|
+
When I parse the string "2004-06-11?"
|
|
18
14
|
When I convert the date
|
|
19
|
-
Then the EDTF string should be "
|
|
20
|
-
|
|
21
|
-
Scenario: Date Roundtrips
|
|
22
|
-
When I parse the string "2001-02-03"
|
|
23
|
-
When I convert the date
|
|
24
|
-
Then the EDTF string should be "2001-02-03"
|
|
25
|
-
When I parse the string "2001-02"
|
|
26
|
-
When I convert the date
|
|
27
|
-
Then the EDTF string should be "2001-02"
|
|
28
|
-
When I parse the string "2001"
|
|
29
|
-
When I convert the date
|
|
30
|
-
Then the EDTF string should be "2001"
|
|
31
|
-
When I parse the string "-9909"
|
|
32
|
-
When I convert the date
|
|
33
|
-
Then the EDTF string should be "-9909"
|
|
34
|
-
When I parse the string "0000"
|
|
35
|
-
When I convert the date
|
|
36
|
-
Then the EDTF string should be "0000"
|
|
37
|
-
|
|
38
|
-
Scenario: DateTime Roundtrips
|
|
39
|
-
When I parse the string "2001-02-03T09:30:01"
|
|
40
|
-
When I convert the date
|
|
41
|
-
Then the EDTF string should be "2001-02-03T09:30:01+00:00"
|
|
42
|
-
When I parse the string "2004-01-01T10:10:10Z"
|
|
43
|
-
When I convert the date
|
|
44
|
-
Then the EDTF string should be "2004-01-01T10:10:10+00:00"
|
|
45
|
-
When I parse the string "2004-01-01T10:10:10+05:00"
|
|
46
|
-
When I convert the date
|
|
47
|
-
Then the EDTF string should be "2004-01-01T10:10:10+05:00"
|
|
48
|
-
|
|
49
|
-
Scenario: Interval Roundtrips
|
|
50
|
-
When I parse the string "1964/2008"
|
|
51
|
-
When I convert the date
|
|
52
|
-
Then the EDTF string should be "1964/2008"
|
|
53
|
-
When I parse the string "2004-06/2006-08"
|
|
54
|
-
When I convert the date
|
|
55
|
-
Then the EDTF string should be "2004-06/2006-08"
|
|
56
|
-
When I parse the string "2004-02-01/2005-02-08"
|
|
57
|
-
When I convert the date
|
|
58
|
-
Then the EDTF string should be "2004-02-01/2005-02-08"
|
|
59
|
-
When I parse the string "2004-02-01/2005-02"
|
|
60
|
-
When I convert the date
|
|
61
|
-
Then the EDTF string should be "2004-02-01/2005-02"
|
|
62
|
-
When I parse the string "2004-02-01/2005"
|
|
63
|
-
When I convert the date
|
|
64
|
-
Then the EDTF string should be "2004-02-01/2005"
|
|
65
|
-
When I parse the string "2005/2006-02"
|
|
66
|
-
When I convert the date
|
|
67
|
-
Then the EDTF string should be "2005/2006-02"
|
|
68
|
-
|
|
15
|
+
Then the EDTF string should be "2004-06-11?"
|
|
@@ -93,6 +93,19 @@ Then /^the date should be approximate\? "([^"]*)"$/ do |arg1|
|
|
|
93
93
|
@date.approximate?.should == !!(arg1 =~ /y(es)?/i)
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
+
Then /^the year should be approximate\? "([^"]*)"$/ do |arg1|
|
|
97
|
+
@date.approximate?(:year).should == !!(arg1 =~ /y(es)?/i)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Then /^the month should be approximate\? "([^"]*)"$/ do |arg1|
|
|
101
|
+
@date.approximate?(:month).should == !!(arg1 =~ /y(es)?/i)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
Then /^the day should be approximate\? "([^"]*)"$/ do |arg1|
|
|
105
|
+
@date.approximate?(:day).should == !!(arg1 =~ /y(es)?/i)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
96
109
|
Then /^the unspecified string code be "([^"]*)"$/ do |arg1|
|
|
97
110
|
@date.unspecified.to_s.should == arg1
|
|
98
111
|
end
|
data/lib/edtf/date.rb
CHANGED
|
@@ -46,6 +46,7 @@ class Date
|
|
|
46
46
|
@precision ||= :day
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
# Sets this Date/Time's precision to the passed-in value.
|
|
49
50
|
def precision=(precision)
|
|
50
51
|
precision = precision.to_sym
|
|
51
52
|
raise ArgumentError, "invalid precision #{precision.inspect}" unless PRECISIONS.include?(precision)
|
|
@@ -71,37 +72,37 @@ class Date
|
|
|
71
72
|
|
|
72
73
|
def_delegators :uncertain, :uncertain?, :certain?
|
|
73
74
|
|
|
74
|
-
def certain!(
|
|
75
|
-
uncertain.certain!(
|
|
75
|
+
def certain!(arguments = precision_filter)
|
|
76
|
+
uncertain.certain!(arguments)
|
|
76
77
|
self
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
def uncertain!(
|
|
80
|
-
uncertain.uncertain!(
|
|
80
|
+
def uncertain!(arguments = precision_filter)
|
|
81
|
+
uncertain.uncertain!(arguments)
|
|
81
82
|
self
|
|
82
83
|
end
|
|
83
84
|
|
|
84
|
-
def approximate?(
|
|
85
|
-
approximate.uncertain?(
|
|
85
|
+
def approximate?(arguments = precision_filter)
|
|
86
|
+
approximate.uncertain?(arguments)
|
|
86
87
|
end
|
|
87
88
|
|
|
88
89
|
alias approximately? approximate?
|
|
89
90
|
|
|
90
|
-
def approximate!(
|
|
91
|
-
approximate.uncertain!(
|
|
91
|
+
def approximate!(arguments = precision_filter)
|
|
92
|
+
approximate.uncertain!(arguments)
|
|
92
93
|
self
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
alias approximately! approximate!
|
|
96
97
|
|
|
97
|
-
def precise?(
|
|
98
|
-
!approximate?(
|
|
98
|
+
def precise?(arguments = precision_filter)
|
|
99
|
+
!approximate?(arguments)
|
|
99
100
|
end
|
|
100
101
|
|
|
101
102
|
alias precisely? precise?
|
|
102
103
|
|
|
103
|
-
def precise!(
|
|
104
|
-
approximate.certain!(
|
|
104
|
+
def precise!(arguments = precision_filter)
|
|
105
|
+
approximate.certain!(arguments)
|
|
105
106
|
self
|
|
106
107
|
end
|
|
107
108
|
|
|
@@ -109,15 +110,15 @@ class Date
|
|
|
109
110
|
|
|
110
111
|
def_delegators :unspecified, :unspecified?, :specified?, :unsepcific?, :specific?
|
|
111
112
|
|
|
112
|
-
def unspecified!(
|
|
113
|
-
unspecified.unspecified!(
|
|
113
|
+
def unspecified!(arguments = precision_filter)
|
|
114
|
+
unspecified.unspecified!(arguments)
|
|
114
115
|
self
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
alias unspecific! unspecified!
|
|
118
119
|
|
|
119
|
-
def specified!(
|
|
120
|
-
unspecified.specified!(
|
|
120
|
+
def specified!(arguments = precision_filter)
|
|
121
|
+
unspecified.specified!(arguments)
|
|
121
122
|
self
|
|
122
123
|
end
|
|
123
124
|
|
|
@@ -130,11 +131,13 @@ class Date
|
|
|
130
131
|
end
|
|
131
132
|
|
|
132
133
|
def edtf
|
|
133
|
-
FORMATS.take(values.length).join('-') % values
|
|
134
|
+
FORMATS.take(values.length).join('-') % values << (uncertain? ? '?' : '')
|
|
134
135
|
end
|
|
135
136
|
|
|
136
137
|
alias to_edtf edtf
|
|
137
138
|
|
|
139
|
+
# Returns a the Date of the next day, month, or year depending on the
|
|
140
|
+
# current Date/Time's precision.
|
|
138
141
|
def next
|
|
139
142
|
send("next_#{precision}")
|
|
140
143
|
end
|
|
@@ -151,6 +154,8 @@ class Date
|
|
|
151
154
|
# def ===(other)
|
|
152
155
|
# end
|
|
153
156
|
|
|
157
|
+
# Returns an array of the current year, month, and day values filtered by
|
|
158
|
+
# the Date/Time's precision.
|
|
154
159
|
def values
|
|
155
160
|
precision_filter.map { |p| send(p) }
|
|
156
161
|
end
|
data/lib/edtf/parser.y
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
class EDTF::Parser
|
|
4
4
|
|
|
5
|
-
token T Z E X
|
|
6
|
-
UNCERTAIN APPROXIMATE UNSPECIFIED UNKNOWN OPEN LONGYEAR CARET UNMATCHED
|
|
7
|
-
DOTS COMMA LBRACE RBRACE LSQUARE RSQUARE
|
|
5
|
+
token T Z E X U UNKNOWN OPEN LONGYEAR UNMATCHED DOTS IUA
|
|
8
6
|
|
|
9
7
|
expect 0
|
|
10
8
|
|
|
@@ -13,253 +11,421 @@ rule
|
|
|
13
11
|
edtf : level_0_expression
|
|
14
12
|
| level_1_expression
|
|
15
13
|
| level_2_expression
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
;
|
|
18
15
|
|
|
19
16
|
# ---- Level 0 / ISO 8601 Rules ----
|
|
20
|
-
|
|
17
|
+
|
|
18
|
+
# NB: level 0 intervals are covered by the level 1 interval rules
|
|
21
19
|
level_0_expression : date
|
|
22
20
|
| date_time
|
|
23
|
-
|
|
21
|
+
;
|
|
24
22
|
|
|
25
23
|
date : positive_date
|
|
26
24
|
| negative_date
|
|
25
|
+
;
|
|
27
26
|
|
|
28
|
-
positive_date :
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
positive_date :
|
|
28
|
+
year { result = Date.new(val[0]); result.precision = :year }
|
|
29
|
+
| year_month { result = Date.new(*val.flatten); result.precision = :month }
|
|
30
|
+
| year_month_day { result = Date.new(*val.flatten); result.precision = :day }
|
|
31
|
+
;
|
|
33
32
|
|
|
33
|
+
negative_date : '-' positive_date { result = -val[1] }
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
date_time : date T time {
|
|
37
|
+
result = DateTime.new(val[0].year, val[0].month, val[0].day, *val[2])
|
|
38
|
+
}
|
|
36
39
|
|
|
37
40
|
time : base_time
|
|
38
41
|
| base_time zone_offset { result = val.flatten }
|
|
39
|
-
|
|
40
|
-
base_time : hour
|
|
42
|
+
|
|
43
|
+
base_time : hour ':' minute ':' second { result = val.values_at(0, 2, 4) }
|
|
41
44
|
| midnight
|
|
42
|
-
|
|
43
|
-
midnight :
|
|
44
|
-
|
|
45
|
-
zone_offset : Z
|
|
46
|
-
|
|
|
47
|
-
|
|
|
45
|
+
|
|
46
|
+
midnight : '2' '4' ':' '0' '0' ':' '0' '0' { result = [24, 0, 0] }
|
|
47
|
+
|
|
48
|
+
zone_offset : Z { result = 0 }
|
|
49
|
+
| '-' zone_offset_hour { result = -1 * val[1] }
|
|
50
|
+
| '+' positive_zone_offset { result = val[1] }
|
|
51
|
+
;
|
|
48
52
|
|
|
49
53
|
positive_zone_offset : zone_offset_hour
|
|
50
|
-
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
| '0' '0' ':' '0' '0' { result = 0 }
|
|
55
|
+
;
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
zone_offset_hour : d01_13 ':' minute { result = Rational(val[0] * 60 + val[2], 1440) }
|
|
59
|
+
| '1' '4' ':' '0' '0' { result = Rational(840, 1440) }
|
|
60
|
+
| '0' '0' ':' d01_59 { result = Rational(val[3], 1440) }
|
|
61
|
+
;
|
|
62
|
+
|
|
63
|
+
year : digit digit digit digit {
|
|
64
|
+
result = val.zip([1000,100,10,1]).reduce(0) { |s,(a,b)| s += a * b }
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
month : d01_12
|
|
60
|
-
|
|
61
|
-
year_month : year
|
|
62
|
-
|
|
68
|
+
|
|
69
|
+
year_month : year '-' month { result = [val[0], val[2]] }
|
|
70
|
+
|
|
63
71
|
# We raise an exception if there are two many days for the month, but
|
|
64
72
|
# do not consider leap years, as the EDTF BNF did not either.
|
|
65
73
|
# NB: an exception will be raised regardless, because the Ruby Date
|
|
66
74
|
# implementation calculates leap years.
|
|
67
|
-
year_month_day : year_month
|
|
75
|
+
year_month_day : year_month '-' d01_31 {
|
|
76
|
+
result = val[0] << val[2]
|
|
77
|
+
if result[2] > 31 || (result[2] > 30 && [2,4,6,9,11].include?(result[1])) || (result[2] > 29 && result[1] == 2)
|
|
78
|
+
raise ArgumentError, "invalid date (invalid days #{result[2]} for month #{result[1]})"
|
|
79
|
+
end
|
|
80
|
+
}
|
|
68
81
|
|
|
69
|
-
hour
|
|
70
|
-
|
|
82
|
+
hour : d00_23
|
|
71
83
|
minute : d00_59
|
|
72
|
-
|
|
73
84
|
second : d00_59
|
|
74
|
-
|
|
75
|
-
# covered by level_1_interval
|
|
76
|
-
# level_0_interval : date
|
|
85
|
+
|
|
86
|
+
# Completely covered by level_1_interval
|
|
87
|
+
# level_0_interval : date '/' date { result = Interval.new(val[0], val[1]) }
|
|
88
|
+
|
|
77
89
|
|
|
78
90
|
# ---- Level 1 Extension Rules ----
|
|
79
|
-
|
|
80
|
-
level_1_expression : uncertain_or_approximate_date
|
|
81
|
-
| unspecified
|
|
82
|
-
| level_1_interval
|
|
83
|
-
| long_year_simple
|
|
84
|
-
| season
|
|
85
|
-
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
| UNCERTAIN APPROXIMATE { result = [:uncertain!, :approximate!] }
|
|
92
|
-
|
|
92
|
+
# NB: Uncertain/approximate Dates are covered by the Level 2 rules
|
|
93
|
+
level_1_expression : unspecified | level_1_interval | long_year_simple | season
|
|
94
|
+
|
|
95
|
+
# uncertain_or_approximate_date : date ua { result = uoa(val[0], val[1]) }
|
|
93
96
|
|
|
94
|
-
unspecified : unspecified_year
|
|
97
|
+
unspecified : unspecified_year
|
|
98
|
+
{
|
|
99
|
+
result = Date.new(val[0][0])
|
|
100
|
+
result.unspecified.year[2,2] = val[0][1]
|
|
101
|
+
result.precision = :year
|
|
102
|
+
}
|
|
95
103
|
| unspecified_month
|
|
96
104
|
| unspecified_day
|
|
97
105
|
| unspecified_day_and_month
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
;
|
|
107
|
+
|
|
108
|
+
unspecified_year :
|
|
109
|
+
digit digit digit U
|
|
110
|
+
{
|
|
111
|
+
result = [val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }, [false,true]]
|
|
112
|
+
}
|
|
113
|
+
| digit digit U U
|
|
114
|
+
{
|
|
115
|
+
result = [val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }, [true, true]]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
unspecified_month : year '-' U U {
|
|
119
|
+
result = Date.new(val[0]).unspecified!(:month)
|
|
120
|
+
result.precision = :month
|
|
121
|
+
}
|
|
107
122
|
|
|
123
|
+
unspecified_day : year_month '-' U U {
|
|
124
|
+
result = Date.new(*val[0]).unspecified!(:day)
|
|
125
|
+
}
|
|
108
126
|
|
|
109
|
-
|
|
127
|
+
unspecified_day_and_month : year '-' U U '-' U U {
|
|
128
|
+
result = Date.new(val[0]).unspecified!([:day,:month])
|
|
129
|
+
}
|
|
110
130
|
|
|
111
|
-
level_1_start : date
|
|
112
|
-
| uncertain_or_approximate_date
|
|
113
|
-
| UNKNOWN { result = :unknown }
|
|
114
|
-
|
|
115
|
-
level_1_end : level_1_start
|
|
116
|
-
| OPEN { result = :open }
|
|
117
131
|
|
|
132
|
+
level_1_interval : level_1_start '/' level_1_end {
|
|
133
|
+
result = Interval.new(val[0], val[2])
|
|
134
|
+
}
|
|
118
135
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
level_1_start : date | internal_uncertain_or_approximate_date | UNKNOWN
|
|
137
|
+
|
|
138
|
+
level_1_end : level_1_start | OPEN
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
long_year_simple :
|
|
142
|
+
LONGYEAR long_year
|
|
143
|
+
{
|
|
144
|
+
result = Date.new(val[1])
|
|
145
|
+
result.precision = :year
|
|
146
|
+
}
|
|
147
|
+
| LONGYEAR '-' long_year
|
|
148
|
+
{
|
|
149
|
+
result = Date.new(-1 * val[2])
|
|
150
|
+
result.precision = :year
|
|
151
|
+
}
|
|
152
|
+
;
|
|
153
|
+
|
|
154
|
+
long_year :
|
|
155
|
+
positive_digit digit digit digit digit {
|
|
156
|
+
result = val.zip([10000,1000,100,10,1]).reduce(0) { |s,(a,b)| s += a * b }
|
|
157
|
+
}
|
|
158
|
+
| long_year digit { result = 10 * val[0] + val[1] }
|
|
159
|
+
;
|
|
124
160
|
|
|
125
161
|
|
|
126
|
-
season : year
|
|
162
|
+
season : year '-' season_number { result = Season.new(val[0], val[2]) }
|
|
127
163
|
|
|
128
|
-
season_number :
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
|
164
|
+
season_number : '2' '1' { result = 21 }
|
|
165
|
+
| '2' '2' { result = 22 }
|
|
166
|
+
| '2' '3' { result = 23 }
|
|
167
|
+
| '2' '4' { result = 24 }
|
|
168
|
+
;
|
|
132
169
|
|
|
133
170
|
|
|
134
171
|
# ---- Level 2 Extension Rules ----
|
|
135
|
-
|
|
172
|
+
|
|
173
|
+
# NB: Level 2 Intervals are covered by the Level 1 Interval rules.
|
|
136
174
|
level_2_expression : season_qualified
|
|
137
|
-
|
|
175
|
+
| internal_uncertain_or_approximate_date
|
|
138
176
|
| internal_unspecified
|
|
139
177
|
| choice_list
|
|
140
178
|
| inclusive_list
|
|
141
179
|
| masked_precision
|
|
142
|
-
# | level_2_interval
|
|
143
180
|
| date_and_calendar
|
|
144
181
|
| long_year_scientific
|
|
145
|
-
|
|
182
|
+
;
|
|
146
183
|
|
|
147
|
-
season_qualified : season CARET { result = val[0]; result.qualifier = val[1] }
|
|
148
184
|
|
|
185
|
+
season_qualified : season '^' { result = val[0]; result.qualifier = val[1] }
|
|
149
186
|
|
|
150
|
-
long_year_scientific : long_year_simple E integer { result = Date.new(val[0].year * 10 ** val[2]); result.precision = :year }
|
|
151
|
-
| LONGYEAR int1_4 E integer { result = Date.new(val[1] * 10 ** val[3]); result.precision = :year }
|
|
152
|
-
| LONGYEAR MINUS int1_4 E integer { result = Date.new(-1 * val[2] * 10 ** val[4]); result.precision = :year }
|
|
153
|
-
|
|
154
187
|
|
|
155
|
-
|
|
156
|
-
|
|
188
|
+
long_year_scientific :
|
|
189
|
+
long_year_simple E integer
|
|
190
|
+
{
|
|
191
|
+
result = Date.new(val[0].year * 10 ** val[2])
|
|
192
|
+
result.precision = :year
|
|
193
|
+
}
|
|
194
|
+
| LONGYEAR int1_4 E integer
|
|
195
|
+
{
|
|
196
|
+
result = Date.new(val[1] * 10 ** val[3])
|
|
197
|
+
result.precision = :year
|
|
198
|
+
}
|
|
199
|
+
| LONGYEAR '-' int1_4 E integer
|
|
200
|
+
{
|
|
201
|
+
result = Date.new(-1 * val[2] * 10 ** val[4])
|
|
202
|
+
result.precision = :year
|
|
203
|
+
}
|
|
204
|
+
;
|
|
157
205
|
|
|
158
|
-
masked_precision : digit digit digit X { d = val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }; result = Date.new(d) ... Date.new(d+10) }
|
|
159
|
-
| digit digit X X { d = val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }; result = Date.new(d) ... Date.new(d+100) }
|
|
160
206
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
207
|
+
date_and_calendar : date '^' { result = val[0]; result.calendar = val[1] }
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
masked_precision :
|
|
211
|
+
digit digit digit X
|
|
212
|
+
{
|
|
213
|
+
d = val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }
|
|
214
|
+
result = Date.new(d) ... Date.new(d+10)
|
|
215
|
+
}
|
|
216
|
+
| digit digit X X
|
|
217
|
+
{
|
|
218
|
+
d = val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }
|
|
219
|
+
result = Date.new(d) ... Date.new(d+100)
|
|
220
|
+
}
|
|
221
|
+
;
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
choice_list : '[' list ']' { result = val[1] }
|
|
225
|
+
|
|
226
|
+
inclusive_list : '{' list '}' { result = val[1] }
|
|
227
|
+
|
|
228
|
+
list : earlier { result = val }
|
|
229
|
+
| earlier ',' list_elements ',' later { result = [val[0]] + val[2] + [val[4]] }
|
|
230
|
+
| earlier ',' list_elements { result = [val[0]] + val[2] }
|
|
231
|
+
| earlier ',' later { result = [val[0]] + [val[2]] }
|
|
232
|
+
| list_elements ',' later { result = val[0] + [val[2]] }
|
|
171
233
|
| list_elements
|
|
172
|
-
| later
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
234
|
+
| later { result = val }
|
|
235
|
+
;
|
|
236
|
+
|
|
237
|
+
list_elements : list_element { result = [val[0]].flatten }
|
|
238
|
+
| list_elements ',' list_element { result = val[0] + [val[2]].flatten }
|
|
239
|
+
;
|
|
240
|
+
|
|
177
241
|
list_element : date
|
|
178
|
-
|
|
179
|
-
| uncertain_or_approximate_date
|
|
242
|
+
| internal_uncertain_or_approximate_date
|
|
180
243
|
| unspecified
|
|
181
|
-
| consecutives
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
|
188
|
-
|
|
244
|
+
| consecutives { result = val[0].map { |d| Date.new(*d) } }
|
|
245
|
+
;
|
|
246
|
+
|
|
247
|
+
earlier : DOTS date { result = val[1] }
|
|
248
|
+
|
|
249
|
+
later : year_month_day DOTS { result = Date.new(*val[0]); result.precision = :day }
|
|
250
|
+
| year_month DOTS { result = Date.new(*val[0]); result.precision = :month }
|
|
251
|
+
| year DOTS { result = Date.new(val[0]); result.precision = :year }
|
|
252
|
+
;
|
|
253
|
+
|
|
189
254
|
consecutives : year_month_day DOTS year_month_day
|
|
190
255
|
| year_month DOTS year_month
|
|
191
|
-
| year DOTS year
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
internal_unspecified :
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
256
|
+
| year DOTS year { result = (val[0]..val[2]).to_a.map }
|
|
257
|
+
;
|
|
258
|
+
|
|
259
|
+
internal_unspecified :
|
|
260
|
+
unspecified_year '-' month '-' d01_31
|
|
261
|
+
{
|
|
262
|
+
result = Date.new(val[0][0], val[2], val[4])
|
|
263
|
+
result.unspecified.year[2,2] = val[0][1]
|
|
264
|
+
}
|
|
265
|
+
| unspecified_year '-' U U '-' d01_31
|
|
266
|
+
{
|
|
267
|
+
result = Date.new(val[0][0], 1, val[5])
|
|
268
|
+
result.unspecified.year[2,2] = val[0][1]
|
|
269
|
+
result.unspecified!(:month)
|
|
270
|
+
}
|
|
271
|
+
| unspecified_year '-' U U '-' U U
|
|
272
|
+
{
|
|
273
|
+
result = Date.new(val[0][0], 1, 1)
|
|
274
|
+
result.unspecified.year[2,2] = val[0][1]
|
|
275
|
+
result.unspecified!([:month, :day])
|
|
276
|
+
}
|
|
277
|
+
| unspecified_year '-' month '-' U U
|
|
278
|
+
{
|
|
279
|
+
result = Date.new(val[0][0], val[2], 1)
|
|
280
|
+
result.unspecified.year[2,2] = val[0][1]
|
|
281
|
+
result.unspecified!(:day)
|
|
282
|
+
}
|
|
283
|
+
| year '-' U U '-' d01_31
|
|
284
|
+
{
|
|
285
|
+
result = Date.new(val[0], 1, val[5])
|
|
286
|
+
result.unspecified!(:month)
|
|
287
|
+
}
|
|
288
|
+
;
|
|
289
|
+
|
|
290
|
+
internal_uncertain_or_approximate_date : internal_uncertain_or_approximate
|
|
291
|
+
| '(' internal_uncertain_or_approximate ')' ua { result = uoa(val[1], val[3]) }
|
|
292
|
+
|
|
293
|
+
internal_uncertain_or_approximate :
|
|
294
|
+
iua_year { result = val[0]; result.precision = :year }
|
|
295
|
+
| iua_year_month { result = val[0]; result.precision = :month }
|
|
296
|
+
| iua_year_month_day
|
|
297
|
+
|
|
298
|
+
iua_year : year ua { result = uoa(Date.new(val[0]), val[1], :year) }
|
|
299
|
+
|
|
300
|
+
iua_year_month :
|
|
301
|
+
iua_year '-' month opt_ua
|
|
302
|
+
{
|
|
303
|
+
result = uoa(val[0].change(:month => val[2]), val[3], [:month, :year])
|
|
304
|
+
}
|
|
305
|
+
| '(' iua_year IUA month opt_ua
|
|
306
|
+
{
|
|
307
|
+
result = uoa(uoa(val[1], val[2], :year).change(:month => val[3]), val[4], :month)
|
|
308
|
+
}
|
|
309
|
+
| year '-' month ua
|
|
310
|
+
{
|
|
311
|
+
result = uoa(Date.new(val[0], val[2]), val[3], [:year, :month])
|
|
312
|
+
}
|
|
313
|
+
| year '-' '(' month ')' ua
|
|
314
|
+
{
|
|
315
|
+
result = uoa(Date.new(val[0], val[3]), val[5], [:month])
|
|
316
|
+
}
|
|
317
|
+
;
|
|
318
|
+
|
|
319
|
+
iua_year_month_day :
|
|
320
|
+
iua_year_month '-' d01_31 opt_ua
|
|
321
|
+
{
|
|
322
|
+
result = uoa(val[0].change(:day => val[2]), val[3])
|
|
323
|
+
}
|
|
324
|
+
| iua_year_month '-' '(' d01_31 ')' ua
|
|
325
|
+
{
|
|
326
|
+
result = uoa(val[0].change(:day => val[3]), val[5], [:day])
|
|
327
|
+
}
|
|
328
|
+
| '(' iua_year_month IUA d01_31 opt_ua
|
|
329
|
+
{
|
|
330
|
+
result = uoa(uoa(val[1], val[2], [:year, :month]).change(:day => val[3]), val[4], :day)
|
|
331
|
+
}
|
|
332
|
+
| year '-' '(' month IUA d01_31 opt_ua
|
|
333
|
+
{
|
|
334
|
+
result = uoa(uoa(Date.new(val[0], val[3], val[5]), val[4], :month), val[6], :day)
|
|
335
|
+
}
|
|
336
|
+
| year_month '-' d01_31 ua
|
|
337
|
+
{
|
|
338
|
+
result = uoa(Date.new(val[0][0], val[0][1], val[2]), val[3])
|
|
339
|
+
}
|
|
340
|
+
| year_month '-' '(' d01_31 ')' ua
|
|
341
|
+
{
|
|
342
|
+
result = uoa(Date.new(val[0][0], val[0][1], val[3]), val[5], [:day])
|
|
343
|
+
}
|
|
344
|
+
| year '-' '(' month '-' d01_31 ')' ua
|
|
345
|
+
{
|
|
346
|
+
result = uoa(Date.new(val[0], val[3], val[5]), val[7], [:month, :day])
|
|
347
|
+
}
|
|
348
|
+
;
|
|
349
|
+
|
|
350
|
+
opt_ua : { result = [] } | ua
|
|
351
|
+
|
|
352
|
+
ua : '?'
|
|
353
|
+
| '~'
|
|
354
|
+
| '?' '~' { result = val.flatten }
|
|
355
|
+
;
|
|
200
356
|
|
|
201
357
|
# ---- Auxiliary Rules ----
|
|
202
358
|
|
|
203
|
-
digit :
|
|
359
|
+
digit : '0' { result = 0 }
|
|
204
360
|
| positive_digit
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
| D9 { result = 9 }
|
|
215
|
-
|
|
216
|
-
d01_12 : D0 positive_digit { result = val[1] }
|
|
217
|
-
| D1 D0 { result = 10 }
|
|
218
|
-
| D1 D1 { result = 11 }
|
|
219
|
-
| D1 D2 { result = 12 }
|
|
361
|
+
;
|
|
362
|
+
|
|
363
|
+
positive_digit : '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
|
|
364
|
+
|
|
365
|
+
d01_12 : '0' positive_digit { result = val[1] }
|
|
366
|
+
| '1' '0' { result = 10 }
|
|
367
|
+
| '1' '1' { result = 11 }
|
|
368
|
+
| '1' '2' { result = 12 }
|
|
369
|
+
;
|
|
220
370
|
|
|
221
371
|
d01_13 : d01_12
|
|
222
|
-
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
|
227
|
-
|
|
|
228
|
-
|
|
|
229
|
-
|
|
|
230
|
-
|
|
231
|
-
|
|
372
|
+
| '1' '3' { result = 13 }
|
|
373
|
+
;
|
|
374
|
+
|
|
375
|
+
d01_23 : '0' positive_digit { result = val[1] }
|
|
376
|
+
| '1' digit { result = 10 + val[1] }
|
|
377
|
+
| '2' '0' { result = 20 }
|
|
378
|
+
| '2' '1' { result = 21 }
|
|
379
|
+
| '2' '2' { result = 22 }
|
|
380
|
+
| '2' '3' { result = 23 }
|
|
381
|
+
;
|
|
382
|
+
|
|
383
|
+
d00_23 : '0' '0'
|
|
232
384
|
| d01_23
|
|
385
|
+
;
|
|
233
386
|
|
|
234
387
|
d01_29 : d01_23
|
|
235
|
-
|
|
|
236
|
-
|
|
|
237
|
-
|
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
388
|
+
| '2' '4' { result = 24 }
|
|
389
|
+
| '2' '5' { result = 25 }
|
|
390
|
+
| '2' '6' { result = 26 }
|
|
391
|
+
| '2' '7' { result = 27 }
|
|
392
|
+
| '2' '8' { result = 28 }
|
|
393
|
+
| '2' '9' { result = 29 }
|
|
394
|
+
;
|
|
241
395
|
|
|
242
396
|
d01_30 : d01_29
|
|
243
|
-
|
|
|
397
|
+
| '3' '0' { result = 30 }
|
|
398
|
+
;
|
|
244
399
|
|
|
245
400
|
d01_31 : d01_30
|
|
246
|
-
|
|
|
247
|
-
|
|
401
|
+
| '3' '1' { result = 31 }
|
|
402
|
+
;
|
|
403
|
+
|
|
248
404
|
d01_59 : d01_29
|
|
249
|
-
|
|
|
250
|
-
|
|
|
251
|
-
|
|
|
252
|
-
|
|
253
|
-
|
|
405
|
+
| '3' digit { result = 30 + val[1] }
|
|
406
|
+
| '4' digit { result = 40 + val[1] }
|
|
407
|
+
| '5' digit { result = 50 + val[1] }
|
|
408
|
+
;
|
|
409
|
+
|
|
410
|
+
d00_59 : '0' '0'
|
|
254
411
|
| d01_59
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
412
|
+
;
|
|
413
|
+
|
|
414
|
+
int1_4 : positive_digit { result = val[0] }
|
|
415
|
+
| positive_digit digit { result = 10 * val[0] + val[1] }
|
|
416
|
+
| positive_digit digit digit
|
|
417
|
+
{
|
|
418
|
+
result = val.zip([100,10,1]).reduce(0) { |s,(a,b)| s += a * b }
|
|
419
|
+
}
|
|
420
|
+
| positive_digit digit digit digit
|
|
421
|
+
{
|
|
422
|
+
result = val.zip([1000,100,10,1]).reduce(0) { |s,(a,b)| s += a * b }
|
|
423
|
+
}
|
|
424
|
+
;
|
|
260
425
|
|
|
261
426
|
integer : positive_digit { result = val[0] }
|
|
262
|
-
|
|
427
|
+
| integer digit { result = 10 * val[0] + val[1] }
|
|
428
|
+
;
|
|
263
429
|
|
|
264
430
|
|
|
265
431
|
|
|
@@ -291,63 +457,78 @@ require 'strscan'
|
|
|
291
457
|
warn "failed to parse extended date time %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect]
|
|
292
458
|
end
|
|
293
459
|
|
|
460
|
+
def apply_uncertainty(date, uncertainty, scope = nil)
|
|
461
|
+
uncertainty.each do |u|
|
|
462
|
+
scope.nil? ? date.send(u) : date.send(u, scope)
|
|
463
|
+
end
|
|
464
|
+
date
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
alias uoa apply_uncertainty
|
|
468
|
+
|
|
294
469
|
def next_token
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
470
|
+
case
|
|
471
|
+
when @src.eos?
|
|
472
|
+
nil
|
|
473
|
+
# when @src.scan(/\s+/)
|
|
474
|
+
# ignore whitespace
|
|
475
|
+
when @src.scan(/\(/)
|
|
476
|
+
['(', @src.matched]
|
|
477
|
+
when @src.scan(/\)\?~-/)
|
|
478
|
+
[:IUA, [:uncertain!, :approximate!]]
|
|
479
|
+
when @src.scan(/\)\?-/)
|
|
480
|
+
[:IUA, [:uncertain!]]
|
|
481
|
+
when @src.scan(/\)~-/)
|
|
482
|
+
[:IUA, [:approximate!]]
|
|
483
|
+
when @src.scan(/\)/)
|
|
484
|
+
[')', @src.matched]
|
|
485
|
+
when @src.scan(/\[/)
|
|
486
|
+
['[', @src.matched]
|
|
487
|
+
when @src.scan(/\]/)
|
|
488
|
+
[']', @src.matched]
|
|
489
|
+
when @src.scan(/\{/)
|
|
490
|
+
['{', @src.matched]
|
|
491
|
+
when @src.scan(/\}/)
|
|
492
|
+
['}', @src.matched]
|
|
493
|
+
when @src.scan(/T/)
|
|
494
|
+
[:T, @src.matched]
|
|
495
|
+
when @src.scan(/Z/)
|
|
496
|
+
[:Z, @src.matched]
|
|
497
|
+
when @src.scan(/\?/)
|
|
498
|
+
['?', [:uncertain!]]
|
|
499
|
+
when @src.scan(/~/)
|
|
500
|
+
['~', [:approximate!]]
|
|
501
|
+
when @src.scan(/open/i)
|
|
502
|
+
[:OPEN, :open]
|
|
503
|
+
when @src.scan(/unkn?own/i) # matches 'unkown' typo too
|
|
504
|
+
[:UNKNOWN, :unknown]
|
|
505
|
+
when @src.scan(/u/)
|
|
506
|
+
[:U, @src.matched]
|
|
507
|
+
when @src.scan(/x/i)
|
|
508
|
+
[:X, @src.matched]
|
|
509
|
+
when @src.scan(/y/)
|
|
510
|
+
[:LONGYEAR, @src.matched]
|
|
511
|
+
when @src.scan(/e/)
|
|
512
|
+
[:E, @src.matched]
|
|
513
|
+
when @src.scan(/\+/)
|
|
514
|
+
['+', @src.matched]
|
|
515
|
+
when @src.scan(/-/)
|
|
516
|
+
['-', @src.matched]
|
|
517
|
+
when @src.scan(/:/)
|
|
518
|
+
[':', @src.matched]
|
|
519
|
+
when @src.scan(/\//)
|
|
520
|
+
['/', @src.matched]
|
|
521
|
+
when @src.scan(/\s*\.\.\s*/)
|
|
522
|
+
[:DOTS, '..']
|
|
523
|
+
when @src.scan(/\s*,\s*/)
|
|
524
|
+
[',', ',']
|
|
525
|
+
when @src.scan(/\^\w+/)
|
|
526
|
+
['^', @src.matched[1..-1]]
|
|
527
|
+
when @src.scan(/\d/)
|
|
528
|
+
[@src.matched, @src.matched.to_i]
|
|
529
|
+
else @src.scan(/./)
|
|
530
|
+
[:UNMATCHED, @src.rest]
|
|
531
|
+
end
|
|
351
532
|
end
|
|
352
533
|
|
|
353
534
|
|