Module: DateNamedFile::DateishHelpers
Overview
Provide some simple and very naïve methods to turn something that might be a date into a date.
Constant Summary collapse
- ALL_DIGITS =
/\A\d+\Z/
- VALID_DELIMITERS =
/[-_ :]/
Instance Method Summary collapse
- #datetime_from_parts(parts) ⇒ Object
- #digit_string?(str) ⇒ Boolean
- #ditch_leading_delimiters(str) ⇒ Object
- #extract_delimited_datetime(str) ⇒ Object
- #extract_from_digitstring(str) ⇒ Object
- #extract_non_year_parts(str) ⇒ Object
- #extract_rest(str) ⇒ Object
-
#extract_undelimited_datetime(digit_string) ⇒ DateTime, FalseClass
An undelimited datetime is a string of digits at least eight digits long (to get YYYYMMDD).
-
#extract_unix_timestamp(digit_string) ⇒ DateTime, FalseClass
Any string that is (a) exactly 10 digits, and (b) starts with ‘1’ will be considered a unix timestamp and treated as such LIMITATION: Only good back to Sept 2001.
- #extract_year(str) ⇒ Object
-
#forgiving_dateify(date_ish) ⇒ DateTime
Attempt to turn big integer (turned into a string of digits), an actual string of digits, or a delimited string of digits (delimited by chars in VALID_DELIMITERS) into a DateTime.
-
#looks_like_unix_timestamp?(digit_string) ⇒ Boolean
Is this plausible a modern unix timestamp? Valid back to 2001.
-
#perform_simple_transforms(str) ⇒ Object
Deal with d/m/yyyy.
- #validate_delimited_datetime!(str) ⇒ Object
- #validate_parts!(parts) ⇒ Object
Instance Method Details
#datetime_from_parts(parts) ⇒ Object
136 137 138 139 140 141 142 143 |
# File 'lib/date_named_file/dateish.rb', line 136 def datetime_from_parts(parts) year = parts[0] non_year_parts = parts[1..-1].map { |dstring| dstring.scan(/\d\d/) }.flatten all_parts = non_year_parts.unshift(year).map(&:to_i) DateTime.new(*all_parts) rescue ArgumentError raise InvalidDateFormat.new("DateTime.new rejected extracted parts ([#{parts.join(',')}]).") end |
#digit_string?(str) ⇒ Boolean
163 164 165 |
# File 'lib/date_named_file/dateish.rb', line 163 def digit_string?(str) ALL_DIGITS.match(str) end |
#ditch_leading_delimiters(str) ⇒ Object
180 181 182 |
# File 'lib/date_named_file/dateish.rb', line 180 def ditch_leading_delimiters(str) str.sub(/\A#{VALID_DELIMITERS}/, '') end |
#extract_delimited_datetime(str) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/date_named_file/dateish.rb', line 110 def extract_delimited_datetime(str) str = perform_simple_transforms(str) validate_delimited_datetime!(str) year = extract_year(str) non_year_parts = extract_non_year_parts(str) all_parts = non_year_parts.unshift(year) datetime_from_parts(all_parts) rescue ArgumentError => e # presumably a DateTime parse error false rescue NonTwoDigitDateParts raise InvalidDateFormat.new("Trying to parse as delimited date. '#{str}' looks to have non-two-digit parts (no zero padding?).") rescue NonDigitsInDelimitedDate raise InvalidDateFormat.new("Trying to parse as delimited date. '#{str}' looks to have non-digits between delimiters.") end |
#extract_from_digitstring(str) ⇒ Object
59 60 61 62 |
# File 'lib/date_named_file/dateish.rb', line 59 def extract_from_digitstring(str) (str) or extract_undelimited_datetime(str) end |
#extract_non_year_parts(str) ⇒ Object
145 146 147 148 149 |
# File 'lib/date_named_file/dateish.rb', line 145 def extract_non_year_parts(str) parts = extract_rest(str).split(VALID_DELIMITERS) validate_parts!(parts) parts end |
#extract_rest(str) ⇒ Object
175 176 177 178 |
# File 'lib/date_named_file/dateish.rb', line 175 def extract_rest(str) everything_after_the_year = str[4..-1] ditch_leading_delimiters(everything_after_the_year) end |
#extract_undelimited_datetime(digit_string) ⇒ DateTime, FalseClass
An undelimited datetime is a string of digits at least eight digits long (to get YYYYMMDD). Anything after that is pulled out into two-digit chunks and sent along to DateTime.new as integers. This means:
-
YYYYMMDD is always necessary; everything after that is optional
-
The rest must be in order: Hour, Minute, Second
-
Everything is assumed to be two digits and zero-padded
Limitations:
-
No support for milliseconds with normal dates. Milliseconds are
parsed but silently thrown out. Because c’mon, really?
77 78 79 80 81 82 83 84 85 |
# File 'lib/date_named_file/dateish.rb', line 77 def extract_undelimited_datetime(digit_string) return false unless digit_string?(digit_string) m = /\A(\d{4})(\d{2})(\d{2})(\d{2})?(\d{2})?(\d{2})?\d*\Z/.match(digit_string) if m datetime_from_parts(m[1..-1].compact) else false end end |
#extract_unix_timestamp(digit_string) ⇒ DateTime, FalseClass
Any string that is (a) exactly 10 digits, and (b) starts with ‘1’ will be considered a unix timestamp and treated as such LIMITATION: Only good back to Sept 2001
92 93 94 95 96 97 98 |
# File 'lib/date_named_file/dateish.rb', line 92 def (digit_string) if (digit_string) DateTime.strptime(digit_string, '%s') else false end end |
#extract_year(str) ⇒ Object
171 172 173 |
# File 'lib/date_named_file/dateish.rb', line 171 def extract_year(str) str[0..3] end |
#forgiving_dateify(date_ish) ⇒ DateTime
Attempt to turn big integer (turned into a string of digits), an actual string of digits, or a delimited string of digits (delimited by chars in VALID_DELIMITERS) into a DateTime.
Should handle:
* Something that response to #to_datetime, which just calls that.
* The symbols :today, :yesterday, and :tomorrow
* unix timestamp (see #extract_unix_timestamp)
* string of digits YYYYMMDD (see #extract_undelimited_datetime)
* delimited string of digits (see #extract_delimited_datetime)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/date_named_file/dateish.rb', line 36 def forgiving_dateify(date_ish) return DateTime.now if date_ish == :today return (DateTime.now - 1) if date_ish == :yesterday return (DateTime.now + 1) if date_ish == :tomorrow if date_ish.respond_to?(:to_i) and date_ish.to_i < 0 return DateTime.now + date_ish.to_i end if date_ish.respond_to? :to_datetime date_ish.to_datetime else str = date_ish.to_s if digit_string?(str) extract_from_digitstring(str) or raise InvalidDateFormat.new("All-digit string '#{str}' doesn't parse as date string or unix timestamp") else extract_delimited_datetime(str) end end rescue InvalidDateFormat => e raise InvalidDateFormat.new("Can't turn '#{date_ish}' into a date-time: #{e.}") end |
#looks_like_unix_timestamp?(digit_string) ⇒ Boolean
Is this plausible a modern unix timestamp? Valid back to 2001
103 104 105 106 107 |
# File 'lib/date_named_file/dateish.rb', line 103 def (digit_string) digit_string?(digit_string) and digit_string.size == 10 and /\A1[0-9]/.match(digit_string[0..1]) end |
#perform_simple_transforms(str) ⇒ Object
Deal with d/m/yyyy
127 128 129 130 131 132 133 134 |
# File 'lib/date_named_file/dateish.rb', line 127 def perform_simple_transforms(str) slash_matcher = %r[(\d{1,2})/(\d{1,2})/(\d{4})] if m = slash_matcher.match(str) '%4d-%02d-%02d' % [m[3], m[1], m[2]] else str end end |
#validate_delimited_datetime!(str) ⇒ Object
167 168 169 |
# File 'lib/date_named_file/dateish.rb', line 167 def validate_delimited_datetime!(str) /\A\d{4}/.match(str) or raise InvalidDateFormat.new("'#{str}' doesn't obviously start with a year") end |
#validate_parts!(parts) ⇒ Object
151 152 153 154 155 156 157 158 159 |
# File 'lib/date_named_file/dateish.rb', line 151 def validate_parts!(parts) unless parts.all? { |p| digit_string?(p) } raise NonDigitsInDelimitedDate.new end unless parts.all? { |p| p.size == 2 } raise NonTwoDigitDateParts.new end end |