Factory girl Timestamps issue - ruby-on-rails

I was using the following code to generate 3 mocks:
# today is 27.02
order1 = Factory(:order, :created_at => Date.yesterday) # created_all is 25.02?
order2 = Factory(:order, :quantity => 2, :created_at => Date.today) # created_all is 26.02??
order3 = Factory(:order, :created_at => Date.today) # created_all is 26.02???
In order to have the date set right I use:
order1 = Factory(:order, :created_at => 1.days.ago)
order2 = Factory(:order, :quantity => 2, :created_at => Time.now)
order3 = Factory(:order, :created_at => Time.now)
Any idea what is the diffrence betwen Date.today and Time.now ?
Thank you,

First they are instances of different classes, and represent different info:
Date contains only date information, and Time contains all the date, time, and timezone info
>> Date.today
=> #<Date: 2012-02-27 (4911969/2,0,2299161)>
>> Time.now
=> 2012-02-27 14:14:22 +0200
In your example both Date.today and Time.now will be type-casted to the type you have in db (date or time)
>> Time.now
=> 2012-02-27 14:14:22 +0200
>> Time.now.to_date
=> #<Date: 2012-02-27 (4911969/2,0,2299161)>
>> Time.now.to_date.to_time
=> 2012-02-27 00:00:00 +0200

Related

How to check if variable is Date or Time or DateTime in Ruby?

Any easy way to check if a variable / object is of Date / Time / DateTime type? Without naming all the types
Another option:
def is_datetime(d)
d.methods.include? :strftime
end
Or alternatively:
if d.respond_to?(:strftime)
# d is a Date or DateTime object
end
you can inspect the class of a object doing
object.class
It should return Date, String or whatever it is. You can also do the reverse and check if an object is an instance of a class:
object.instance_of?(class)
where class is the one you want to check (String, Date), returning true/false
If you want to verify the object, here you have a couple of examples:
nisevi#nisevi ~:$ irb
irb(main):001:0> require "date"
=> true
irb(main):002:0> require "time"
=> true
irb(main):003:0> d = Date.new
=> #<Date: -4712-01-01 ((0j,0s,0n),+0s,2299161j)>
irb(main):004:0> dt = DateTime.new
=> #<DateTime: -4712-01-01T00:00:00+00:00 ((0j,0s,0n),+0s,2299161j)>
irb(main):005:0> t = Time.new
=> 2016-06-22 21:33:09 +0200
irb(main):014:0> d.instance_of?(Date)
=> true
irb(main):015:0> d.instance_of?(DateTime)
=> false
irb(main):016:0> d.instance_of?(Time)
=> false
irb(main):017:0> dt.instance_of?(DateTime)
=> true
irb(main):018:0> dt.instance_of?(Time)
=> false
irb(main):019:0> dt.instance_of?(Date)
=> false
irb(main):020:0> t.instance_of?(Time)
=> true
irb(main):021:0> t.instance_of?(DateTime)
=> false
irb(main):022:0> t.instance_of?(Date)
=> false
Also I think that TimeZone is from Rails and not from Ruby.
As per your comment if you want to convert a Time object to DateTime I think that something like this it should work:
def time_to_datetime time
return time.to_datetime if time.instance_of?(Time)
false
end
Here you have some code:
irb(main):026:0> t.instance_of?(Time)
=> true
irb(main):027:0> t.methods.sort.to_s
=> "[:!, :!=, :!~, :+, :-, :<, :<=, :<=>, :==, :===, :=~, :>, :>=, :__id__, :__send__, :asctime, :between?, :class, :clone, :ctime, :day, :define_singleton_method, :display, :dst?, :dup, :enum_for, :eql?, :equal?, :extend, :freeze, :friday?, :frozen?, :getgm, :getlocal, :getutc, :gmt?, :gmt_offset, :gmtime, :gmtoff, :hash, :hour, :httpdate, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_variable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :is_a?, :isdst, :iso8601, :itself, :kind_of?, :localtime, :mday, :method, :methods, :min, :mon, :monday?, :month, :nil?, :nsec, :object_id, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :remove_instance_variable, :respond_to?, :rfc2822, :rfc822, :round, :saturday?, :sec, :send, :singleton_class, :singleton_method, :singleton_methods, :strftime, :subsec, :succ, :sunday?, :taint, :tainted?, :tap, :thursday?, :to_a, :to_date, :to_datetime, :to_enum, :to_f, :to_i, :to_r, :to_s, :to_time, :trust, :tuesday?, :tv_nsec, :tv_sec, :tv_usec, :untaint, :untrust, :untrusted?, :usec, :utc, :utc?, :utc_offset, :wday, :wednesday?, :xmlschema, :yday, :year, :zone]"
irb(main):028:0> t.to_datetime
=> #<DateTime: 2016-06-22T21:33:09+02:00 ((2457562j,70389s,767750206n),+7200s,2299161j)>
irb(main):029:0> t.instance_of?(Time)
=> true
irb(main):030:0> t.instance_of?(DateTime)
=> false
irb(main):031:0> tdt = t.to_datetime
=> #<DateTime: 2016-06-22T21:33:09+02:00 ((2457562j,70389s,767750206n),+7200s,2299161j)>
irb(main):032:0> tdt.instance_of?(Time)
=> false
irb(main):033:0> tdt.instance_of?(DateTime)
=> true
Here you have some interesting info In Ruby on Rails, what's the difference between DateTime, Timestamp, Time and Date?
In rails 5.2+ you can test if an object is_a?
Date.today.is_a?(Date) # -> true
Date.today.is_a?(DateTime) # -> false
I do not think there is an "easy way" without typing all the type variations of Date / Time / DateTime / Timezone out.
The simplest and fastest way is to do dateTime.is_a?(DateTime) or Time.is_a?(Time), repeat ad nausem - which all will return a boolean.
Conversely you can also use kind_of?.
You might also be able to find a framework that has a function to check all of the variations of date and time.
To find what class the module (or method) is located in, you use the .class function, this allows you to inspect Ruby objects to find out what class they are located in. The syntax for this looks like this: object.class. Here's some examples:
irb(main):001:0> require 'date'
=> true
irb(main):002:0> d = Date.today
=> #<Date: 2016-06-22 ((2457562j,0s,0n),+0s,2299161j)>
irb(main):003:0> t = Time.now
=> 2016-06-22 18:52:24 -0500
irb(main):004:0> t.class
=> Time
irb(main):005:0> d.class
=> Date
As you can see this is an easy and simple way to find the class that the object is in.
The Column objects returned by columns and columns_hash can then be used to get information such as the data type and default values, for example:
User.columns_hash['email'].type
=> :string
User.columns_hash['email'].default
=> nil
User.columns_hash['email'].sql_type
=> "varchar(255)"
(Source)
In Rails you can use the acts_like? method. Time does not act_like_date? so you need to check for date and time.
var.acts_like?(:date) || var.acts_like?(:time)
For the sake of completion, another option would be:
def responds_to_datetime?(date)
true if date.to_datetime rescue false
end

Changing of difference between created_at and frozen Time.now after reloading of object

I have spec which checks calculation of difference between Time.now and created_at attribute of object. I stubbed Time.now, so this value is constant. Also I've set Time.now to created_at, but this value changes after reloading of object. How is it possible and how can I freeze created_at after object reloading?
This is an example of issue:
time = Time.now
=> 2015-03-19 15:50:13 UTC
Time.stubs :now => time
=> #<Expectation:0x9938830 allowed any number of times...
user = User.last
=> #<User:0x000000097a6e40...
user.update_attribute :created_at, Time.now - 1.minute
=> true
user.created_at
=> Thu, 19 Mar 2015 15:49:13 UTC +00:00
Time.now - user.created_at
=> 60.0
Time.now - user.reload.created_at
=> 60.442063277
I use rails 4.2.0, ruby 2.2.0 and rspec 2.14.1
Just reset nanoseconds:
time = Time.now.change(nsec: 0)
or milliseconds:
time = Time.now.change(usec: 0)
Here details.

Check if DateTime value is today, tomorrow or later

I have an object attribute of the DateTime class.
How would I understand if the saved date is today, tomorrow or else later?
Here are some useful ways to achieve it:
datetime = DateTime.now => Sun, 26 Oct 2014 21:00:00
datetime.today? # => true
datetime.to_date.past? # => false (only based on date)
datetime.to_date.future? # => false (only based on date)
datetime.to_date == Date.tomorrow # => false
datetime.to_date == Date.yesterday # => false
Something like...
datetime = Time.now.to_datetime
=> Sun, 26 Oct 2014 16:24:55 -0600
datetime >= Date.today
=> true
datetime < Date.tomorrow
=> true
datetime += 1.day
=> Mon, 27 Oct 2014 16:25:12 -0600
datetime >= Date.today
=> true
datetime >= Date.tomorrow
=> true
datetime < (Date.tomorrow + 1.day)
=> false
?
yesterday? & tomorrow? (Rails 6.1+)
Rails 6.1 adds new #yesterday? and #tomorrow? methods to Date and Time classes.
As a result, now, your problem can be solved as:
datetime = DateTime.current
# => Mon, 16 Nov 2020 20:50:16 +0000
datetime.today?
# => true
datetime.yesterday?
# => false
datetime.tomorrow?
# => false
It is also worth to mention that #yesterday? and #tomorrow? are aliased to #prev_day? and #next_day?.
Here is a link to the corresponding PR.

How to validate :created_at in model (RAILS 3)

irb(main):044:0> i1.created_at
=> Thu, 24 Apr 2014 02:41:15 UTC +00:00
irb(main):045:0> i2.created_at
=> Thu, 24 Apr 2014 02:41:15 UTC +00:00
irb(main):046:0> i1.created_at == i2.created_at
=> false
irb(main):047:0> i1.created_at.to_time.to_i == i2.created_at.to_time.to_i
=> true
Seems not to work validates_uniqueness_of :created_at
because
irb(main):046:0> i1.created_at == i2.created_at
=> false
How to validate created_at? Don't want to save with the same date.
+++ UPDATE +++
irb(main):048:0> i1.created_at.class
=> ActiveSupport::TimeWithZone
irb(main):049:0> i2.created_at.class
=> ActiveSupport::TimeWithZone
Since they might have different precision milliseconds.
Refer to the post: Testing ActiveSupport::TimeWithZone objects for equality
Chances are the millisecond values would be unequal.
puts i1.created_at.usec
puts i2.created_at.usec
I think, if you are getting concurrent requests, there are chances that you may have multiple entries in the table which are created at same time and will have same time stamps.
As you said, if you don't want to save with the same date, you can put a lock while saving the entries, removing the possibility of creating two entries at same time. In that case validates_uniqueness_of :created_at should also work.
Just in case
class Item < ActiveRecord::Base
attr_accessible :asin, :domain, :formatted_price, :user_id, :created_at
validate :double_dates
private
def double_dates
if Item.where(:user_id => self.user_id, :asin => self.asin, :domain => self.domain).where("DATE(created_at) = ?", Date.today).length >= 1
errors.add(:created_at, "no double dates")
end
end
end

Wrong boolean result comparing Date objects

I'm trying to write test that compare some dates. So far i have 2 tests, one of them works as intended, but the other one fails because doesnt/not correctly compare dates.
Here is my code:
def self.has_expired?(card, start_month, start_year, annually)
card_date = Date.new(card.year, card.month, -1)
billing_date = Date.new(start_year, start_month, -1)
if !annually
p '--------'
p card_date
p billing_date
card_date > billing_date
else
#return false
end
end
creditcard object
creditcard = ActiveMerchant::Billing::CreditCard.new(
:number => 1234567890123456
:month => 01,
:year => 13,
:first_name => 'John',
:last_name => 'Doe',
:verification_value => 132,
:brand => 'visa'
)
Here is output of p's
First block works as intended.
"--------"
Tue, 31 Jan 0013
Thu, 28 Feb 2013
false
Second block fails, expecting true, but got false
."--------"
Tue, 31 Jan 0013
Fri, 30 Nov 2012
false
Here is my rspec code
describe CreditCard do
context 'card_expired' do
it 'should return false with args passed to method (02month, 13 year, annually==false)' do
CreditCard.has_expired?(creditcard, 02, 2013, false).should == false
end
it 'should return true with args passed to method (11month, 12 year, annually==false)' do
CreditCard.has_expired?(creditcard, 11, 2012, false).should == true
end
end
end
in irb it works as charm, returning correct value(true/false)
I think the problem is in your logic. A card is expired when the expiration date is before the billing date, thus when
card_date < billing_date # expired
and not when
card_date > billing_date # valid
Also try puting in the full 2013 and see if that helps if it keeps breaking
:year => 2013,
You're also missing a comma after this line (probably a copy/paste error) :number => 1234567890123456

Resources