carbon_date 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +151 -0
- data/Rakefile +10 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/carbon_date.gemspec +40 -0
- data/lib/carbon_date/date.rb +187 -0
- data/lib/carbon_date/formatter.rb +30 -0
- data/lib/carbon_date/standard_formatter.rb +114 -0
- data/lib/carbon_date/version.rb +3 -0
- data/lib/carbon_date.rb +9 -0
- metadata +233 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ae908e3fff96f810d6da2d667dd5d4bb4b36375f
|
4
|
+
data.tar.gz: 03f87e6676aeefeb7e518b098a3dfa8b45fcff50
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a85737f07ef57b1899fbc2d0edaec40b4d40d44789dc58e01358940d70229f0839ce582a15926f1f00c627475dfeb3de5f9be3336a19bce6554447cd133c0d42
|
7
|
+
data.tar.gz: 9fff56dc1df8ac528547df5b6aa70202704fecdaa985f92e3c8f0bd67576630a5b742773595b8fe3fa918728d92128e0b63b12fe74554dc7c20f146a40604963
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Bradley Marques
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# CarbonDate
|
2
|
+
|
3
|
+
CarbonDate is a Ruby gem that models (pre)historic dates with (im)precision. Dates are modelled according to the [Gregorian Calendar](https://en.wikipedia.org/wiki/Gregorian_calendar), and can have the following precision:
|
4
|
+
|
5
|
+
0. billion_years
|
6
|
+
1. hundred_million_years
|
7
|
+
2. ten_million_years
|
8
|
+
3. million_years
|
9
|
+
4. hundred_thousand_years
|
10
|
+
5. ten_thousand_years
|
11
|
+
6. millennium
|
12
|
+
7. century
|
13
|
+
8. decade
|
14
|
+
9. year
|
15
|
+
10. month
|
16
|
+
11. day
|
17
|
+
12. hour
|
18
|
+
13. minute
|
19
|
+
14. second
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'carbon_date'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
$ bundle
|
33
|
+
```
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
$ gem install carbon_date
|
39
|
+
```
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
## Creation and Formatting
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
CarbonDate::Date.new(2017, 12, 01, 16, 45, 12, precision: :second).to_s
|
47
|
+
=> "16:45:12 1st December, 2017"
|
48
|
+
|
49
|
+
CarbonDate::Date.new(1914, 07, 28, precision: :month).to_s
|
50
|
+
=> "July, 1914"
|
51
|
+
|
52
|
+
CarbonDate::Date.new(1914, 07, 28, precision: :day).to_s
|
53
|
+
=> "28th July, 1914"
|
54
|
+
|
55
|
+
CarbonDate::Date.new(1914, 07, 28, precision: :year).to_s
|
56
|
+
=> "1914"
|
57
|
+
|
58
|
+
CarbonDate::Date.new(1914, 07, 28, precision: :decade).to_s
|
59
|
+
=> "1910s"
|
60
|
+
|
61
|
+
CarbonDate::Date.new(1914, 07, 28, precision: :century).to_s
|
62
|
+
=> "20th century"
|
63
|
+
|
64
|
+
CarbonDate::Date.new(-44, 03, 15, precision: :day).to_s
|
65
|
+
=> "15th March, 44 BCE"
|
66
|
+
|
67
|
+
CarbonDate::Date.new(-4.6e9, precision: :hundred_million_years).to_s
|
68
|
+
=> "4,600,000,000 years ago"
|
69
|
+
|
70
|
+
```
|
71
|
+
|
72
|
+
## Creation from ISO8601 Timestamp with precision
|
73
|
+
|
74
|
+
CarbonDate also supports creation from the ISO8601, with precision, such as the format of dates used on [Wikidata](www.wikidata.org)
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
CarbonDate::Date.iso8601('+0632-06-08T00:00:00Z', 11).to_s
|
78
|
+
=> "8th June, 632"
|
79
|
+
```
|
80
|
+
|
81
|
+
## Conversion to Standard Ruby Objects
|
82
|
+
|
83
|
+
`CarbonDate::Date` objects can be converted to standard Ruby `Date` and `DateTime` objects:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
CarbonDate::Date.new().to_date
|
87
|
+
=> #<Date: 1970-01-01 ((2440588j,0s,0n),+0s,2299161j)>
|
88
|
+
|
89
|
+
CarbonDate::Date.new().to_datetime
|
90
|
+
=> #<DateTime: 1970-01-01T00:00:00+00:00 ((2440588j,0s,0n),+0s,2299161j)>
|
91
|
+
```
|
92
|
+
|
93
|
+
They can also be compared using `==`, `<=` and `>=` operators:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
CarbonDate::Date.new(1970, 1, 1, 0, 0, 0, precision: :second) == CarbonDate::Date.new
|
97
|
+
=> true
|
98
|
+
|
99
|
+
CarbonDate::Date.new(1970, precision: :year) <= CarbonDate::Date.new(2016, precision: :year)
|
100
|
+
=> true
|
101
|
+
|
102
|
+
|
103
|
+
CarbonDate::Date.new(1970, precision: :year) >= CarbonDate::Date.new(2016, precision: :year)
|
104
|
+
=> true
|
105
|
+
|
106
|
+
CarbonDate::Date.new(1970, precision: :year) >= CarbonDate::Date.new(2016, precision: :year)
|
107
|
+
=> false
|
108
|
+
```
|
109
|
+
|
110
|
+
|
111
|
+
## Custom Formatting
|
112
|
+
|
113
|
+
If you don't like the way `to_s` formats the dates, create your own custom formatter:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
class MyCustomFormatter < CarbonDate::Formatter
|
117
|
+
def year(date)
|
118
|
+
# ...
|
119
|
+
end
|
120
|
+
# ...
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
See `standard_formatter.rb` for an example of the functions that will require overriding.
|
125
|
+
|
126
|
+
Then, to use your custom formatter, simply do:
|
127
|
+
```ruby
|
128
|
+
CarbonDate::Date.formatter = MyCustomFormatter.new
|
129
|
+
# All subsequent dates will be formatted using your custom formatter
|
130
|
+
```
|
131
|
+
|
132
|
+
## Contributing
|
133
|
+
|
134
|
+
Please feel free to contribute to this gem:
|
135
|
+
|
136
|
+
+ fork
|
137
|
+
+ create your own branch
|
138
|
+
+ submit pull request
|
139
|
+
|
140
|
+
## License
|
141
|
+
|
142
|
+
The MIT License (MIT)
|
143
|
+
|
144
|
+
Copyright (c) 2016 Bradley Marques
|
145
|
+
|
146
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
147
|
+
|
148
|
+
The above copyright notice and this permission notice shall be included in
|
149
|
+
all copies or substantial portions of the Software.
|
150
|
+
|
151
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
data/carbon_date.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'carbon_date/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "carbon_date"
|
8
|
+
spec.version = CarbonDate::VERSION
|
9
|
+
spec.authors = ["Bradley Marques"]
|
10
|
+
spec.email = ["bradleyrcmarques@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Models (pre)historical dates with (im)precision in Ruby}
|
13
|
+
#spec.description = %q{Models (pre)historical dates with (im)precision in Ruby}
|
14
|
+
spec.homepage = "https://github.com/bradleymarques/carbon_date"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
31
|
+
spec.add_development_dependency 'rake', '>= 11.1.2', '~> 11.1.2'
|
32
|
+
spec.add_development_dependency 'simplecov', '>= 0.11.2', '~> 0.11.2'
|
33
|
+
spec.add_development_dependency 'minitest-display', '>= 0.3.1', '~> 0.3.1'
|
34
|
+
spec.add_development_dependency 'minitest-reporters', '~> 1.1.9', '>= 1.1.9'
|
35
|
+
spec.add_development_dependency 'm', '>= 1.5.0', '~> 1.5.0'
|
36
|
+
spec.add_development_dependency 'pry', '~> 0.10.3', '>= 0.10.3'
|
37
|
+
spec.add_development_dependency 'rdoc', '~> 4.2.2', '>= 4.2.2'
|
38
|
+
|
39
|
+
spec.add_dependency 'activesupport', '~> 4.2.6', '>= 4.2.6'
|
40
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'carbon_date/standard_formatter'
|
3
|
+
|
4
|
+
module CarbonDate
|
5
|
+
|
6
|
+
##
|
7
|
+
# A date with a precision
|
8
|
+
class Date
|
9
|
+
|
10
|
+
@formatter = CarbonDate::StandardFormatter.new
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :formatter
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# The precisions available
|
18
|
+
#
|
19
|
+
# TODO: Consider refactoring into a simple array of symbols, since level could be replaced by the index in the array
|
20
|
+
PRECISION = [
|
21
|
+
{symbol: :second, level: 14},
|
22
|
+
{symbol: :minute, level: 13},
|
23
|
+
{symbol: :hour, level: 12},
|
24
|
+
{symbol: :day, level: 11},
|
25
|
+
{symbol: :month, level: 10},
|
26
|
+
{symbol: :year, level: 9,},
|
27
|
+
{symbol: :decade, level: 8,},
|
28
|
+
{symbol: :century, level: 7,},
|
29
|
+
{symbol: :millennium, level: 6,},
|
30
|
+
{symbol: :ten_thousand_years, level: 5,},
|
31
|
+
{symbol: :hundred_thousand_years, level: 4},
|
32
|
+
{symbol: :million_years, level: 3},
|
33
|
+
{symbol: :ten_million_years, level: 2},
|
34
|
+
{symbol: :hundred_million_years, level: 1},
|
35
|
+
{symbol: :billion_years, level: 0}
|
36
|
+
]
|
37
|
+
|
38
|
+
attr_reader :precision, :year, :month, :day, :hour, :minute, :second
|
39
|
+
|
40
|
+
def initialize(year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0, precision: :second)
|
41
|
+
month = 1 if month == 0
|
42
|
+
day = 1 if day == 0
|
43
|
+
self.precision = precision
|
44
|
+
self.set_date(year, month, day)
|
45
|
+
self.hour = hour
|
46
|
+
self.minute = minute
|
47
|
+
self.second = second
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Sets the precision
|
52
|
+
#
|
53
|
+
# Raises ArgumentError if invalid symbol
|
54
|
+
def precision=(value)
|
55
|
+
p = PRECISION.find { |x| x[:symbol] == value }
|
56
|
+
raise ArgumentError.new "Invalid precision #{value}" unless p
|
57
|
+
@precision = p
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# An atomic function to set the date component.
|
62
|
+
#
|
63
|
+
# Raises ArgumentError if invalid date
|
64
|
+
def set_date(year, month, day)
|
65
|
+
|
66
|
+
raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}") unless (1..12).include? month
|
67
|
+
raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}") if (year.nil? || year == 0)
|
68
|
+
|
69
|
+
begin
|
70
|
+
::Date.new(year, month, day)
|
71
|
+
rescue ArgumentError
|
72
|
+
raise ArgumentError.new("Invalid date #{year}-#{month}-#{day}")
|
73
|
+
end
|
74
|
+
|
75
|
+
@year = year.to_i
|
76
|
+
@month = month
|
77
|
+
@day = day
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Sets the year. Calls set_date() to ensure atomicity.
|
83
|
+
def year=(value)
|
84
|
+
set_date(value, @month, @day)
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Sets the month. Calls set_date() to ensure atomicity.
|
89
|
+
#
|
90
|
+
# Raises ArgumentError if:
|
91
|
+
# - value is not in (1..12)
|
92
|
+
def month=(value)
|
93
|
+
set_date(@year, value, @day)
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Sets the month. Calls set_date() to ensure atomicity.
|
98
|
+
#
|
99
|
+
# Raises ArgumentError if:
|
100
|
+
# - value is not in (1..12)
|
101
|
+
def day=(value)
|
102
|
+
set_date(@year, @month, value)
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Sets the hour with validation
|
107
|
+
#
|
108
|
+
# Raises ArgumentError unless in the range (0..23)
|
109
|
+
def hour=(value)
|
110
|
+
raise ArgumentError.new "Invalid hour #{value}" unless (0..23).include? value
|
111
|
+
@hour = value
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Sets the minute with validation
|
116
|
+
#
|
117
|
+
# Raises ArgumentError unless in the range (0..60)
|
118
|
+
def minute=(value)
|
119
|
+
raise ArgumentError.new "Invalid minute #{value}" unless (0..60).include? value
|
120
|
+
@minute = value
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Sets the second with validation
|
125
|
+
#
|
126
|
+
# Raises ArgumentError unless in the range (0..60)
|
127
|
+
def second=(value)
|
128
|
+
raise ArgumentError.new "Invalid second #{value}" unless (0..60).include? value
|
129
|
+
@second = value
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Converts from an iso8601 datetime format, with precision
|
134
|
+
#
|
135
|
+
# Dates like these are found on Wikidata (https://www.wikidata.org)
|
136
|
+
#
|
137
|
+
# +string+ -> the iso8601 datetime in the form +1989-03-23T23:11:08Z
|
138
|
+
# +precision_level+ -> an integer between 0 and 14 (see CarbonDate::Date::PRECISION)
|
139
|
+
def self.iso8601(string, precision_level)
|
140
|
+
p = PRECISION.find { |p| p[:level] == precision_level}
|
141
|
+
raise ArgumentError.new("Invalid precision level #{precision_level}") unless p
|
142
|
+
# If there is an initial '-' symbol on the year, it needs to be treateded differenty than the other '-'.
|
143
|
+
# Example: -0500-01-01 is the 1st January 500 BCE
|
144
|
+
if string[0] == '-'
|
145
|
+
string = string[1..(string.length - 1)] # Drop the initial '-'
|
146
|
+
bce = true
|
147
|
+
else
|
148
|
+
bce = false
|
149
|
+
end
|
150
|
+
d = string.split('T').map { |x| x.split /[-:]/ }.flatten.map(&:to_i)
|
151
|
+
year = bce ? -d[0] : d[0]
|
152
|
+
CarbonDate::Date.new(year, d[1], d[2], d[3], d[4], d[5], precision: p[:symbol])
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Prints a human-readable version of the date, using a Formatter
|
157
|
+
def to_s
|
158
|
+
CarbonDate::Date.formatter.date_to_string(self)
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Convert to a standard Ruby Date object
|
163
|
+
def to_date
|
164
|
+
::Date.new(@year, @month, @day)
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Convert into a standard Ruby DateTime object
|
169
|
+
def to_datetime
|
170
|
+
::DateTime.new(@year, @month, @day, @hour, @minute, @second)
|
171
|
+
end
|
172
|
+
|
173
|
+
def ==(another_date)
|
174
|
+
return false if self.precision != another_date.precision
|
175
|
+
self.to_datetime == another_date.to_datetime
|
176
|
+
end
|
177
|
+
|
178
|
+
def <=(another_date)
|
179
|
+
self.to_datetime <= another_date.to_datetime
|
180
|
+
end
|
181
|
+
|
182
|
+
def >=(another_date)
|
183
|
+
self.to_datetime >= another_date.to_datetime
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CarbonDate
|
2
|
+
|
3
|
+
##
|
4
|
+
# Responsible for formatting a CarbonDate::Date to a human-readable string
|
5
|
+
class Formatter
|
6
|
+
|
7
|
+
def date_to_string(date)
|
8
|
+
precision = date.precision.fetch(:symbol, nil)
|
9
|
+
case precision
|
10
|
+
when :billion_years then billion_years(date)
|
11
|
+
when :hundred_million_years then hundred_million_years(date)
|
12
|
+
when :ten_million_years then ten_million_years(date)
|
13
|
+
when :million_years then million_years(date)
|
14
|
+
when :hundred_thousand_years then hundred_thousand_years(date)
|
15
|
+
when :ten_thousand_years then ten_thousand_years(date)
|
16
|
+
when :millennium then millennium(date)
|
17
|
+
when :century then century(date)
|
18
|
+
when :decade then decade(date)
|
19
|
+
when :year then year(date)
|
20
|
+
when :month then month(date)
|
21
|
+
when :day then day(date)
|
22
|
+
when :hour then hour(date)
|
23
|
+
when :minute then minute(date)
|
24
|
+
when :second then second(date)
|
25
|
+
else raise StandardError.new("Unrecognized precision: #{precision}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'active_support/core_ext/integer/inflections'
|
2
|
+
require 'carbon_date/formatter'
|
3
|
+
|
4
|
+
module CarbonDate
|
5
|
+
##
|
6
|
+
# The default formatter for CarbonDate::Date
|
7
|
+
class StandardFormatter < Formatter
|
8
|
+
|
9
|
+
##
|
10
|
+
# Suffix to use for Before Common Era dates (quite often BCE or BC)
|
11
|
+
BCE_SUFFIX = 'BCE'
|
12
|
+
|
13
|
+
MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def year(date)
|
18
|
+
y = date.year.abs.to_s
|
19
|
+
return [y, BCE_SUFFIX].join(' ') if (date.year <= -1)
|
20
|
+
y
|
21
|
+
end
|
22
|
+
|
23
|
+
def month(date)
|
24
|
+
[MONTHS[date.month - 1], year(date)].join(', ')
|
25
|
+
end
|
26
|
+
|
27
|
+
def day(date)
|
28
|
+
[date.day.ordinalize.to_s, month(date)].join(' ')
|
29
|
+
end
|
30
|
+
|
31
|
+
def hour(date)
|
32
|
+
h = date.minute >= 30 ? date.hour + 1 : date.hour
|
33
|
+
time = [pad(h.to_s), '00'].join(':')
|
34
|
+
[time, day(date)].join(' ')
|
35
|
+
end
|
36
|
+
|
37
|
+
def minute(date)
|
38
|
+
time = [pad(date.hour.to_s), pad(date.minute.to_s)].join(':')
|
39
|
+
[time, day(date)].join(' ')
|
40
|
+
end
|
41
|
+
|
42
|
+
def second(date)
|
43
|
+
time = [pad(date.hour.to_s), pad(date.minute.to_s), pad(date.second.to_s)].join(':')
|
44
|
+
[time, day(date)].join(' ')
|
45
|
+
end
|
46
|
+
|
47
|
+
def decade(date)
|
48
|
+
d = ((date.year.abs.to_i / 10) * 10).to_s + 's'
|
49
|
+
return [d, BCE_SUFFIX].join(' ') if (date.year <= -1)
|
50
|
+
d
|
51
|
+
end
|
52
|
+
|
53
|
+
def century(date)
|
54
|
+
c = ((date.year.abs.to_i / 100) + 1).ordinalize + ' century'
|
55
|
+
return [c, BCE_SUFFIX].join(' ') if (date.year <= -1)
|
56
|
+
c
|
57
|
+
end
|
58
|
+
|
59
|
+
def millennium(date)
|
60
|
+
m = ((date.year.abs.to_i / 1000) + 1).ordinalize + ' millennium'
|
61
|
+
return [m, BCE_SUFFIX].join(' ') if (date.year <= -1)
|
62
|
+
m
|
63
|
+
end
|
64
|
+
|
65
|
+
def ten_thousand_years(date)
|
66
|
+
coarse_precision(date.year, 10e3.to_i)
|
67
|
+
end
|
68
|
+
|
69
|
+
def hundred_thousand_years(date)
|
70
|
+
coarse_precision(date.year, 100e3.to_i)
|
71
|
+
end
|
72
|
+
|
73
|
+
def million_years(date)
|
74
|
+
coarse_precision(date.year, 1e6.to_i)
|
75
|
+
end
|
76
|
+
|
77
|
+
def ten_million_years(date)
|
78
|
+
coarse_precision(date.year, 10e6.to_i)
|
79
|
+
end
|
80
|
+
|
81
|
+
def hundred_million_years(date)
|
82
|
+
coarse_precision(date.year, 100e6.to_i)
|
83
|
+
end
|
84
|
+
|
85
|
+
def billion_years(date)
|
86
|
+
coarse_precision(date.year, 1e9.to_i)
|
87
|
+
end
|
88
|
+
|
89
|
+
def coarse_precision(date_year, interval)
|
90
|
+
|
91
|
+
date_year = date_year.to_i
|
92
|
+
interval = interval.to_i
|
93
|
+
|
94
|
+
year_diff = date_year - ::Date.today.year
|
95
|
+
return "Within the last #{number_with_delimiter(interval)} years" if (-(interval - 1)..0).include? year_diff
|
96
|
+
return "Within the next #{number_with_delimiter(interval)} years" if (1..(interval - 1)).include? year_diff
|
97
|
+
|
98
|
+
rounded = (year_diff.to_f / interval.to_f).round * interval
|
99
|
+
return "in #{number_with_delimiter(rounded.abs)} years" if rounded > 0
|
100
|
+
return "#{number_with_delimiter(rounded.abs)} years ago" if rounded < 0
|
101
|
+
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def number_with_delimiter(n, delim = ',')
|
106
|
+
n.to_i.to_s.reverse.chars.each_slice(3).map(&:join).join(delim).reverse
|
107
|
+
end
|
108
|
+
|
109
|
+
def pad(s)
|
110
|
+
s.rjust(2, '0')
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
data/lib/carbon_date.rb
ADDED
metadata
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carbon_date
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bradley Marques
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 11.1.2
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 11.1.2
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 11.1.2
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 11.1.2
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: simplecov
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.11.2
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.11.2
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.11.2
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.11.2
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: minitest-display
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.3.1
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.3.1
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.3.1
|
84
|
+
- - "~>"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 0.3.1
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: minitest-reporters
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.1.9
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.1.9
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.1.9
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 1.1.9
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: m
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 1.5.0
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 1.5.0
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.5.0
|
124
|
+
- - "~>"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.5.0
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: pry
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.10.3
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 0.10.3
|
137
|
+
type: :development
|
138
|
+
prerelease: false
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 0.10.3
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 0.10.3
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: rdoc
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 4.2.2
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 4.2.2
|
157
|
+
type: :development
|
158
|
+
prerelease: false
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - "~>"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: 4.2.2
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 4.2.2
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: activesupport
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 4.2.6
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 4.2.6
|
177
|
+
type: :runtime
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - "~>"
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: 4.2.6
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: 4.2.6
|
187
|
+
description:
|
188
|
+
email:
|
189
|
+
- bradleyrcmarques@gmail.com
|
190
|
+
executables: []
|
191
|
+
extensions: []
|
192
|
+
extra_rdoc_files: []
|
193
|
+
files:
|
194
|
+
- ".gitignore"
|
195
|
+
- ".travis.yml"
|
196
|
+
- Gemfile
|
197
|
+
- LICENSE.txt
|
198
|
+
- README.md
|
199
|
+
- Rakefile
|
200
|
+
- bin/console
|
201
|
+
- bin/setup
|
202
|
+
- carbon_date.gemspec
|
203
|
+
- lib/carbon_date.rb
|
204
|
+
- lib/carbon_date/date.rb
|
205
|
+
- lib/carbon_date/formatter.rb
|
206
|
+
- lib/carbon_date/standard_formatter.rb
|
207
|
+
- lib/carbon_date/version.rb
|
208
|
+
homepage: https://github.com/bradleymarques/carbon_date
|
209
|
+
licenses:
|
210
|
+
- MIT
|
211
|
+
metadata:
|
212
|
+
allowed_push_host: https://rubygems.org
|
213
|
+
post_install_message:
|
214
|
+
rdoc_options: []
|
215
|
+
require_paths:
|
216
|
+
- lib
|
217
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
223
|
+
requirements:
|
224
|
+
- - ">="
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
version: '0'
|
227
|
+
requirements: []
|
228
|
+
rubyforge_project:
|
229
|
+
rubygems_version: 2.4.5
|
230
|
+
signing_key:
|
231
|
+
specification_version: 4
|
232
|
+
summary: Models (pre)historical dates with (im)precision in Ruby
|
233
|
+
test_files: []
|