Ruby Date.strptime difficulties when parsing 13/Nov/11 - ruby

When parsing a Jira Custom Field containing a date (e.g. 13/Nov/11) I started with this:
elsif custom.customfieldId == "customfield_10282"
#agenda_item.planned_release_date = custom.values.to_s
But the database stores it as 11/13/0011. So I got clever and used this:
elsif custom.customfieldId == "customfield_10282"
#agenda_item.planned_release_date = Date.strptime(custom.values, "%d/%m/%Y")
And now I get:
private method sub!' called for ["15/Nov/11"]:Jira4R::V2::ArrayOf_xsd_string
C:/Ruby187/lib/ruby/1.8/date/format.rb:429:in_strptime_i'
C:/Ruby187/lib/ruby/1.8/date/format.rb:401:in scan'
C:/Ruby187/lib/ruby/1.8/date/format.rb:401:in_strptime_i'
C:/Ruby187/lib/ruby/1.8/date/format.rb:601:in `_strptime'
[truncated the rest of the stack]
What am I missing?

This works:
p Date.strptime('13/Nov/11', "%d/%b/%y")
Your problems:
`%Y is the year with 4 digits (2011). Use %y
%m is the month in digits (11). Use %b instead (Nov)

If I properly understand your issue, try to use this:
Date.strptime('13/Nov/11', "%d/%b/%y") # => 2011-11-13
You have abbreviated month name and there for you should use b format directive. Beside this because your year contains only two last numbers, use y directive.

Related

Creating an array of something by not today's date?

I have two arrays I'm trying to make. The first one is all the "quotes" with a "follow_up_date" that is today's date. My code looks like:
#dailyTasks = Quote.where(:follow_up => 1,:follow_up_date => Date.today())
This works perfectly for me and is not the issue.
My next array is the same concept but all the quotes to be added are quotes with a follow_up_date that is not today's date. Something like this is what I'm looking for:
#upcomingTasks = Quote.where(:follow_up => 1, :follow_up_date => NOT Date.today())
Does anyone know the proper syntax I should be using to add quotes whose date is NOT today's date?
You can use where.not to get that negation:
#upcomingTasks = Quote.where(follow_up: 1).where.not(follow_up_date: Date.today())
You can simply use equality operators
today = Date.today
today == some_other_date
Can also use < and > to check if date is earlier or later than another.
today < some_other_date
If using Date.today, it does not compare the exact time like it would if using Time.now from other time/date related built-ins.

How to correctly swap some characters in string

I have a string that represents a date:
"12.27.1995"
I need to swap the month and the day to get:
"27.12.1995"
I did:
date = "12.27.1995"
month = date[0]+date[1]
day = date[3]+date[4]
date[0] = day[0]
date[1] = day[1]
date[3] = month[0]
date[4] = month[1]
It works good, but looks to bad for me. Is it possible to make it more reliable using less code?
Since your string represents a date, you might want to use a Date object, with strptime to parse the original string and strftime to output it in the desired format:
require 'date'
date = Date.strptime("12.27.1995", "%m.%d.%Y")
puts date.strftime("%d.%m.%Y")
# 27.12.1995
Yes. Perhaps like this:
date = "12.27.1995"
m, d, y = date.split(".")
date = [d, m, y].join(".")
While the answer by #sawa is perfectly valid and should be used here, I would show some technic which is wrong and should not be used here, but might be helpful for anybody to swap two fixed parts of the string:
"12.27.1995".tap { |s| s[0..1], s[3..4] = s[3..4], s[0..1] }
#⇒ "27.12.1995"
Not elegant, but a way using regex captures:
/(\d{1,2})\.(\d{1,2})\.(\d{4})/.match "12.27.1995"
[$2, $1, $3].join('.') #=> "27.12.1995"

Slice the last 4 or otherwise handle this input/output pattern, in Ruby?

print('What is the day and hour (ex., Monday 08AM): ')
appoint = gets.slice[0..-4]
puts(appoint)
is returning this error:
/scope.rb:2:in slice': wrong number of arguments (0 for 1..2) (ArgumentError)
from /scope.rb:2:in'
Also tried slice[appoint.length..-4] and some other things.
From reading other questions, I gathered that this was how such a slice was done. I'm not familiar with the regex pattern. I'd actually like to be able tot return the day of the week, as well, which may mean from -5 back to input or everything up until the space with some kind of regex pattern.
Do you want this ?
appoint = gets.slice(-4,4)
For Monday 08AM it returns:
08AM
You can use slice like this: slice(start, length).
In your case start is -4 and length is 4.
EDIT
Or with only brackets:
appoint = gets[-4..-1]
A string is also an array of characters.
Regex exmaple:
s = "Monday 08AM"
day = /[a-zA-Z]+/
s[day]
=> "Monday"
# \d? to also catch 8AM without 0 at the start
hour = /\d?\d[paPA][mM]/
s[hour]
=> "08AM"
Regex tutorial from Ruby 1.9.3 docs

How to find dates in a csv file using a regular expression and store in an array [using Ruby]?

I have data stored in a csv file that looks like this:
Date,BLOCK,,Wood,Miscellaneous,,Totals,MO
Saturday,4055-RU,4055-AR,4091,1139,1158,,100
11/13/15,C Sort,B,C,iGPS,PECO,,
Starting,758,"3,936",840,0,0,"5,534",
Sorted,656,736,540,162,64,"2,158",
Subtotal 1,"1,414","4,672","1,380",162,64,"7,692",
Shipped,0,"1,152",620,162,64,"1,898",
,"1,414","3,520",860,0,0,"5,794",
Physical,"1,414","3,520",860,0,0,"5,794",
Variance,0,0,0,0,0,0,
Date,BLOCK,,Wood,Miscellaneous,,Totals,MO
Saturday,4055-RU,4055-AR,4091,1139,1158,,100
11/14/15,C Sort,B,C,iGPS,PECO,,
Starting,758,"3,936",840,0,0,"5,534",
Sorted,656,736,540,162,64,"2,158",
Subtotal 1,"1,414","4,672","1,380",162,64,"7,692"
Shipped,0,"1,152",620,162,64,"1,898"
,"1,414","3,520",860,0,0,"5,794"
Physical,"1,414","3,520",860,0,0,"5,794"
Variance,0,0,0,0,0,0
and I need to make an array of all the dates mentioned (in this case, dates = ['11/13/15', '11/14/15'].
I believe it is possible to pull this info out using a regular expression, but I don't really understand how they work/how to go about this. So, how can I extract the dates?
EDIT: I can sort through the data by row using CSV.foreach, but the trouble I am having is to tell the program to pull out anything that matches a date format (ie. 11/13/15). Does that make more sense of my question?
Thank you!
- Sean
The correct one liner is:
File.open('yourfile.csv').read.scan /\d{2}\/\d{2}\/\d{2}/
and by the way \d{2} is so much nicer than \d\d and here's why:
you can see the 2. \d{2} reads like "2 digit number" (once you're
used to it)
if you want to change it to 1 or 2 digits you can do {1,2}
dates = []
File.open('yourfile.csv').each_line do |line|
if m = line.match(/^\d\d\/\d\d\/\d\d/)
dates.push m
end
end
puts dates
BTW. I am sure someone could write this as a one-liner, but this might be a little easier to understand for someone new to Ruby.
I making these assumptions:
All dates are of the format mm/dd/yy.
All dates that you want in the array are at the start of each line.
You don't need to verify that it is a valid date.
You could get a first approximation with this:
dates = CSV.open('x.csv').map{|r| r.select { |x| x =~ /\d\d\/\d\d\/\d\d/ } }.flatten
and then, if needed, scan through the elements of dates to make sure numbers are in the proper ranges (so that you don't accidentally include a date that claims to be Feb 31 2001). If you want to check the format, you could use DateTime.strptime and catch ArgumentErrors:
clean = dates.select do |d|
begin
# I'm guessing on the date format.
DateTime.strptime(d, '%m/%d/%y')
rescue ArgumentError
nil
end
end

How do you store a string in MongoDB as a Date type using Ruby?

I have a string that I'm parsing out from log files that looks like the following:
"[22/May/2011:23:02:21 +0000]"
What's the best way (examples in Ruby would be most appreciated, as I'm using the Mongo Ruby driver) to get that stashed into MongoDB as a native Date type?
require 'date' # this is just to get the ABBR_MONTHNAMES list
input = "[22/May/2011:23:02:21 +0000]"
# this regex captures the numbers and month name
pattern = %r{^\[(\d{2})/(\w+)/(\d{4}):(\d{2}):(\d{2}):(\d{2}) ([+-]\d{4})\]$}
match = input.match(pattern)
# MatchData can be splatted, which is very convenient
_, date, month_name, year, hour, minute, second, tz_offset = *match
# ABBR_MONTHNAMES contains "Jan", "Feb", etc.
month = Date::ABBR_MONTHNAMES.index(month_name)
# we need to insert a colon in the tz offset, because Time.new expects it
tz = tz_offset[0,3] + ':' + tz_offset[3,5]
# this is your time object, put it into Mongo and it will be saved as a Date
Time.new(year.to_i, month, date.to_i, hour.to_i, minute.to_i, second.to_i, tz)
A few things to note:
I assumed that the month names are the same as in the ABBR_MONTHNAMES list, otherwise, just make your own list.
Never ever use Date.parse to parse dates it is incredibly slow, the same goes for DateTime.parse, Time.parse, which use the same implementation.
If you parse a lot of different date formats check out the home_run gem.
If you do a lot of these (like you often do when parsing log files), consider not using a regex. Use String#index, #[] and #split to extract the parts you need.
If you want to do this as fast as possible, something like the following is probably more appropriate. It doesn't use regexes (which are useful, but not fast):
date = input[1, 2].to_i
month_name = input[4, 3]
month = Date::ABBR_MONTHNAMES.index(month_name)
year = input[8, 4].to_i
hour = input[13, 2].to_i
minute = input[16, 2].to_i
second = input[19, 2].to_i
tz_offset = input[22, 3].to_i * 60 * 60 + input[25, 2].to_i * 60
Time.new(year, month, date, hour, minute, second, tz_offset)
It takes advantage of the fact that all fields have fixed width (at least I assume they do). So all you need to do is extract the substrings. It also calculates the timezone offset as a number instead of a string.

Resources