Ruby date conversion from 10-Aug-14 to dd/mm/yy - ruby

I'm reading from xls & csv files with the dates that have the following formatting;
10-Aug-14
And I need them to be: dd/mm/yyyy (11/08/2014)
Have tried the date_format gem the standard Ruby Date & Time classes with no luck.
Inspection shows it's an array consisting of a Date object & a String;
p date_start #=> #<Date: -4712-01-01 ((0j,0s,0n),+0s,2299161j)> "11-Aug-14"
puts date_start #=> -4712-01-01
#=> 11-Aug-14
puts date_start.class #=> Array
puts date_start[0].class #=> Date
puts date_start[1].class #=> String
Any idea how I can parse this into a date that Ruby understands.
Also I need to get the weekdays in numbers between two dates so getting this right is key.

For parse date:
my_date = Date.strptime("10-Aug-14 ", "%d-%b-%y")
To the other format(dd/mm/yy):
puts my_date.strftime("%d/%m/%Y")
For weekdays count you can use 'weekdays gem' --> https://github.com/mdarby/weekdays

Related

converting a hash string into a date object ruby

I created a hash out of file that contains date as a string in different formats (like September 1988, the other line would be July 11th 1960, and sometimes year only)
require 'date'
def create_book_hash(book_array)
{
link: book_array[0],
title: book_array[1],
author: book_array[2],
pages: book_array[3].to_i,
date: book_array[4],
rating: book_array[5].to_f,
genre: book_array[6]
}
end
def books_sorted_by_date (books_array)
books_array.sort_by { |key| Date.strptime(key[:date], '%Y, %m') }
end
book_file= File.read("books.txt")
.split("\n")
.map { |line| line.split("|")}
.map { |book_array| create_book_hash(book_array)}
puts books_sorted_by_date(book_file)
I'm trying to sort books by date, so it would be in ascending order by year and since I have different string types, i put a hash key as the first argument in strptime to access all the values in :date . And that gives me \strptime': invalid date (Date::Error).` I don't understand why and what can I do to convert these strings into date objects? (just ruby, no rails)
Handle Both Standard and Custom Date Strings
Date#parse doesn't handle arbitrary strings in all cases. Even when it does, it may not handle them the way you expect. For example:
parse_date "1/1/18"
#=> #<Date: 2001-01-18 ((2451928j,0s,0n),+0s,2299161j)>
While Date#parse handles many date formats automagically, it only successfully parses objects that match its internal expectations. When you have multiple or arbitrary date formats, you have to define your own date specifications using Date#strptime to handle those formats that Date#parse doesn't understand, or that it handles incorrectly. For example:
require 'date'
def parse_date str
Date.parse str
rescue Date::Error
case str
when /\A\d{4}\z/
Date.strptime str, '%Y'
when /\A\d{2}\z/
Date.strptime str, '%y'
else
raise "unexpected date format: #{str}"
end
end
date_samples = ["July 11th 1960", "September 1988", "1776"]
date_samples.map { |date| parse_date(date) }
#=> [#<Date: 1960-07-11 ((2437127j,0s,0n),+0s,2299161j)>, #<Date: 1988-09-01 ((2447406j,0s,0n),+0s,2299161j)>, #<Date: 1776-01-01 ((2369731j,0s,0n),+0s,2299161j)>]
This obviously is not an exhaustive list of potential formats, but you can add more examples to date_samples and update the case statement to include any unambiguous date formats you expect from your data set.
Date.strptime needs two parameters date-string and format of the date. To use strptime you need to know what is the format of the string beforehand.
see some examples here - https://apidock.com/ruby/Date/strptime/class
In your program you don't know exact format of the date on that line when it parses so you need to try something like -
def books_sorted_by_date (books_array)
books_array.sort_by { |key| Date.parse(key[:date]) }
end
Date.parse needs one argument - date string, it then tries to guess the date.
see details - https://apidock.com/ruby/v2_6_3/Date/parse/class
You will still have problems with just year with this approach.

ruby Date.month with a leading zero

I have a Date object in Ruby.
When I do myobj.month I get 8. How do I get the date's month with a leading zero such as 08.
Same idea with day.
What I am trying to get at the end is 2015/08/05.
There is the possibility of using a formated string output
Examples:
puts sprintf('%02i', 8)
puts '%02i' % 8
%02i is the format for 2 digits width integer (number) with leading zeros.
Details can be found in the documentation for sprintf
In your specific case with a date, you can just use the Time#strftime od Date#strftime method:
require 'time'
puts Time.new(2015,8,1).strftime("%m")

Extract Date from string ruby

I have this string :
Rep. Barletta, Lou [R-PA-11] (Introduced 06/04/2015)
And I want to extract the date which is "06/04/2015". How do i do this in ruby?
I have tried to do something like this:
str[-1..-11]
but didnt work. Any suggestion? Thanks!
str = "Rep. Barletta, Lou [R-PA-11] (Introduced 06/04/2015)"
str.match(/(\d{2}\/\d{2}\/\d{4})/)[0]
#=> "06/04/2015"
This code matches anything that's in the format of 2 numbers/2 numbers/4 numbers and returns it.
If there's a possibility of having XX/XX/XXXX somewhere else in the string, I'd probably use the following code instead:
str = "Rep. Barletta, Lou [R-PA-11] (Introduced 06/04/2015)"
str.match(\(Introduced (\d{2}\/\d{2}\/\d{4})\)$)[0]
#=> "06/04/2015"
This searches for (Introduced XX/XX/XXXX) and grabs the date from that in particular.
Date has a parse method, which happens to just work.
require 'date'
str = "Rep. Barletta, Lou [R-PA-11] (Introduced 06/04/2015)"
p d = Date.parse(str) # => #<Date: 2015-04-06 ((2457119j,0s,0n),+0s,2299161j)>
str[-11..-2] if the position of the date does not change
I agree with Piccolo's comment. Here is a simple regular expression you can try in irb. I recommend experimenting in irb to learn some rudimentary Ruby regular expressions.
For example, /.+([0-9]{2}\/[0-9]{2}\/[0-9]{4}).+/ looks for anything followed by two digits, slash, two digits, slash, four digits, then anything:
$ irb
2.2.0 :001 > s='Rep. Barletta, Lou [R-PA-11] (Introduced 06/04/2015)'
2.2.0 :009 > /.+([0-9]{2}\/[0-9]{2}\/[0-9]{4}).+/ =~ s && $1
=> "06/04/2015"
2.2.0 :010 >
#steenslag's answer looks for valid dates (unlike the other answers), but could still be tripped up:
str = "The first 10 may go 15/15/2015 with Lou (Introduced 06/04/2015)"
Date.parse(str)
#=> #<Date: 2015-05-10 ((2457153j,0s,0n),+0s,2299161j)>
To ensure the date is in the specified format, you could do the following:
require 'date'
def extract_date(str, fmt)
a = str.each_char
.each_cons(10)
.find { |a| Date.strptime(a.join, fmt) rescue nil }
a ? a.join : nil
end
For str as above:
extract_date(str, '%d/%m/%Y')
#=> "06/04/2015"
A second example:
extract_date("15/15/2015", '%d/%m/%Y')
#=> nil

Parse Date string in Ruby

I have a String 20120119 which represents a date in the format 'YYYYMMDD'.
I want to parse this string into a Ruby object that represents a Date so that I can do some basic date calculation, such as diff against today's date.
I am using version 1.8.6 (requirement).
You could use the Date.strptime method provided in Ruby's Standard Library:
require 'date'
string = "20120723"
date = Date.strptime(string,"%Y%m%d")
Alternately, as suggested in the comments, you could use Date.parse, because the heuristics work correctly in this case:
require 'date'
string = "20120723"
date = Date.parse(string)
Both will raise an ArgumentError if the date is not valid:
require 'date'
Date.strptime('2012-March', '%Y-%m')
#=> ArgumentError: invalid date
Date.parse('2012-Foo') # Note that '2012-March' would actually work here
#=> ArgumentError: invalid date
If you also want to represent hours, minutes, and so on, you should look at DateTime. DateTime also provides a parse method which works like the parse method on Date. The same goes for strptime.

How do I use the Time class on hash values?

I am working through Chris Pine's Ruby book, and I am slightly confused why my code doesn't quite work.
I have a file called birthdays.txt which has around 10 lines of text which resembles:
Andy Rogers, 1987, 02, 03
etc.
My code as follows:
hash = {}
File.open('birthdays.txt', "r+").each_line do |line|
name, date = line.chomp.split( /, */, 2 )
hash[name] = date
end
puts 'whose birthday would you like to know?'
name = gets.chomp
puts hash[name]
puts Time.local(hash[name])
My question is, why does the last line of code, Time.local(hash[name]) produce this output?:
1987-01-01 00:00:00 +0000
instead of:
1987-02-03 00:00:00 +0000
If you look at the documentation for Time.local,
Time.local doesn't parse a string. It expects you to pass a separate parameter for year, month, and date. When you pass a string like "1987, 02, 03", it takes that to be a single parameter, the year. It then tries to coerce that string into an integer - in this case, 1982.
so, basically, you want to slice up that string into the year, month, and day. there's multiple ways to do this. Here's one (it can be made shorter, but this is the most clear way)
year, month, date = date.split(/, */).map {|x| x.to_i}
Time.local(year, month, date)
line = "Andy Rogers, 1987, 02, 03\n"
name, date = line.chomp.split( /, */, 2 ) #split (', ', 2) is less complex.
#(Skipping the hash stuff; it's fine)
p date #=> "1987, 02, 03"
# Time class can't handle one string, it wants: "1987", "02", "03"
# so:
year, month, day = date.split(', ')
p Time.local(year, month, day)
# or do it all at once (google "ruby splat operator"):
p Time.local(*date.split(', '))
hash = {}
File.open('birthdays.txt').each_line do |line|
line = line.chomp
name, date = line.split(',',2)
year, month, day = date.split(/, */).map {|x| x.to_i}
hash[name] = Time.local(year, month, day)
end
puts 'Whose birthday and age do you want to find out?'
name = gets.chomp
if hash[name] == nil
puts ' Ummmmmmmm, dont know that one'
else
age_secs = Time.new - hash[name]
age_in_years = (age_secs/60/60/24/365 + 1)
t = hash[name]
t.strftime("%m/%d/%y")
puts "#{name}, will be, #{age_in_years.to_i} on #{t.strftime("%m/%d/")}"
end
had to move the Time.local call earlier in the program and then bingo, cheers guys!

Resources