Module: DateTimePrecision

Included in:
Date, DateTime, Time
Defined in:
lib/date_time_precision/lib.rb,
lib/date_time_precision/version.rb,
lib/date_time_precision/format/hash.rb,
lib/date_time_precision/format/json.rb,
lib/date_time_precision/format/iso8601.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

MICROSECONDS_SUPPORTED =
!!Time.now.usec
USEC =
FRAC  = 7
SEC =
6
MIN =
5
HOUR =
4
DAY =
3
MONTH =
2
YEAR =
1
DECADE =
0.5
CENTURY =
0.25
NONE =
0
NEW_DEFAULTS =

Default values for y,m,d,h,m,s,frac

[-4712,1,1,0,0,0,0]
DATE_ATTRIBUTES =
[
  :year,
  :mon,
  :day,
  :hour,
  :min,
  :sec,
  :usec
]
DATE_ATTRIBUTE_PRECISIONS =
{
  :century => CENTURY,
  :decade => DECADE,
  :year => YEAR,
  :mon => MONTH,
  :day => DAY,
  :hour => HOUR,
  :min => MIN,
  :sec => SEC,
  :usec => FRAC
}
PATCH_VERSION =
begin
  if defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx')
    #JRuby and Rubinius implement the Date/Time classes in pure Ruby, so they can use the 1.9.2 patch
    RUBY_VERSION >= '1.9' ? '1.9.2' : '1.8.7'
  elsif RUBY_VERSION > '2'
    # The 1.9.3 patch works in Ruby 2.0.0
    '1.9.3'
  else
    RUBY_VERSION
  end
end
VERSION =
"0.8.0"
ISO8601_DATE_FRAGMENTS =
%w(%0*d %02d %02d)
ISO8601_TIME_FRAGMENTS =
%w(%02d %02d %02d)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/date_time_precision/lib.rb', line 170

def self.included(base)
  # Redefine any conversion methods so precision is preserved
  [:to_date, :to_time, :to_datetime].each do |conversion_method|
    # If the conversion method is already defined, patch it
    orig = :"orig_#{conversion_method}"
    if base.method_defined?(conversion_method) && !base.instance_methods(false).map(&:to_sym).include?(orig)
      base.class_eval do
        alias_method orig, conversion_method
        define_method(conversion_method) do
          d = send(orig)
          d.precision = [self.precision, d.class::MAX_PRECISION].min
          DATE_ATTRIBUTES.each do |attribute|
            d.instance_variable_set(:"@#{attribute}_set", self.instance_variable_get(:"@#{attribute}_set"))
          end
          d
        end
      end
    else
      # Define our own conversion methods by converting to hash first
      require 'date_time_precision/format/hash'
      base.class_eval do
        define_method(conversion_method) do
          to_h.send(conversion_method)
        end
      end
    end

    base.send :public, conversion_method
  end
  
  # Extend with this module's class methods
  base.extend(ClassMethods)
  
  # Define attribute query methods, including:
  # year?, mon?, day?, hour?, min?, sec?, usec?
  DATE_ATTRIBUTE_PRECISIONS.each do |attribute_name, precision|
    #next unless precision <= base::MAX_PRECISION
    
    base.class_eval <<-EOM, __FILE__, __LINE__
      def #{attribute_name}?
        return !@#{attribute_name}_set.nil? ? @#{attribute_name}_set : (self.precision >= #{precision})
      end

      def #{attribute_name}_set=(val)
        @#{attribute_name}_set = !!val
      end
      protected :#{attribute_name}_set=
    EOM
  end

  base.class_eval <<-EOM, __FILE__, __LINE__
    def attributes_set(*vals)
      #{DATE_ATTRIBUTES.map{|attribute| "@#{attribute}_set"}.join(', ')} = *(vals.flatten.map{|v| !!v})
    end
  EOM
  
  base.instance_eval do
    alias_method :month?, :mon?

    alias_method :mday, :day
    alias_method :mday?, :day?
  end
end

.precision(val) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/date_time_precision/lib.rb', line 78

def self.precision(val)
  case val
  when Date,Time,DateTime
    val.precision
  when Hash
    case
    when val[:sec_frac], val[:subsec], val[:usec]
      FRAC
    when val[:sec]
      SEC
    when val[:min]
      MIN
    when val[:hour]
      HOUR
    when val[:mday], val[:day], val[:d]
      DAY
    when val[:mon], val[:month], val[:m]
      MONTH
    when val[:year], val[:y]
      YEAR
    when val[:decade]
      DECADE
    when val[:century]
      CENTURY
    else
      NONE
    end
  when Array
    val.index{|v| v.nil?} || val.length
  else
    NONE
  end
end

Instance Method Details

#as_json(*args) ⇒ Object



20
21
22
# File 'lib/date_time_precision/format/json.rb', line 20

def as_json(*args)
  to_h
end

#centuryObject



138
139
140
141
# File 'lib/date_time_precision/lib.rb', line 138

def century
  year_with_bce_adjustment = (self.year > 0) ? self.year : self.year + 100
  year_with_bce_adjustment - year_with_bce_adjustment % 100
end

#decadeObject



133
134
135
136
# File 'lib/date_time_precision/lib.rb', line 133

def decade
  year_with_bce_adjustment = (self.year > 0) ? self.year : self.year + 10
  (year_with_bce_adjustment - year_with_bce_adjustment % 10)
end

#fragmentsObject



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/date_time_precision/lib.rb', line 112

def fragments
  frags = []
  frags << year if year?
  frags << month if month?
  frags << day if day?
  frags << hour if hour?
  frags << min if min?
  frags << sec if sec?
  frags << usec if usec?
  frags
end

#partial_match?(date2) ⇒ Boolean

Returns true if dates partially match (i.e. one is a partial date of the other)

Returns:

  • (Boolean)


125
126
127
# File 'lib/date_time_precision/lib.rb', line 125

def partial_match?(date2)
  self.class::partial_match?(self, date2)
end

#precisionObject

Returns the precision for this Date/Time object, or the maximum precision if none was specified



69
70
71
72
# File 'lib/date_time_precision/lib.rb', line 69

def precision
  @precision = self.class::MAX_PRECISION unless @precision
  return @precision
end

#precision=(prec) ⇒ Object



74
75
76
# File 'lib/date_time_precision/lib.rb', line 74

def precision=(prec)
  @precision = [prec,self.class::MAX_PRECISION].min
end

#to_h(format = nil) ⇒ Object



39
40
41
42
43
44
45
46
# File 'lib/date_time_precision/format/hash.rb', line 39

def to_h(format = nil)
  keys = Hash::DATE_FORMATS[format || :default]
  
  Hash[keys.each_with_index.map do |key,i|
    attribute_name = Hash::DATE_FORMATS[:ruby][i]
    [key, self.send(attribute_name)] if self.send("#{attribute_name}?")
  end.compact]
end

#to_json(opts = {}) ⇒ Object



24
25
26
# File 'lib/date_time_precision/format/json.rb', line 24

def to_json(opts = {})
  to_h.to_json(opts)
end