Nokogiri parsing a datetime - ruby-on-rails

I am doing a scraping in a website and get stucked on this:
inside_doc.css('.listing-header-container').at_css("h3 time").to_s
=> "<time datetime=\"2018-08-10T16:49:03Z\" data-local=\"time\" data-format=\"%b %e\">Aug 10</time>"
Im trying to get this 'datetime'element to add to my model. In this case I want to get this value:
2018-08-10T16:49:03Z\
In my model I have a attribute called:
#my_model.date_of_publication = 2018-08-10T16:49:03Z\
How can I do this in Nokogiri?

I just found. Just add a #datetime to the parsing
inside_doc.css('.listing-header-container').at_css("h3 time #datetime").to_s

It should look like this:
dt = page.at('time[datetime]')['datetime']
and then you can parse that with Chronic:
time = Chronic.parse dt

Related

Converting a string into a date Ruby on Rails

I'm attempting to convert a string date into a date that can be stored in the database. These are my attempts:
params[:event][:start_date] = '03-21-2016'
DateTime.strptime(params[:event][:start_date], '%Y-%m-%dT%H:%M:%S%z')
or
DateTime.strptime(params[:event][:start_date], '%m-%d-%Y')
However I keep getting an invalid date error. I'm not sure what I'm doing wrong.
One way to do it would be this:
date_string = '03-21-2016'
month, day, year = date_string.split('-').map(&:to_i)
DateTime.new(year, month, day)
You need to understand what each fragment (eg %Y) in the format string ('%Y-%m-%dT%H:%M:%S%z') means: read this.
http://apidock.com/rails/ActiveSupport/TimeWithZone/strftime
Once you know this, you can tailor a format string to the date string you have, or expect to get: in this case, "%m-%d-%Y".
When debugging create a new, basic and simple, version of the code and test that.
require 'date'
params = '03-21-2016'
DateTime.strptime(params, '%m-%d-%Y') # => #<DateTime: 2016-03-21T00:00:00+00:00 ((2457469j,0s,0n),+0s,2299161j)>
Note the order for the format: '%m-%d-%Y', which works. That's the problem with your first attempt, where you tried to use%Y-%m-%d. There is NO month21or day2016`.
Your second attempt is valid but your question makes it appear it doesn't work. You need to be more careful with your testing:
params = {event:{start_date:'03-21-2016'}}
DateTime.strptime(params[:event][:start_date], '%m-%d-%Y') # => #<DateTime: 2016-03-21T00:00:00+00:00 ((2457469j,0s,0n),+0s,2299161j)>

Rails string to DOB year

I'm currently storing strings formatted like "01/01/1989" (client side validation) for the bday field.
I want to parse out the year and store it as a variable, like this:
#bdayyear = current_user.bday.year
I want that to bring back "1989"
How would I go about doing that?
Just do using #strftime and ::strptime :
s = "01/01/1989"
current_user.bday.strptime(s, "%d/%m/%Y").strftime("%Y")
# => "1989"
Convert it into a DateTime object and you can call year on it
>> DateTime.parse("01/01/1989").year
=> 1989
If the format is always consistent the why not just use the string
"01/01/1989".slice(-4..-1)
"01/01/1989"[-4..-1]
Or
"01/01/1989".split(/\W/).pop
These will all return "1989" without converting it to a date

Call a method from constructed string in Ruby / Rails

I've got a problem in doing some metaprogramming in Ruby / Rails which must be minor, but I can't get the clue.
I wan't to assign values to an active record relation, with my model having attributes:
MyModelClass.p1_id,
.p2_id,
...
.p8_id
SecondModel.position #Integer in (1..8)
I now want to do the following
sms = SecondModel.where(:xyz => 'bla')
sms.each do |sm|
mmc = MyModellClass.first
mmc.#somehow construct method here = sm.id
end
So that somehow this is accomplished
mmc.p1_id = sm.id
mmc.p2_id = sm.id
..
mmc.p8_id = sm.id
To sum up: I want to create that p*n*_id stuff dynamically, but I can't find out, how to tell Ruby, that this should be a method. I tried so far:
mmc.send('p#{sm.position.to_s}_id'.to_sym) = sm.id
But this doesn't work. Any clues?
You were close. Try this:
mmc.send("p#{sm.position.to_s}_id=", sm.id)
Here we call the method with = and pass the value of attribute as the second argument of send

Saving and Querying a Date in GORM Grails

I have a database table TableA, which has a column 'theDate' for which the datatype in the database is DATE.
When I save a java.util.Date to 'theDate' through GORM it appears to save just the date value when I look at the data in the table by just executing select * from TableA.
However, when I run a query such as:
select * from TableA where theDate = :myDate
No results are found, but if I run something like;
select * from TableA where theDate <= :myDate
I do get results.
So it's like the Time is relevant.
My question is how do I save a Date and query for a Date ignoring the Time completely and just matching on an exact Date only?
Thanks.
note: I have also tried using sql.Date and util.Calendar but to no success.
clearTime()
You can use clearTime() before saving and before comparing to zero out the time fields:
// zero the time when saving
new MyDomain(theDate: new Date().clearTime()).save()
// zero the target time before comparing
def now = new Date().clearTime()
MyDomain.findAll('SELECT * FROM MyDomain WHERE theDate = :myDate', [myDate: now])
joda-time plugin
An alternative would be to install the joda-time plugin and use the LocalDate type (which only holds date information, no times) instead of Date. For what it's worth, I don't think I've worked on a project with dates without using the Joda plugin. It's completely worth it.
If you have date saved without clearing you could retrieve it using range, as Jordan H. wrote but in more simple way.
def getResults(Date date) {
def from = date.clearTime()
def to = from + 1
def results = MyDomain.findAll("from MyDomain where dateCreated between :start and :stop" ,[start:from,stop:to])
}
Your question may be a duplicate. See Convert datetime in to date. But if anyone has more recent information, that would be great.
If that doesn't help, you can hack it the way I might, with a BETWEEN restriction, e.g.
def today = new Date()
def ymdFmt = new java.text.SimpleDateFormat("yyyy-MM-dd")
def dateYmd = ymdFmt.format(today)
def dateTimeFormat = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
def startDate = dateTimeFormat.parse("${dateYmd} 00:00:00");
def endDate = dateTimeFormat.parse("${dateYmd} 23:59:59");
MyDomain.findAll("from MyDomain where dateCreated between ? and ?", [startDate, endDate])
It's definitely not pretty, but it may get you where you're going.
I figured it out.
I used DateGroovyMethods.clearTime to clear the time value before saving.
You can use the DB type date not datetime , in the filed type

All day event icalendar gem

I am using the below to setup an event to export to ical with the icalendar gem.
#calendar = Icalendar::Calendar.new
event = Icalendar::Event.new
event.dtstart = ev.start_at.strftime("%Y%m%d")
event.dtend = ev.end_at.strftime("%Y%m%d")
event.summary = ev.summary
#calendar.add
In order to make an event all day it needs to look like this:
DTSTART;VALUE=DATE:20101117
DTEND;VALUE=DATE:20101119
Right now I am using
event.dtstart = "$VALUE=DATE:"+ev.start_at.strftime("%Y%m%d")"
This will output
DTSTART:$VALUE=DATE:20101117
and then I replace all ":$" with ";" with
#allday = #calendar.to_ical.gsub(":$", ";")
Is there a more direct way to save dates as all day?
I played around with this and figured out one way. You can assign properties to the event dates, in the form of key-value pairs. so you could assign the VALUE property like so:
event = Icalendar::Event.new
event.dtstart = Date.new(2010,12,1)
event.dtstart.ical_params = { "VALUE" => "DATE" }
puts event.to_ical
# output
BEGIN:VEVENT
DTSTAMP:20101201T230134
DTSTART;VALUE=DATE:20101201
SEQUENCE:0
UID:2010-12-01T23:01:34-08:00_923426206#ubuntu
END:VEVENT
Now the fun part. Given a calendar you can create an event and pass in a block which initializes the date with its properties:
calendar.event do
dtstart Date.new(2010,11,17), ical_params = {"VALUE"=>"DATE"}
dtend Date.new(2010,11,19), ical_params = {"VALUE"=>"DATE"}
end
So this thread seems quite old (and did not solve the problem with the most recent version of the icalendar gem - 2.3.0). I've recently had to create "all day" calendar events in ics format. I've found this to be a much better solution (and seems to work the way you'd expect calendars to handle it) - see the snippet below
date = Date.new(2010,11,17)
event = Icalendar::Event.new
event.dtstart = Icalendar::Values::Date.new date
event.dtstart.ical_param "VALUE", "DATE"
event.dtend = Icalendar::Values::Date.new (date + 1.day)
event.dtend.ical_param "VALUE", "DATE"
puts event.to_ical
The above code produces the following output:
BEGIN:VEVENT
DTSTAMP:20150521T162712Z
UID:4c239930-15ba-44b4-a045-c6fae3d858d2
DTSTART;VALUE=DATE:20101117
DTEND;VALUE=DATE:20101118
END:VEVENT
Note that the Date does not have a time associated with it. The code in the prior reply currently produces the time. I had to dig into the source code for icalendar to figure out this solution.
I hope this helps someone else.
Cheers!

Resources