Ruby: How to check if a string is a valid time? - ruby-on-rails

I'm pulling data from a feed that I have no control over and I need to verify if a string I'm given is a valid time.
Most of the time I'm correctly sent something like "2:35" or "15:41" but other times it's things like "AM" or "PM" (and no numbers)...so I ultimately just need to ignore those.
So, how can I verify if the data is a valid time?

You haven't exactly specified what you assume to be a valid time (e.g. whether you should accept optional seconds), so here's one guess:
data =~ /^([01]?[0-9]|2[0-3])\:[0-5][0-9]$/

Using Time.parse() is not a good solution, as shown in the example of the comments.
I'll leave the answer here for 'historical reasons', to keep the comments, and as a warning for future readers!
You can use Time.parse() and check for the ArgumentError exception for invalid times.
Extra advantage is that you also have the time in a usable format to work with if it is valid!

Related

Twilio fetch all call logs from last 5 days in ruby

I want to fetch the call logs for the last 5 days, I read on the documentation
You can also specify an inequality, such as EndTime<=YYYY-MM-DD, to read calls that ended on or before midnight of this date
I am trying the following with no luck
#client.calls.list(to: phone_number, end_time: ">=#{Time.now - 5.days}")
Twilio developer evangelist here.
There are several things here, and I need to apologise for at least one of them.
Firstly, the less than/greater than equal that the Twilio API implemented was actually a bit of a hack with the way the parameters are formatted. The parameter as the docs point out is EndTime<=YYYY-MM-DD but this is made of the parameter name EndTime< and the parameter value YYYY-MM-DD separated by =. I apologise that this seemed like a cool hack but actually made things harder.
The Ruby library actually tries to unpick this and make it more sensible again. You can use the parameter end_time_after instead of trying to form the correct end_time format.
Second, I ran the string you were using for the end_time and it produced this:
irb(main):001:0> ">=#{Time.now - 5.days}"
=> ">=2021-02-28 14:35:44 +1100"
So when a time is stringified in Ruby, it doesn't just show up in the YYYY-MM-DD format.
So, to fix your API call, should format the date to YYYY-MM-DD and use end_time_after. Note, since you're using ActiveSupport, you can also call on 5.days.ago instead of Time.now - 5.days.
This should work for you:
#client.calls.list(to: phone_number, end_time_after: "#{5.days.ago.strftime("%Y-%m-%d")}")
Let me know if this helps at all.

How to return untranslated keys

For an API, I want to return the actual keyified string.
So:
User.errors.messages[:name]
#=> activerecord.errors.models.user.attrributes.blank
Instead of
Can't be blank
I know I can override this by creating an actual translation, or by setting custom errors in the validates methods in my Models, but I was wondering if there is a lower level, simpler way to make rails return the "keyified" string instead of parsing it through the translation-layers.
I answered some similar questions on SO, but could not find them right now...
I think that this is not possible right now because the ActiveModel::Errors::add method does not store the Key to the message, but just the derived message.
It's also not trivial to reverse get the key from translation files or the like.
I think it would be a valuable addition to rails to actually store the key of the error-message instead of just the message itself.

Parsing a CSV for Database Insertion when Formatted Incorrectly

I recently wrote a mailing platform for one of our employees to use. The system runs great, scales great, and is fun to use. However, it is currently inoperable due to a bug that I can't figure out how to fix (fairly inexperienced developer).
The process goes something like this...
Upload a CSV file to a specific FTP directory.
Go to the import_mailing_list page.
Choose a CSV file within the FTP directory.
Name and describe what the list contains.
Associate file headings with database columns.
Then, the back-end loops over each line of the file, associating the values with a heading, and importing these values into a database.
This all works wonderfully, except in a specific case, when a raw CSV is not correctly formatted. For example...
fname, lname, email
Bob, Schlumberger, bob#bob.com
Bobbette, Schlumberger
Another, Record, goeshere#email.com
As you can see, there is a missing comma on line two. This would cause an error when attempting to pull "valArray[3]" (or valArray[2], in the case of every language but mine).
I am looking for the most efficient solution to keep this error from happening. Perhaps I should check the array length, and compare it to the index we're going to attempt to pull, before pulling it. But to do this for each and every value seems inefficient. Anybody have another idea?
Our stack is ColdFusion 8/9 and MySQL 5.1. This is why I refer to the array index as [3].
There's ArrayIsDefined(array, elementIndex), or ArrayLen(array)
seems inefficient?
You gotta code what you need to code, forget about inefficiency. Get it right before you get it fast (when needed).
I suppose if you are looking for another way of doing this (instead of checking the array length each time, although that really doesn't sound that bad to me), you could wrap each line insert attempt in a try/catch block. If it fails, then stuff the failed row in a buffer (including the line number and error message) that you could then display to the user after the batch has completed, so they could see each of the failed lines and why they failed. This has the advantages of 1) not having to explicitly check the array length each time and 2) catching other errors that you might not have anticipated beforehand (maybe a value is too long for your field, for example).

CAB file API clarification

Since I'm not really seeing any content anywhere that doesn't point back to the original Microsoft documents on this matter, or source code that really doesn't seem to answer the questions I'm having, I thought I might ask a few things here. (Delphi tag is there because that's what my dev environment is on the code I'm making from this)
That said, I had a few questions the API document wasn't answering. First one: fdi_notify messages. What is "my responsibility" is in coding these: fdintCABINET_INFO: fdintPARTIAL_FILE: fdintNEXT_CABINET: fdintENUMERATE: ? I'll illustrate what I mean by an example. For fdintCLOSE_FILE_INFO, "my responsibility" is to Close a file related to handle given me, and set the file's date and time according to the data passed in fdi_notify.
I figure I'm missing something since my code isn't handling extracting spanned CAB files...any thoughts on how to do this?
What you're more than likely running into is that FDICopy only reads the cab you passed in. It will use fdintNEXT_CABINET to get spanned data for any files you extract in response to fdintCOPY_FILE, but it only calls fdintCOPY_FILE for files that start on that first cab.
To get a directory listing for the entire set, you need to call FDICopy in a loop. Every time you get a fdintCABINET_INFO event, save off the psz1 parameter (next cab name). When FDICopy returns, check that. If it's an empty string you're done, if not call FDICopy again with the next cab as the new path.
fdintCABINET_INFO: The only responsibility for this is returning 0 to continue processing. You can use the information provided (the path of the next cabinet, next disk, path name, nad set ID), but you don't need to.
fdintPARTIAL_FILE: Depending on how you're processing your cabs, you can probably ignore this. You'll only see it for the second and later images in a set, and it's to tell you that the particular entry is continued from a previous cab. If you started at the first cab in the set you'll have already seen an fdintCOPY_FILE for the file. If you're processing random .cabs, you won't really be able to use it either, since you won't have the start of the file to extract.
fdintNEXT_CABINET: You can use this to prompt the user for a new directory for the next cabinet, but for simple spanning support just return 0 if the passed in filename is valid or -1 if it isn't. If you return 0 and the cab isn't valid, or is the wrong one, this will get called again. The easiest approach (if you don't request a new disk/directory), is just to check pfdin^.fdie. If it's FDIError_None it's equal the first time being called for the requested cab, so you can return 0. If it's anything else it's already tried to open the requested cab at least once, so you can return -1 as an error.
fdintENUMERATE: I think you can ignore this. It isn't covered in the documentation, and the two cab libraries I've looked at don't use it. It may be a leftover from a previous API version.

JavaMail: how to get new messages comparing with time-stamps

I'm trying to get messages after a certain time-stamp, the way I've coded it was suggested by another programmer in this site:
GregorianCalendar date = new GregorianCalendar();
SearchTerm newer = new ReceivedDateTerm(ComparisonTerm.GT,date.getTime());
Message msgs[] = folder.search(newerThen);
The issue is that I get all the messages since the date, not the specific time. I was wondering if there is some work-around to emulate this. I mean, for an instance, if I want to get all the messages since today in the midday I would get those messages spicifically and not those ones received in today's morning.
Thanks in advance,
EDIT:
A new thought concerning to this: perhaps some date manipulation could do the job. I mean, comparing the minutes in the timestamp and filter programmatically those messages that don't fit the criteria. I know it's not the best way, but it could work.
PS: I'm using IMAP and trying to get mails from gmail, but I guess it should work no matter what the mail-server is.
Unfortunately, no. In this case, the IMAP protocol is being used by the JavaMail classes, and IMAP's SEARCH command takes only dates, not times (see the SINCE and SENTSINCE criteria).
You could use the setTime() method to query for some specific time.
Example:
setTime(timeInMilliseconds)

Resources