Class: Reckon::DateColumn

Inherits:
Array
  • Object
show all
Defined in:
lib/reckon/date_column.rb

Overview

Handle date columns in csv

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arr = [], options = {}) ⇒ DateColumn

Returns a new instance of DateColumn.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/reckon/date_column.rb', line 10

def initialize(arr = [], options = {})
  # output date format
  @ledger_date_format = options[:ledger_date_format]

  # input date format
  date_format = options[:date_format]
  arr.each do |value|
    if date_format
      begin
        value = Date.strptime(value, date_format)
      # ruby 2.6.0 doesn't have Date::Error, but Date::Error is a subclass of
      # ArgumentError
      rescue ArgumentError
        puts "I'm having trouble parsing '#{value}' with the desired format: #{date_format}"
        exit 1
      end
    else
      value = [$1, $2, $3].join("/") if value =~ /^(\d{4})(\d{2})(\d{2})\d+\[\d+\:GMT\]$/ # chase format
      value = [$3, $2, $1].join("/") if value =~ /^(\d{2})\.(\d{2})\.(\d{4})$/            # german format
      value = [$3, $2, $1].join("/") if value =~ /^(\d{2})\-(\d{2})\-(\d{4})$/            # nordea format
      value = [$1, $2, $3].join("/") if value =~ /^(\d{4})\-(\d{2})\-(\d{2})$/            # yyyy-mm-dd format
      value = [$1, $2, $3].join("/") if value =~ /^(\d{4})(\d{2})(\d{2})/                 # yyyymmdd format

      unless @endian_precedence # Try to detect endian_precedence
        reg_match = value.match(%r{^(\d\d)/(\d\d)/\d\d\d?\d?})
        # If first one is not \d\d/\d\d/\d\d\d?\d set it to default
        if !reg_match
          @endian_precedence = %i[middle little]
        elsif reg_match[1].to_i > 12
          @endian_precedence = [:little]
        elsif reg_match[2].to_i > 12
          @endian_precedence = [:middle]
        end
      end
    end
    push(value)
  end

  # if endian_precedence still nil, raise error
  return if @endian_precedence || date_format

  raise("Unable to determine date format. Please specify using --date-format")
end

Instance Attribute Details

#endian_precedenceObject

Returns the value of attribute endian_precedence.



8
9
10
# File 'lib/reckon/date_column.rb', line 8

def endian_precedence
  @endian_precedence
end

Class Method Details

.likelihood(entry) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/reckon/date_column.rb', line 72

def self.likelihood(entry)
  date_score = 0
  date_score += 10 if entry =~ /\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i
  date_score += 5 if entry =~ /^[\-\/\.\d:\[\]]+$/
  # add points for columns that start with date-like characters -/.\d:[]
  date_score += entry.gsub(/[^\-\/\.\d:\[\]]/, '').length if entry.gsub(
    /[^\-\/\.\d:\[\]]/, ''
  ).length > 3
  date_score -= entry.gsub(/[\-\/\.\d:\[\]]/, '').length
  date_score += 30 if entry =~ /^\d+[:\/\.-]\d+[:\/\.-]\d+([ :]\d+[:\/\.]\d+)?$/
  date_score += 10 if entry =~ /^\d+\[\d+:GMT\]$/i

  # ruby 2.6.0 doesn't have Date::Error, but Date::Error is a subclass of
  # ArgumentError
  #
  # Sometimes DateTime.parse can throw a RangeError
  # See https://github.com/cantino/reckon/issues/126
  begin
    DateTime.parse(entry)
    date_score += 20
  rescue StandardError
    # we don't need do anything here since the column didn't parse as a date
    nil
  end

  date_score
end

Instance Method Details

#for(index) ⇒ Object



54
55
56
57
58
59
60
61
62
63
# File 'lib/reckon/date_column.rb', line 54

def for(index)
  value = at(index)
  guess = Chronic.parse(value, contex: :past,
                               endian_precedence: @endian_precedence)
  if guess.to_i < 953_236_800 && value =~ %r{/}
    guess = Chronic.parse((value.split("/")[0...-1] + [(2000 + value.split("/").last.to_i).to_s]).join("/"), context: :past,
                                                                                                             endian_precedence: @endian_precedence)
  end
  guess&.to_date
end

#pretty_for(index) ⇒ Object



65
66
67
68
69
70
# File 'lib/reckon/date_column.rb', line 65

def pretty_for(index)
  date = self.for(index)
  return "" if date.nil?

  date.strftime(@ledger_date_format || '%Y-%m-%d')
end