Scope to query last year's data - ruby

I've written a scope that returns all objects with a transfer_date from the beginning of the current year to the end of the current year.
scope :year, lambda { where("transfer_date BETWEEN ? AND ?", Time.zone.now.beginning_of_year, Time.zone.now.end_of_year) }
This works well and gives me the objects that I need. But now I'm looking to write a scope that does the same thing but for the previous year. I know there's no method in the Time class for beginning_of_last_year so I'm thinking that it might be better to define a class method instead of a scope.
If I wanted to return all objects with a date between the beginning of last year and the end of last year, what would be the best way to express this in Ruby?
I've written this as a scope but I think it can be cleaner:
scope :previous_year, lambda {where("transfer_date BETWEEN ? AND ?", Time.zone.now.beginning_of_year - 1.year, Time.zone.now.end_of_year - 1.year)}

There are a few optimizations I'd make here.
Since you already have ActiveSupport loaded and you're using it, make use of the ago method, and write something that's a little more flexible. You can also use a range and ActiveRecord can handle writing the appropriate query for your DB, no string substitution needed.
scope :from_year, ->(date) { where(transfer_date: date.beginning_of_year..date.end_of_year) }
# usage
Record.from_year(1.year.ago)
This is a lot less rigid. You can now easily query for records that are from 5 years ago without writing any new code. If you find yourself using last year in a lot of places, make it a convenience method:
def self.last_year
from_year 1.year.ago
end

How about this:
(Time.zone.now - 1.year).beginning_of_year
(Time.zone.now - 1.year).end_of_year

I use this line of code
scope :last_year, lambda {where(transfer_date: 1.year.ago.all_year)}
irb(main):032:0> 1.year.ago.all_year
=> Thu, 01 Jan 2015 00:00:00 UTC +00:00..Thu, 31 Dec 2015 23:59:59 UTC +00:00

Related

how should I test whether a route has params in Sinatra?

In a Sinatra app, I have many routes that use a date. They are all formatted:
get '/foo/:bar/:year/:month' do
# code
end
I want to create a before hook setting a requested date according to the route params. This shouldn't run if the route doesn't have month and year params.
I tried this:
before do
if params[:year].any? && params[:month].any?
#requested_date = Date.new(params[:year].to_i, params[:month].to_i, 01)
end
end
and this:
before do
if defined?(params[:year]) && defined?(params[:month])
#requested_date = Date.new(params[:year].to_i, params[:month].to_i, 01)
end
end
But I keep running into the same error: Date::Error - invalid date:
To reliably check if params hash have year/month keys you can use Hash#key?, smth. like:
before do
if params.key?(:year) && params.key?(:month)
<set date>
end
end
But there is still a problem. The route '/foo/:bar/:year/:month' will match things like /foo/bar/baz/qux with Sinatra router resolving params to { bar: 'bar', year: 'baz', month: 'qux'}.
So you still cannot just feed the params to Date constructor and expect it to give a valid date for you. In simplest case you can just write a helper method like
def build_date(year, month)
Date.new(year.to_i, month.to_i, 01)
rescue Date::Error
# So what now?
end
and use it in your before block, but another question arise - what to do in case of an error? The easiest solution is to just respond with 404, but you might need something more sophisticated (for example, to communicate the invalid date format to the user).
Another thing to mention is Sinatra's capability to match routes using regexps: for example, you could force Sinatra router to recognize only routes that contain 4 digits for year and integers in range 1-12 for month. I'd probably avoid it (makes routes harder to reason about, also accessing the matched params becomes a bit cluttered), but still a good thing to remember about...

Ruby | DateTime

I was working with a ruby script to push stats into a time series kairos db and encountered the 'Datetime' class in ruby.
My question is does DateTime.now differ from DateTime.now()?
And if it does, can I get an example of their outputs?
There is no difference between DateTime.now and DateTime.now(). Parentheses are optional in method calls in Ruby.
You can check some documentation about calling methods in Ruby here.
Example of both calls returning the exactly same result:
(local dev):0> DateTime.now
=> Thu, 14 May 2020 16:52:11 +0100
(local dev):0> DateTime.now()
=> Thu, 14 May 2020 16:52:15 +0100
No differences. They are the same method call. In Ruby, you can call any method with or without parentheses. And there's no "public fields" in Ruby, only public methods, so the only thing you can "dot" is methods.

Does anyone know what TimezoneOffset does on LuisPredictionOptions?

I'm sending LUIS a query that is based on a time value (e.g. "what is the time 10 minutes from now" - just an example). I want the time to come back in the local timezone, so on the LuisPredictionOptions object (C#) I set the TimezoneOffset (as an example I set it to 2 hours ahead, or 120 minutes).
In Fiddler I can see when it calls the LUIS endpoint it's correctly adding "timezoneOffset=120.0".
However, the timezone comes back as UTC - it doesn't matter whether the timezoneOffset is set, or even what it is set to, the time always comes back UTC, using the builtin datetimeV2 entity.
Does anyone know what the TimezoneOffset property is for? Am I just using it incorrectly? Is there another way perhaps to get a local time from LUIS?
[Update]: Here are some examples: https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/[AppId]?verbose=true&timezoneOffset=0&subscription-key=[subscriptionkey]&q=/luis/v2.0/apps/c1be57f4-3850-489e-8266-db376b82c011?timezoneOffset=120&log=true
https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/[AppId]?verbose=true&timezoneOffset=0&subscription-key=[subscriptionkey]&q=/luis/v2.0/apps/c1be57f4-3850-489e-8266-db376b82c011?timezoneOffset=240&log=true
and I'm trying the following example utterance: "in 10 minutes".
When I do this, the timex is in UTC (e.g. timex=2020-01-11T16:08:25) and the "value" comes back with the same value, minus the "T", as follows: value=2020-01-11 16:08:25
I could understand perhaps if the timex is in UTC, but then possibly "value" should be adjusted by the timezoneOffset?
It looks like there's an incorrect question mark in your URL, right before timezoneOffset.
Using the same query I was able to get the expected behavior, where the returned value is different by 10 minutes.
Which SDK are you using? Perhaps you're using the V3 Runtime SDK which uses the V3 endpoint that doesn't use timeZoneOffset but instead uses datetimeReference, and need to use the V2 Runtime SDK instead.
https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/[app-id]?verbose=true&timezoneOffset=10&subscription-key=[key]&q=in 10 minutes
The TimeZoneInfo class's FindSystemTimeZoneById method can be used to determine the correct timezoneOffset based on system time. An example in C# is shown below:
// Get CST zone id
TimeZoneInfo targetZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
// Get local machine's value of Now
DateTime utcDatetime = DateTime.UtcNow;
// Get Central Standard Time value of Now
DateTime cstDatetime = TimeZoneInfo.ConvertTimeFromUtc(utcDatetime, targetZone);
// Find timezoneOffset
int timezoneOffset = (int)((cstDatetime - utcDatetime).TotalMinutes);
Reference:
https://learn.microsoft.com/en-us/azure/cognitive-services/luis/luis-concept-data-alteration?tabs=V2#c-code-determines-correct-value-of-timezoneoffset

Converting a date to string representation

I have a date like this:
Date.today - 7
I tried to convert it into a string:
#last_week = strftime((Date.today - 7), '%Y-%m-%d')
But I get the error "undefined method `strftime'". What am I doing wrong?
You can do it like this:
#last_week = (Date.today - 7).strftime('%Y-%m-%d')
This is what you want, but don't do it.:
module Kernel
def strftime(date, format)
date.strftime(format)
end
end
for the reason, see below comments~~~~~
You are trying to use strftime() as though it was a standalone function. In Ruby, there is no such function. The correct way to do this is to call the method Date#strftime().
Here's an example to format today's date as a string:
Date.today.strftime("%m/%d/%y")
Now that you know how to get a date and format the date to a printable string, you can address your specific code need, which is
#last_week = (Date.today - 7).strftime("%Y-%m-%d")
This will give you the date formatted string "2016-04-28" (or thereabouts, depending on when you run the code).
There is no method as strftime on Kernel (although there is such instance method on Date), but you are trying to call such method.
Addition by #Keith Bennett
You are not calling strftime with an explicit object to receive the method, so the Ruby runtime defaults to calling the method on self, which, in this context, is the top level object, an instance of Object, which inherits from BasicObject and includes the Kernel module. None of these contain a strftime method. However, the Date method does have strftime defined. So you can do what you want to do by calling strftime on the calculated Date instance.

How to check if the object was created within this month

I have a task to find out if an object is created within this month or not. I tried a lot to resolve this. I used 1.month, since(-1), etc. But still I am not on a right track to proceed with these solutions.
I don't think there is a built in way to tell the creation time of an object. You would have to explicitly record the creation time.
class TheClassYouWantToMakeObjects
def initialize
#creation_time = Time.now
...
end
def created_within_same_month?
t = Time.now
t.year == #creation_time.year and t.month == #creation_time.month
end
end
Then, whenever you have object instance of TheClassYouWantToMakeObjects, you can check:
object.created_within_same_month?
Edit:
When you do your request, you compare your creation date with 1.month.since(-1) right?
If so, use instead Time.now.beginning_of_month. Time is a ruby class http://www.ruby-doc.org/core-1.9.3/Time.html
Could you write your request please?
Reedit: Great if it worked. My first explanation was not that explicit, thanks #Andrew.

Resources