date_time_precision 0.1.0 → 0.2.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 CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ **/*.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
@@ -7,4 +7,17 @@ rvm:
7
7
  - 1.9.3
8
8
  #- 2.0.0
9
9
  - jruby-18mode
10
- - jruby-19mode
10
+ - jruby-19mode
11
+ gemfile:
12
+ - gemfiles/activesupport2.gemfile
13
+ - gemfiles/activesupport3.gemfile
14
+ matrix:
15
+ exclude:
16
+ - rvm: 1.9.2
17
+ gemfile: gemfiles/activesupport2.gemfile
18
+ - rvm: 1.9.3
19
+ gemfile: gemfiles/activesupport2.gemfile
20
+ - rvm: jruby-19mode
21
+ gemfile: gemfiles/activesupport2.gemfile
22
+ - rvm: rbx-19mode
23
+ gemfile: gemfiles/activesupport2.gemfile
data/Gemfile CHANGED
@@ -1,10 +1,3 @@
1
1
  source :rubygems
2
2
 
3
- # Specify your gem's dependencies in date_time_precision.gemspec
4
3
  gemspec
5
-
6
- if RUBY_VERSION < '1.9'
7
- gem 'activesupport', '~> 2.3.5'
8
- else
9
- gem 'activesupport', '~> 3'
10
- end
data/README.md CHANGED
@@ -40,6 +40,34 @@ The gem adds the following instance methods to Date, Time, and/or DateTime:
40
40
  * min?
41
41
  * sec?
42
42
 
43
+ ## Formats
44
+
45
+ It is useful to convert the various time classes into other formats that preserve the precision. The currently supported formats are Hash and JSON.
46
+
47
+ Examples:
48
+
49
+ ```ruby
50
+ require 'date_time_precision/format/hash'
51
+
52
+ date = Date.new(2000, 10)
53
+ hash = date.to_h
54
+ => {:year=>2000, :mon=>10}
55
+
56
+ hash.to_date.precision
57
+ => 2
58
+ ```
59
+
60
+ ```ruby
61
+ require 'date_time_precision/format/json'
62
+
63
+ date = Date.new(2000, 10)
64
+ puts json = date.to_json
65
+ => {"year":2000,"mon":10}
66
+
67
+ JSON.parse(json).to_date.precision
68
+ => 2
69
+ ```
70
+
43
71
  ## Compatibility
44
72
 
45
73
  Tested in MRI 1.8.7/1.9.2/1.9.3, REE, JRuby 1.8/1.9, and Rubinius 1.8/1.9.
@@ -64,8 +92,10 @@ Or install it yourself as:
64
92
 
65
93
  ## Wishlist
66
94
 
67
- * Support Time::mktime, Time::utc, Time::local
68
- * Support easy string formatting based on precision
95
+ - [x] Support Time::mktime
96
+ - [ ] Support Time::utc
97
+ - [ ] Support Time::local
98
+ - [ ] Support easy string formatting based on precision
69
99
 
70
100
  ## Contributing
71
101
 
@@ -15,8 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = DateTimePrecision::VERSION
17
17
 
18
- gem.add_development_dependency 'rake', '>= 0.9.2'
19
- gem.add_development_dependency 'rspec', '~> 2.10.0'
20
- #gem.add_development_dependency 'ruby-debug'
21
- #gem.add_development_dependency 'ruby-debug19'
18
+ gem.add_development_dependency 'rake'
19
+ gem.add_development_dependency 'rspec'
20
+ gem.add_development_dependency 'activesupport'
21
+ gem.add_development_dependency 'json'
22
22
  end
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'json'
6
+
7
+ gem 'activesupport', '~> 2', :require => false
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'json'
6
+
7
+ gem 'activesupport', '~> 3', :require => false
@@ -0,0 +1,44 @@
1
+ require 'date_time_precision/lib'
2
+
3
+ class Hash
4
+ DATE_FORMATS = {
5
+ :short => [:y, :m, :d],
6
+ :long => [:year, :month, :day],
7
+ :ruby => [:year, :mon, :mday, :hour, :min, :sec, :sec_frac]
8
+ }
9
+ DATE_FORMATS[:default] = DATE_FORMATS[:ruby]
10
+
11
+ def to_time
12
+ Time.mktime(*date_time_args)
13
+ end
14
+
15
+ def to_datetime
16
+ DateTime.new(*date_time_args.take(DateTime::MAX_PRECISION))
17
+ end
18
+
19
+ def to_date
20
+ Date.new(*date_time_args.take(Date::MAX_PRECISION))
21
+ end
22
+
23
+ protected
24
+ def date_time_args
25
+ [self[:year] || self[:y] || self['year'] || self['y'],
26
+ self[:mon] || self[:m] || self[:month] || self['mon'] || self['m'] || self['month'],
27
+ self[:mday] || self[:d] || self[:day] || self['mday'] || self['d'] || self['day'],
28
+ self[:hour] || self[:h] || self[:hr] || self['hour'] || self['h'] || self['hr'],
29
+ self[:min] || self['min'],
30
+ self[:sec] || self[:s] || self['sec'] || self['s'],
31
+ self[:sec_frac] || self['sec_frac']]
32
+ end
33
+ end
34
+
35
+ module DateTimePrecision
36
+ def to_h(format = nil)
37
+ keys = Hash::DATE_FORMATS[format || :default]
38
+
39
+ Hash[keys.each_with_index.map do |key,i|
40
+ attribute_name = Hash::DATE_FORMATS[:ruby][i]
41
+ [key, self.send(attribute_name)] if self.send("#{attribute_name}?")
42
+ end.compact]
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ require 'date_time_precision/format/hash'
2
+
3
+ if defined?(ActiveSupport)
4
+ require 'active_support/json/encoding'
5
+
6
+ [Date, Time, DateTime].each do |klass|
7
+ klass.class_eval do
8
+ def as_json(*args)
9
+ to_h
10
+ end
11
+
12
+ def to_json(opts = {})
13
+ to_h.to_json(opts)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ module DateTimePrecision
20
+ def as_json(*args)
21
+ to_h
22
+ end
23
+
24
+ def to_json(opts = {})
25
+ to_h.to_json(opts)
26
+ end
27
+ end
@@ -11,6 +11,16 @@ module DateTimePrecision
11
11
 
12
12
  # Default values for y,m,d,h,m,s,frac
13
13
  NEW_DEFAULTS = [-4712,1,1,0,0,0,0]
14
+
15
+ DATE_ATTRIBUTES = {
16
+ :year => YEAR,
17
+ :mon => MONTH,
18
+ :mday => DAY,
19
+ :hour => HOUR,
20
+ :min => MIN,
21
+ :sec => SEC,
22
+ :sec_frac => FRAC
23
+ }
14
24
  end
15
25
 
16
26
  # Returns the precision for this Date/Time object, or the
@@ -30,7 +40,7 @@ module DateTimePrecision
30
40
  val.precision
31
41
  when Hash
32
42
  case
33
- when val[:sec_frac]
43
+ when val[:sec_frac], val[:subsec]
34
44
  FRAC
35
45
  when val[:sec]
36
46
  SEC
@@ -38,9 +48,9 @@ module DateTimePrecision
38
48
  MIN
39
49
  when val[:hour]
40
50
  HOUR
41
- when val[:mday]
51
+ when val[:mday], val[:day]
42
52
  DAY
43
- when val[:mon]
53
+ when val[:mon], val[:month]
44
54
  MONTH
45
55
  when val[:year]
46
56
  YEAR
@@ -54,33 +64,11 @@ module DateTimePrecision
54
64
  end
55
65
  end
56
66
 
57
- def subsec?
58
- return self.precision >= FRAC
59
- end
60
-
61
- def sec?
62
- return self.precision >= SEC
63
- end
64
-
65
- def min?
66
- return self.precision >= MIN
67
- end
68
-
69
- def hour?
70
- return self.precision >= HOUR
71
- end
72
-
73
- def year?
74
- return self.precision >= YEAR
75
- end
76
-
77
- def month?
78
- return self.precision >= MONTH
79
- end
80
- alias_method :mon?, :month?
81
-
82
- def day?
83
- return self.precision >= DAY
67
+ # Define attribute query methods
68
+ DATE_ATTRIBUTES.each do |attribute_name, precision|
69
+ define_method "#{attribute_name}?" do
70
+ return self.precision >= precision
71
+ end
84
72
  end
85
73
 
86
74
  def fragments
@@ -99,6 +87,11 @@ module DateTimePrecision
99
87
  self.class::partial_match?(self, date2)
100
88
  end
101
89
 
90
+ def normalize_new_args(args)
91
+ self.class.normalize_new_args(args)
92
+ end
93
+ protected :normalize_new_args
94
+
102
95
  module ClassMethods
103
96
  def partial_match?(date1, date2)
104
97
  return true if date1.nil? or date2.nil?
@@ -112,6 +105,14 @@ module DateTimePrecision
112
105
  val = val.take(self::MAX_PRECISION) if val.is_a? Array
113
106
  DateTimePrecision::precision(val)
114
107
  end
108
+
109
+ def normalize_new_args(args)
110
+ unless args.all?
111
+ args = args.compact
112
+ args = args.concat(DateTimePrecision::NEW_DEFAULTS.slice(args.length, DateTimePrecision::NEW_DEFAULTS.length - args.length))
113
+ end
114
+ args.take(self::MAX_PRECISION)
115
+ end
115
116
  end
116
117
 
117
118
  def self.included(base)
@@ -132,5 +133,21 @@ module DateTimePrecision
132
133
 
133
134
  # Extend with this module's class methods
134
135
  base.extend(ClassMethods)
136
+
137
+ base.instance_eval do
138
+ if method_defined?(:usec)
139
+ alias_method :usec?, :sec_frac?
140
+ alias_method :sec_frac, :usec
141
+ end
142
+
143
+ if method_defined?(:subsec)
144
+ alias_method :subsec?, :sec_frac?
145
+ end
146
+
147
+ alias_method :month?, :mon?
148
+
149
+ alias_method :mday, :day
150
+ alias_method :day?, :mday?
151
+ end
135
152
  end
136
153
  end
@@ -1,4 +1,15 @@
1
1
  require 'date_time_precision/lib'
2
2
 
3
- require 'date_time_precision/patch/nil'
4
- Dir["#{File.dirname(__FILE__)}/patch/#{RUBY_VERSION}/*.rb"].each {|f| require f }
3
+ require 'date_time_precision/format/nil'
4
+
5
+ DateTimePrecision::PATCH_VERSION = begin
6
+ if defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx')
7
+ #JRuby and Rubinius implement the Date/Time classes in pure Ruby, so they can use the 1.9.2 patch
8
+ RUBY_VERSION >= '1.9' ? '1.9.2' : '1.8.7'
9
+ else
10
+ RUBY_VERSION
11
+ end
12
+ end
13
+
14
+
15
+ Dir["#{File.dirname(__FILE__)}/patch/#{DateTimePrecision::PATCH_VERSION}/*.rb"].each {|f| require f }
@@ -6,13 +6,29 @@ class Time
6
6
 
7
7
  MAX_PRECISION = DateTimePrecision::SEC
8
8
 
9
- def self.parse(date, now=self.now)
10
- d = Date._parse(date, false)
11
- year = d[:year]
12
- year = yield(year) if year && block_given?
13
- t = make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
14
- t.precision = DateTimePrecision::precision(d)
15
- t
9
+ class << self
10
+ alias_method :mktime_orig, :mktime
11
+ def mktime(*args)
12
+ time_args = args.shift(Time::MAX_PRECISION)
13
+ precision = self.precision(time_args)
14
+ time_args = normalize_new_args(time_args)
15
+
16
+ t = mktime_orig(*[time_args, args].flatten)
17
+ t.precision = precision
18
+ t
19
+ end
20
+
21
+ alias_method :make_time_orig, :make_time
22
+ def make_time(*args)
23
+ time_args = args.shift(Time::MAX_PRECISION)
24
+ precision = self.precision(time_args)
25
+ time_args = normalize_new_args(time_args)
26
+
27
+ t = make_time_orig(*[time_args, args].flatten)
28
+ t.precision = precision
29
+ t
30
+ end
31
+ private :make_time
16
32
  end
17
33
 
18
34
  #def self.strptime(str='-4712-01-01', fmt='%F', sg=Date::ITALY)
@@ -4,15 +4,31 @@ require 'time'
4
4
  class Time
5
5
  include DateTimePrecision
6
6
 
7
- MAX_PRECISION = DateTimePrecision::SEC
7
+ MAX_PRECISION = DateTimePrecision::FRAC
8
8
 
9
- def self.parse(date, now=self.now)
10
- d = Date._parse(date, false)
11
- year = d[:year]
12
- year = yield(year) if year && block_given?
13
- t = make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
14
- t.precision = DateTimePrecision::precision(d)
15
- t
9
+ class << self
10
+ alias_method :mktime_orig, :mktime
11
+ def mktime(*args)
12
+ time_args = args.shift(Time::MAX_PRECISION)
13
+ precision = self.precision(time_args)
14
+ time_args = normalize_new_args(time_args)
15
+
16
+ t = mktime_orig(*[time_args, args].flatten)
17
+ t.precision = precision
18
+ t
19
+ end
20
+
21
+ alias_method :make_time_orig, :make_time
22
+ def make_time(*args)
23
+ time_args = args.shift(Time::MAX_PRECISION)
24
+ precision = self.precision(time_args)
25
+ time_args = normalize_new_args(time_args)
26
+
27
+ t = make_time_orig(*[time_args, args].flatten)
28
+ t.precision = precision
29
+ t
30
+ end
31
+ private :make_time
16
32
  end
17
33
 
18
34
  #def self.strptime(str='-4712-01-01', fmt='%F', sg=Date::ITALY)
@@ -10,7 +10,8 @@ class Date
10
10
  alias_method :new_orig, :new
11
11
  def new(*args)
12
12
  precision = self.precision(args)
13
- d = new_orig(*args)
13
+
14
+ d = new_orig(*normalize_new_args(args))
14
15
  d.precision= precision
15
16
  d
16
17
  end
@@ -27,13 +28,10 @@ class Date
27
28
 
28
29
  alias_method :civil_orig, :civil
29
30
  def civil(y=nil, m=nil, d=nil, sg=ITALY)
30
- vals = [y,m,d]
31
- precision = self.precision(vals)
32
- unless vals.all?
33
- vals = vals.compact
34
- vals = vals.concat(NEW_DEFAULTS.slice(vals.length, NEW_DEFAULTS.length - vals.length))
35
- end
36
- y,m,d = vals
31
+ args = [y,m,d]
32
+ precision = self.precision(args)
33
+
34
+ y,m,d = normalize_new_args(args)
37
35
 
38
36
  d = civil_orig(y,m,d,sg)
39
37
  d.precision = precision
@@ -10,7 +10,7 @@ class DateTime < Date
10
10
  alias_method :new_orig, :new
11
11
  def new(*args)
12
12
  precision = self.precision(args)
13
- d = new_orig(*args)
13
+ d = new_orig(*normalize_new_args(args))
14
14
  d.precision= precision
15
15
  d
16
16
  end
@@ -26,16 +26,15 @@ class DateTime < Date
26
26
  end
27
27
 
28
28
  alias_method :civil_orig, :civil
29
- def civil(y=nil, m=nil, d=nil, sg=Date::ITALY)
30
- vals = [y,m,d]
29
+ def civil(*args)
30
+ time_args = args.shift(Time::MAX_PRECISION)
31
+ precision = self.precision(time_args)
32
+ time_args = normalize_new_args(time_args)
33
+
34
+ t = civil_org(*[time_args, args].flatten)
31
35
  precision = self.precision(vals)
32
- unless vals.all?
33
- vals = vals.compact
34
- vals = vals.concat(NEW_DEFAULTS.slice(vals.length, NEW_DEFAULTS.length - vals.length))
35
- end
36
- y,m,d = vals
37
36
 
38
- dt = civil_orig(y,m,d,sg)
37
+ dt = civil_orig(*[normalize_new_args(vals) , sg].flatten)
39
38
  dt.precision = precision
40
39
  dt
41
40
  end
@@ -7,10 +7,25 @@ class Time
7
7
  MAX_PRECISION = DateTimePrecision::FRAC
8
8
 
9
9
  class << self
10
+ alias_method :mktime_orig, :mktime
11
+ def mktime(*args)
12
+ time_args = args.shift(Time::MAX_PRECISION)
13
+ precision = self.precision(time_args)
14
+ time_args = normalize_new_args(time_args)
15
+
16
+ t = mktime_orig(*[time_args, args].flatten)
17
+ t.precision = precision
18
+ t
19
+ end
20
+
10
21
  alias_method :make_time_orig, :make_time
11
22
  def make_time(*args)
12
- t = make_time_orig(*args)
13
- t.precision = self.precision(args)
23
+ time_args = args.shift(Time::MAX_PRECISION)
24
+ precision = self.precision(time_args)
25
+ time_args = normalize_new_args(time_args)
26
+
27
+ t = make_time_orig(*[time_args, args].flatten)
28
+ t.precision = precision
14
29
  t
15
30
  end
16
31
  private :make_time
@@ -1,3 +1,3 @@
1
1
  module DateTimePrecision
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,7 +1,17 @@
1
1
  require 'spec_helper'
2
+ require 'json'
2
3
  require 'active_support'
4
+
5
+ require 'active_support/core_ext/date/conversions'
6
+ require 'active_support/core_ext/time/conversions'
7
+ begin
8
+ require 'active_support/core_ext/datetime/conversions'
9
+ rescue LoadError; end
10
+
3
11
  require 'date_time_precision'
4
12
 
13
+ require 'date_time_precision/format/json'
14
+
5
15
  describe DateTimePrecision, 'Conversions' do
6
16
  context 'when converting from Date to Time or DateTime' do
7
17
  it 'should maintain precision' do
@@ -18,4 +28,19 @@ describe DateTimePrecision, 'Conversions' do
18
28
  t.to_datetime.precision.should == DateTime::MAX_PRECISION
19
29
  t.to_date.precision.should == DateTimePrecision::DAY
20
30
  end
31
+
32
+ it 'will convert a date to a hash' do
33
+ date = Date.new(1999, 10)
34
+ date.as_json.should == date.to_h
35
+ end
36
+
37
+ it 'will retain precision when converting to and from JSON' do
38
+ date = Date.new(1999, 10)
39
+ date.precision.should == DateTimePrecision::MONTH
40
+ json = ActiveSupport::JSON.encode(date)
41
+
42
+ date_from_json = ActiveSupport::JSON.decode(json).to_date
43
+ date_from_json.precision.should == date.precision
44
+
45
+ end
21
46
  end
@@ -1,140 +1,296 @@
1
1
  require 'spec_helper'
2
2
  require 'date_time_precision'
3
3
 
4
- describe DateTimePrecision, 'Constructors' do
5
- it 'has no precision for unspecified date' do
6
- d = Date.new
7
- d.precision.should == DateTimePrecision::NONE
8
- d.year?.should be_false
4
+ describe DateTimePrecision do
5
+ context 'Constructors' do
6
+ it 'has no precision for unspecified date' do
7
+ d = Date.new
8
+ d.precision.should == DateTimePrecision::NONE
9
+ d.year?.should be_false
9
10
 
10
- dt = DateTime.new
11
- dt.precision.should == DateTimePrecision::NONE
12
- dt.year?.should be_false
13
- end
11
+ dt = DateTime.new
12
+ dt.precision.should == DateTimePrecision::NONE
13
+ dt.year?.should be_false
14
+ end
14
15
 
15
- it 'has no precision for nil values' do
16
- nil.precision.should == DateTimePrecision::NONE
17
- end
16
+ it 'has no precision for nil values' do
17
+ nil.precision.should == DateTimePrecision::NONE
18
+ end
18
19
 
19
- it 'has year precision when only year is supplied' do
20
- d = Date.new(1982)
21
- d.precision.should == DateTimePrecision::YEAR
22
- d.year?.should be_true
23
- d.month?.should be_false
24
- d.day?.should be_false
25
- end
20
+ it 'has year precision when only year is supplied' do
21
+ d = Date.new(1982)
22
+ d.precision.should == DateTimePrecision::YEAR
23
+ d.year?.should be_true
24
+ d.month?.should be_false
25
+ d.day?.should be_false
26
+ end
26
27
 
27
- it 'has month precision when year and month are supplied' do
28
- d = Date.new(1982, 11)
29
- d.precision.should == DateTimePrecision::MONTH
30
- d.year?.should be_true
31
- d.month?.should be_true
32
- d.day?.should be_false
33
- end
28
+ it 'has month precision when year and month are supplied' do
29
+ d = Date.new(1982, 11)
30
+ d.precision.should == DateTimePrecision::MONTH
31
+ d.year?.should be_true
32
+ d.month?.should be_true
33
+ d.day?.should be_false
34
+ end
34
35
 
35
- it 'has day precision when year, month, and day are passed in' do
36
- dt = DateTime.new(1987,10,19)
37
- dt.precision.should == DateTimePrecision::DAY
38
- dt.year?.should be_true
39
- dt.month?.should be_true
40
- dt.day?.should be_true
41
- dt.hour?.should be_false
42
- end
36
+ it 'should have day precision when year, month, and day are passed in' do
37
+ dt = DateTime.new(1987,10,19)
38
+ dt.precision.should == DateTimePrecision::DAY
39
+ dt.year?.should be_true
40
+ dt.month?.should be_true
41
+ dt.day?.should be_true
42
+ dt.hour?.should be_false
43
+ end
43
44
 
44
- it 'has hour precision' do
45
- dt = DateTime.new(1970, 1, 2, 3)
46
- dt.precision.should == DateTimePrecision::HOUR
47
- dt.year?.should be_true
48
- dt.month?.should be_true
49
- dt.day?.should be_true
50
- dt.hour?.should be_true
51
- dt.min?.should be_false
52
- end
45
+ it 'should have hour precision' do
46
+ dt = DateTime.new(1970, 1, 2, 3)
47
+ dt.precision.should == DateTimePrecision::HOUR
48
+ dt.year?.should be_true
49
+ dt.month?.should be_true
50
+ dt.day?.should be_true
51
+ dt.hour?.should be_true
52
+ dt.min?.should be_false
53
+ end
53
54
 
54
- it 'should have max precision for fully specified dates/times' do
55
- # Time.new is an alias for Time.now
56
- [Time.new, Time.now, DateTime.now, Date.today].each do |t|
57
- t.precision.should == t.class::MAX_PRECISION
55
+ it 'should have max precision for fully specified dates/times' do
56
+ # Time.new is an alias for Time.now
57
+ [Time.new, Time.now, DateTime.now, Date.today].each do |t|
58
+ t.precision.should == t.class::MAX_PRECISION
59
+ end
60
+ end
61
+
62
+ it 'should accept nil values in the constructor' do
63
+ Date.new(nil).precision.should == DateTimePrecision::NONE
64
+ Date.new(2000, nil).precision.should == DateTimePrecision::YEAR
65
+ DateTime.new(2000, 1, nil).precision.should == DateTimePrecision::MONTH
66
+ Time.mktime(2000, 1, 1, nil, nil).precision.should == DateTimePrecision::DAY
58
67
  end
59
68
  end
60
- end
61
69
 
62
- describe DateTimePrecision, 'Parsing' do
63
- it 'should have second/frac precision when parsing a timestamp' do
64
- t = Time::parse('2000-2-3 00:00:00 UTC')
65
- t.precision.should == DateTimePrecision::SEC
66
- t.year.should == 2000
67
- t.month.should == 2
68
- t.day.should == 3
69
- end
70
+ context 'Parsing' do
71
+ it 'should have second/frac precision when parsing a timestamp' do
72
+ t = Time::parse('2000-2-3 00:00:00 UTC')
73
+ t.precision.should == DateTimePrecision::SEC
74
+ t.year.should == 2000
75
+ t.month.should == 2
76
+ t.day.should == 3
77
+ end
70
78
 
71
- it 'should have minute precision when seconds are not in the timestamp' do
72
- dt = DateTime::parse('2000-1-1 00:00 EST') # => Sat, 01 Jan 2000 00:00:00 -0500
73
- dt.precision.should == DateTimePrecision::MIN
74
- dt.year.should == 2000
75
- dt.day.should == 1
76
- end
79
+ it 'should have minute precision when seconds are not in the timestamp' do
80
+ dt = DateTime::parse('2000-1-1 00:00 EST') # => Sat, 01 Jan 2000 00:00:00 -0500
81
+ dt.precision.should == DateTimePrecision::MIN
82
+ dt.year.should == 2000
83
+ dt.day.should == 1
84
+ end
77
85
 
78
- it 'should have day precision wehn parsing into a Date object' do
79
- d = Date::parse('2000-1-1 00:00:00 EST') # => Sat, 01 Jan 2000
80
- d.precision.should == DateTimePrecision::DAY
81
- end
86
+ it 'should have day precision wehn parsing into a Date object' do
87
+ d = Date::parse('2000-1-1 00:00:00 EST') # => Sat, 01 Jan 2000
88
+ d.precision.should == DateTimePrecision::DAY
89
+ end
82
90
 
83
- it 'should have month precision when day is not in the parsed string' do
84
- t = Time::parse('January 2000 UTC').utc # => Sat Jan 01 00:00:00 -0800 2000
85
- t.precision.should == DateTimePrecision::MONTH
86
- t.year.should == 2000
87
- t.month.should == 1
91
+ it 'should have month precision when day is not in the parsed string' do
92
+ t = Time::parse('January 2000 UTC').utc # => Sat Jan 01 00:00:00 -0800 2000
93
+ t.precision.should == DateTimePrecision::MONTH
94
+ t.year.should == 2000
95
+ t.month.should == 1
96
+ end
88
97
  end
89
- end
90
98
 
91
- describe DateTimePrecision, 'strptime' do
92
- it 'should have day precision when day is specified in date string' do
93
- d = Date.strptime('02/09/1968', '%m/%d/%Y')
94
- d.precision.should == DateTimePrecision::DAY
95
- end
99
+ context 'strptime' do
100
+ it 'should have day precision when day is specified in date string' do
101
+ d = Date.strptime('02/09/1968', '%m/%d/%Y')
102
+ d.precision.should == DateTimePrecision::DAY
103
+ end
96
104
 
97
- it 'should have minute precision when extracting down to the minute' do
98
- dt = DateTime.strptime('2011-02-03 15:14:52','%Y-%m-%d %H:%M')
99
- dt.precision.should == DateTimePrecision::MIN
100
- end
105
+ it 'should have minute precision when extracting down to the minute' do
106
+ dt = DateTime.strptime('2011-02-03 15:14:52','%Y-%m-%d %H:%M')
107
+ dt.precision.should == DateTimePrecision::MIN
108
+ end
101
109
 
102
- it 'should have second precision when extracting down to the second' do
103
- t = DateTime.strptime('2011-02-03 15:14:52','%Y-%m-%d %H:%M:%S')
104
- t.precision.should == DateTimePrecision::SEC
110
+ it 'should have second precision when extracting down to the second' do
111
+ t = DateTime.strptime('2011-02-03 15:14:52','%Y-%m-%d %H:%M:%S')
112
+ t.precision.should == DateTimePrecision::SEC
113
+ end
105
114
  end
106
- end
107
115
 
108
- describe DateTimePrecision, 'Addition' do
109
- it 'will default to max precision when adding or subtracting' do
110
- d = Date.new
111
- d.precision.should == DateTimePrecision::NONE
112
- d += 3
113
- d.precision.should == Date::MAX_PRECISION
114
- d -= 2
115
- d.precision.should == Date::MAX_PRECISION
116
+ context 'Addition' do
117
+ it 'should default to max precision when adding or subtracting' do
118
+ d = Date.new
119
+ d.precision.should == DateTimePrecision::NONE
120
+ d += 3
121
+ d.precision.should == Date::MAX_PRECISION
122
+ d -= 2
123
+ d.precision.should == Date::MAX_PRECISION
116
124
 
117
- dt = DateTime.new
118
- dt.precision.should == DateTimePrecision::NONE
119
- dt += 3
120
- dt.precision.should == DateTime::MAX_PRECISION
121
- dt -= 2
122
- dt.precision.should == DateTime::MAX_PRECISION
125
+ dt = DateTime.new
126
+ dt.precision.should == DateTimePrecision::NONE
127
+ dt += 3
128
+ dt.precision.should == DateTime::MAX_PRECISION
129
+ dt -= 2
130
+ dt.precision.should == DateTime::MAX_PRECISION
123
131
 
124
- t = Time::parse('January 2000 UTC').utc
125
- t.precision.should == DateTimePrecision::MONTH
126
- t += 10
127
- t.precision.should == Time::MAX_PRECISION
128
- t -= 8
129
- t.precision.should == Time::MAX_PRECISION
132
+ t = Time::parse('January 2000 UTC').utc
133
+ t.precision.should == DateTimePrecision::MONTH
134
+ t += 10
135
+ t.precision.should == Time::MAX_PRECISION
136
+ t -= 8
137
+ t.precision.should == Time::MAX_PRECISION
138
+ end
130
139
  end
131
- end
132
140
 
133
- describe DateTimePrecision, 'Partial Matching' do
134
- it 'should match when differing only in day precision' do
135
- d1 = Date.new(2001,3,2)
136
- d2 = Date.new(2001,3)
137
- d1.partial_match?(d2).should be_true
138
- d2.partial_match?(d1).should be_true
141
+ context 'Partial Matching' do
142
+ it 'should match when differing only in day precision' do
143
+ d1 = Date.new(2001,3,2)
144
+ d2 = Date.new(2001,3)
145
+ d1.partial_match?(d2).should be_true
146
+ d2.partial_match?(d1).should be_true
147
+ end
148
+ end
149
+
150
+ context 'Formats' do
151
+ let(:date) { Date.new(1989, 3, 11) }
152
+ let(:datetime) { DateTime.new(1989, 3, 11, 8, 30, 15) }
153
+ let(:time) do
154
+ args = [1989, 3, 11, 8, 30, 15]
155
+ args << 1 if Time::MAX_PRECISION == DateTimePrecision::FRAC
156
+ Time.mktime(*args)
157
+ end
158
+
159
+ context 'Hash' do
160
+ require 'date_time_precision/format/hash'
161
+
162
+ let(:date_hash) do
163
+ {
164
+ :year => 1989,
165
+ :mon => 3,
166
+ :mday => 11
167
+ }
168
+ end
169
+
170
+ let(:datetime_hash) do
171
+ {
172
+ :year => 1989,
173
+ :mon => 3,
174
+ :mday => 11,
175
+ :hour => 8,
176
+ :min => 30,
177
+ :sec => 15,
178
+ }
179
+ end
180
+
181
+ let(:time_hash) do
182
+ @time_hash = datetime_hash
183
+ @time_hash.merge!(:sec_frac => 1) if Time::MAX_PRECISION == DateTimePrecision::FRAC
184
+ @time_hash
185
+ end
186
+
187
+ context 'Converting to hash' do
188
+ it 'should convert Date to a hash' do
189
+ date.to_h.should == date_hash
190
+ end
191
+
192
+ it 'should convert DateTime to a hash' do
193
+ datetime.to_h.should == datetime_hash
194
+ end
195
+
196
+ it 'should convert Time to a hash' do
197
+ time.to_h.should == time_hash
198
+ end
199
+ end
200
+
201
+ context 'Converting to hash with format' do
202
+ let(:short_date_hash) do
203
+ {
204
+ :y => 1989,
205
+ :m => 3,
206
+ :d => 11
207
+ }
208
+ end
209
+
210
+ let(:long_date_hash) do
211
+ {
212
+ :year => 1989,
213
+ :month => 3,
214
+ :day => 11
215
+ }
216
+ end
217
+
218
+ it 'should convert Date to a short hash' do
219
+ date.to_h(:short).should == short_date_hash
220
+ end
221
+
222
+ it 'should convert DateTime to a long hash' do
223
+ datetime.to_h(:long).should == long_date_hash
224
+ end
225
+
226
+ it 'should convert Time to a custom hash' do
227
+ Hash::DATE_FORMATS[:custom] = [:year, :mon, :d, :h, :min, :s]
228
+
229
+ time.to_h(:custom).should == {
230
+ :year => 1989,
231
+ :mon => 3,
232
+ :d => 11,
233
+ :h => 8,
234
+ :min => 30,
235
+ :s => 15,
236
+ }
237
+ end
238
+
239
+ it 'should convert to the default hash format' do
240
+ Hash::DATE_FORMATS[:default] = Hash::DATE_FORMATS[:short]
241
+ date.to_h(:short).should == short_date_hash
242
+ Hash::DATE_FORMATS[:default] = Hash::DATE_FORMATS[:ruby]
243
+ end
244
+ end
245
+
246
+ context 'Converting from hash' do
247
+ it 'should convert a hash to a Date' do
248
+ date_hash.to_date.should == date
249
+ end
250
+
251
+ it 'should convert a hash to a DateTime' do
252
+ datetime_hash.to_datetime.should == datetime
253
+ end
254
+
255
+ it 'should convert a hash to a Time' do
256
+ time_hash.to_time.should == time
257
+ end
258
+
259
+ it 'should accept flexible keys' do
260
+ {
261
+ :y => 1989,
262
+ :m => 3,
263
+ :d => 11
264
+ }.to_date.should == date
265
+
266
+ {
267
+ :year => 1989,
268
+ :month => 3,
269
+ :day => 11
270
+ }.to_date.should == date
271
+ end
272
+ end
273
+ end
274
+
275
+ context 'JSON' do
276
+ require 'date_time_precision/format/json'
277
+ require 'json'
278
+
279
+ it 'should convert a date to a JSON hash' do
280
+ date.as_json.should == date.to_h
281
+ date.to_json.should == date.to_h.to_json
282
+ end
283
+
284
+ it 'should convert a datetime to a JSON hash' do
285
+ datetime.as_json.should == datetime.to_h
286
+ datetime.to_json.should == datetime.to_h.to_json
287
+ end
288
+
289
+ it 'should convert a time to a JSON hash' do
290
+ time.as_json.should == time.to_h
291
+ time.to_json.should == time.to_h.to_json
292
+ end
293
+ end
294
+
139
295
  end
140
296
  end
metadata CHANGED
@@ -1,48 +1,80 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: date_time_precision
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.1.0
4
+ version: 0.2.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Butler
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-19 00:00:00.000000000 Z
12
+ date: 2013-02-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- version_requirements: !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
17
18
  requirements:
18
19
  - - ! '>='
19
20
  - !ruby/object:Gem::Version
20
- version: 0.9.2
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
21
25
  none: false
22
- requirement: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
- version: 0.9.2
27
- none: false
28
- prerelease: false
29
- type: :development
29
+ version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rspec
32
- version_requirements: !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
33
34
  requirements:
34
- - - ~>
35
+ - - ! '>='
35
36
  - !ruby/object:Gem::Version
36
- version: 2.10.0
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
37
41
  none: false
38
- requirement: !ruby/object:Gem::Requirement
39
42
  requirements:
40
- - - ~>
43
+ - - ! '>='
41
44
  - !ruby/object:Gem::Version
42
- version: 2.10.0
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
43
49
  none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
44
55
  prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: json
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
45
70
  type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
46
78
  description: Patches Date, Time, and DateTime ruby classes to keep track of precision
47
79
  email:
48
80
  - dwbutler@ucla.edu
@@ -57,11 +89,14 @@ files:
57
89
  - README
58
90
  - README.md
59
91
  - Rakefile
60
- - date.rb
61
- - date_time.rb
62
92
  - date_time_precision.gemspec
63
93
  - gem_tasks/rspec.rake
94
+ - gemfiles/activesupport2.gemfile
95
+ - gemfiles/activesupport3.gemfile
64
96
  - lib/date_time_precision.rb
97
+ - lib/date_time_precision/format/hash.rb
98
+ - lib/date_time_precision/format/json.rb
99
+ - lib/date_time_precision/format/nil.rb
65
100
  - lib/date_time_precision/lib.rb
66
101
  - lib/date_time_precision/patch.rb
67
102
  - lib/date_time_precision/patch/1.8.7/date.rb
@@ -73,36 +108,38 @@ files:
73
108
  - lib/date_time_precision/patch/1.9.3/date.rb
74
109
  - lib/date_time_precision/patch/1.9.3/date_time.rb
75
110
  - lib/date_time_precision/patch/1.9.3/time.rb
76
- - lib/date_time_precision/patch/nil.rb
77
111
  - lib/date_time_precision/version.rb
78
112
  - spec/date_time_precision/active_support_spec.rb
79
113
  - spec/date_time_precision/date_time_precision_spec.rb
80
114
  - spec/spec_helper.rb
81
- - time.rb
82
115
  homepage: http://github.com/Spokeo/date_time_precision
83
116
  licenses: []
84
- post_install_message:
117
+ post_install_message:
85
118
  rdoc_options: []
86
119
  require_paths:
87
120
  - lib
88
121
  required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
89
123
  requirements:
90
124
  - - ! '>='
91
125
  - !ruby/object:Gem::Version
92
- version: !binary |-
93
- MA==
94
- none: false
126
+ version: '0'
127
+ segments:
128
+ - 0
129
+ hash: 3562610931592917135
95
130
  required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
96
132
  requirements:
97
133
  - - ! '>='
98
134
  - !ruby/object:Gem::Version
99
- version: !binary |-
100
- MA==
101
- none: false
135
+ version: '0'
136
+ segments:
137
+ - 0
138
+ hash: 3562610931592917135
102
139
  requirements: []
103
- rubyforge_project:
140
+ rubyforge_project:
104
141
  rubygems_version: 1.8.24
105
- signing_key:
142
+ signing_key:
106
143
  specification_version: 3
107
144
  summary: Patches Date, Time, and DateTime ruby classes to keep track of precision
108
145
  test_files:
data/date.rb DELETED
@@ -1,64 +0,0 @@
1
- require 'date_time_precision/lib'
2
- require 'date'
3
-
4
- class Date
5
- include DateTimePrecision
6
-
7
- MAX_PRECISION = DateTimePrecision::DAY
8
-
9
- def self.parse(str='-4712-01-01T00:00:00+00:00', comp=false, sg=ITALY)
10
- elem = _parse(str, comp)
11
- precision = DateTimePrecision::precision(elem)
12
- d = new_by_frags(elem, sg)
13
- d.precision = precision
14
- d
15
- end
16
-
17
- def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY)
18
- elem = _strptime(str, fmt)
19
- precision = DateTimePrecision::precision(elem)
20
- d = new_by_frags(elem, sg)
21
- d.precision = precision
22
- d
23
- end
24
-
25
- def self.civil(y=nil, m=nil, d=nil, sg=ITALY)
26
- vals = [y,m,d]
27
- precision = DateTimePrecision::precision(vals)
28
- unless vals.all?
29
- vals = vals.compact
30
- vals = vals.concat(NEW_DEFAULTS.slice(vals.length, NEW_DEFAULTS.length - vals.length))
31
- end
32
- y,m,d = vals
33
-
34
- unless jd = (private_methods.include?(:"_valid_civil?") ? _valid_civil?(y, m, d, sg) : valid_civil?(y, m, d, sg))
35
- raise ArgumentError, 'invalid date'
36
- end
37
-
38
- d = new!(jd_to_ajd(jd, 0, 0), 0, sg)
39
- d.precision = precision
40
- d
41
- end
42
-
43
- class << self; alias_method :new, :civil end
44
-
45
- =begin
46
- Following code is unneccessary, but keeping it as an example
47
- # Return the date as a human-readable string.
48
- #
49
- # The format used is YYYY-MM-DD, YYYY-MM, or YYYY.
50
- def to_s
51
- case
52
- when self.precision.nil?, self.precision >= DateTimePrecision::DAY
53
- format('%.4d-%02d-%02d', year, mon, mday)
54
- when self.precision == DateTimePrecision::MONTH
55
- format('%.4d-%02d', year, mon)
56
- when self.precision == DateTimePrecision::YEAR
57
- format('%.4d', year)
58
- else
59
- '?'
60
- end
61
- end
62
- =end
63
-
64
- end
@@ -1,47 +0,0 @@
1
- require 'date_time_precision/lib'
2
- require 'date'
3
-
4
- class DateTime < Date
5
- include DateTimePrecision
6
-
7
- MAX_PRECISION = DateTimePrecision::SEC
8
-
9
- def self.parse(str='-4712-01-01T00:00:00+00:00', comp=false, sg=ITALY)
10
- elem = _parse(str, comp)
11
- precision = DateTimePrecision::precision(elem)
12
- dt = new_by_frags(elem, sg)
13
- dt.precision = precision
14
- dt
15
- end
16
-
17
- def self.civil(y=nil, m=nil, d=nil, h=nil, min=nil, s=nil, of=0, sg=ITALY)
18
- vals = [y,m,d,h,min,s]
19
- precision = DateTimePrecision::precision(vals)
20
- unless vals.all?
21
- vals = vals.compact
22
- vals = vals.concat(NEW_DEFAULTS.slice(vals.length, NEW_DEFAULTS.length - vals.length))
23
- end
24
- y,m,d,h,min,s = vals
25
-
26
- unless (jd = (private_methods.include?(:"_valid_civil?") ? _valid_civil?(y, m, d, sg) : valid_civil?(y, m, d, sg))) &&
27
- (fr = (private_methods.include?(:"_valid_time?") ? _valid_time?(h, min, s) : valid_time?(h, min, s)))
28
- raise ArgumentError, 'invalid date'
29
- end
30
- if String === of
31
- of = Rational(zone_to_diff(of) || 0, 86400)
32
- end
33
- dt = new!(jd_to_ajd(jd, fr, of), of, sg)
34
- dt.precision = precision
35
- dt
36
- end
37
-
38
- class << self; alias_method :new, :civil end
39
-
40
- def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY)
41
- elem = _strptime(str, fmt)
42
- precision = DateTimePrecision::precision(elem)
43
- d = new_by_frags(elem, sg)
44
- d.precision = precision
45
- d
46
- end
47
- end
data/time.rb DELETED
@@ -1,21 +0,0 @@
1
- require 'date_time_precision/lib'
2
- require 'time'
3
-
4
- class Time
5
- include DateTimePrecision
6
-
7
- MAX_PRECISION = DateTimePrecision::SEC
8
-
9
- def self.parse(date, now=self.now)
10
- d = Date._parse(date, false)
11
- year = d[:year]
12
- year = yield(year) if year && block_given?
13
- t = make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
14
- t.precision = DateTimePrecision::precision(d)
15
- t
16
- end
17
-
18
- #def self.strptime(str='-4712-01-01', fmt='%F', sg=Date::ITALY)
19
- # DateTime.strptime(str, fmt, sg).to_time
20
- #end
21
- end