date_time_precision 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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