I am using ruby 2.2.6 and rails 4.1.16, with pg as database.
I am getting the PG::UndefinedFunction: ERROR : Operator does not exist. timestamp without time zone > time without time zone.
I know this is due to the comparing of different datatype, so I need to change the dataype from the query itself.
I tried looking around and found this guide but it is for rails 5. and another probable solution is to use cast in the sql query.
My query is:
normal = Staff.joins([department: {profils: :schedule_times}], :time_loggers).where(department: selected_departments, status: 1, schedule_times: {day_state: 1, day: wday}, time_loggers: {daterec: date}).where("time_loggers.timein > schedule_times.bstart")
I tried modifying the query by adding a cast to the sql,the query works but didn't return the intended result.
normal = Staff.joins([department: {profils: :schedule_times}], :time_loggers).where(department: selected_departments, status: 1, schedule_times: {day_state: 1, day: wday}, time_loggers: {daterec: date}).where("cast(time_loggers.timein AS TIME) > schedule_times.bstart")
Thanks in advance
EDIT
Actually the query with cast works and returned results, the problem is actually the datacontent.
If I switch the operator to be < as in
where("cast(time_loggers.timein AS TIME) > schedule_times.bstart") then it gives me some results.
time_loggers.timein is Wed, 05 Jan 2022 09:05:00 +08 +08:00
schedule_times.bstart is 2000-01-01 09:00:00 UTC
Now the problem changed already i guess. I need to change the data content directly in the sql before comparing those data, is it possible? Because I need to avoid using each to iterate then compare, as I have thousand of records so the website will be very slow.
What I want is to get those data in my timezone, GMT+8 then only get the hour and minutes and do the comparing.
Or maybe should I post this as another topic?
I managed to work the query.
normal = Staff.joins([department: {profils: :schedule_times}], :time_loggers).where(department: selected_departments, status: 1, schedule_times: {day_state: 1, day: wday}, time_loggers: {daterec: date}).where("to_char(time_loggers.timein + interval '8 hours', 'HH24:MI' > to_char(schedule_times.bstart, 'HH24:MI')")
I converted both timein and bstart using postgres to_char and added 8 hours into timein match the bstart, as it is in GMT+8 using + interval '8 hours.
Special thanks to jad for giving the appropriate direction, that pg documentation is very helpful.
Related
I have a ROR app: ruby 2.3.0, rails 4.2.5.1 and mongoid 5.0, and in one of my models I have :
field :statement_month, default: 1.month.ago.strftime('%m') , but only on 1st of March it saves a wrong result: "01" instead of "02" .
I have no problems for other months in first day of the month.
I also added some logs, before_create and after_create , printing:
"-------1_month_ago_month------------------------" + 1.month.ago.strftime('%m') => in logs it show "02" but in DB object is "01". It is a mongoid issue, or maybe a TimeZone issue ?
The correct syntax for dynamic defaults uses Procs. See https://docs.mongodb.com/mongoid/master/tutorials/mongoid-documents/#defaults.
MongoDB stores times as UTC timestamps, your program does not explicitly convert to UTC thus it is 1) potentially misbehaving with respect to time zones and 2) potentially misbehaving with respect to daylight savings time. Date math generally must be explicitly performed in either local time (and you should know the time zone you are operating in) or in UTC. Mixing the two eventually causes problems.
To troubleshoot the wrong month, set your system time to March 1 and debug the program. In particular, try March 1 01:00 and March 1 23:00. Those are often different dates in UTC for the same local date.
Say I have an Event model with a date_time field representing the date time the event is held, and I want to see all Events that are held, say, 'after 10pm', or 'before 7am' across multiple dates. How could I do this?
My first thought was something like this:
scope :after_time ->(time){ where("events.date_time::time between ?::time and '23:59'::time", time) }
But this doesn't work because dates are stored in UTC and converted to the app's timezone by ActiveRecord.
So let's say I'm searching for Events after 5pm, from my local Adelaide time. The eventual query is this:
WHERE (events.date_time::time between '2016-10-09 06:30:00.000000'::time and '23:59'::time)
That is, because my timezone is +10:30 (Adelaide time), it's now trying to calculate between 6:30am and midnight, where it really needs to be finding ones created between 6:30am and 1:30pm utc.
Now, for this example in particular I could probably hack something together to work out what the 'midnight' time needs to be given the time zone difference. But the between <given time> and <midnight in Adelaide> calculation isn't going to work if that period spans midnight utc. So that solution is bust.
UPDATE:
I think I've managed to get the result I want by trial and error, but I'm not sure I understand exactly what's going on.
scope :after_time, ->(time) {
time = time.strftime('%H:%M:%S')
where_clause = <<-SQL
(events.date_time at time zone 'UTC' at time zone 'ACDT')::time
between ? and '23:59:59'
SQL
joins(:performances).where(where_clause, time)
}
It's basically turning everything into the one time zone so the query for each row ends up looking something like WHERE '20:30:00' between '17:00:00' and '23:59:59', so I'm not having to worry about times spanning over midnight.
Even still, I feel like there's probably a proper way to do this, so I'm open to suggestions.
Check if this works for you,
s = DateTime.now.change(hour: 6, min: 30).utc
e = Date.today.end_of_day.utc
Event.where("date_time::time between ?::time and ?::time", s, e)
this may help you and then you need not to convert every date of DB, instead you can convert the parameterized timestamp into UTC time:
scope :after, ->(start_time) { where('created_at::time > :time', time: start_time.utc.strftime('%H:%M:%S')) }
Now,
for e.g. I do have 3 events for following timestamps(all in UTC):
2013-04-11 11:43:43
2013-04-11 15:10:40
2013-04-12 07:39:26
and then you can call:
start_time = Time.zone.parse('2016-01-01 20:00:00')
# => Fri, 01 Jan 2016 20:00:00 ACDT +10:30
Event.after(start_time) # this will return 2 events(1, 2)
query will be:
SELECT "events".* FROM "events" WHERE (created_at::time > '09:30:00')
Note: This will raise an error ActiveRecord::StatementInvalid: PG::AmbiguousColumn: ERROR: column reference "created_at" is ambiguous if you will use this query with any another model that will have created_at column
I'm accessing the Evernote API via the evernote gem for ruby on rails, and I'm storing the objects (notebooks, tags, notes, etc.) in a Postgresql database.
Evernote returns timestamps that look like this:
1344141917000
1344141967000
1344138641000
The evernote api documentation says this is the number of milliseconds that have passed since the base time of January 1, 1970, 00:00:00 GMT
I've conducted the following exercise in the rails console in an attempt to reconstruct the date.
evernote_timestamp_base = Time.gm(1970,01,01,00,00,00)
=> 1970-01-01 00:00:00 UTC
evernote_timestamp_base + 1344138641000
=> 44564-01-22 04:43:20 UTC
Definitely not right. But chopping those last three zeros off yields the right date:
evernote_timestamp_base + 1344138641
=> 2012-08-05 03:50:41 UTC
Am I missing something here? What's the deal with those last three zeros? Will I have to parse and chop the evernote timstamp values and then add them to the 1970 base, or is there an easier way?
Also, what's the best Postgresql data type for storing these values?
Thanks in advance for your help.
To do this in Ruby, use Time.at. You'll need to divide by 1000 since Evernote timestamps are in millseconds and Ruby/Unix timestamps are in seconds.
createdNote = noteStore.createNote(authToken, note)
createTime = Time.at(createdNote.created / 1000);
puts "Note was created at #{createTime}"
In postgresql you could use a timestamp [with|without] time zone as the type for the column.
The unix timestamp is defined as the number of seconds since January 1, 1970, 00:00:00 GMT which is what Ruby and many other systems use and or support. PostgreSQL can do the conversion for you to. Just pass the value in seconds to the to_timestamp function.
SELECT to_timestamp(1344138641000/1000.0)
To convert it back use
SELECT EXTRACT(EPOCH FROM col)
I get an error in my functional test when using assert_equal:
1) [31mFailure[0m:
test_should_allow_dealer_to_extend_offer:21
<Thu, 14 Apr 2011 23:59:59 PDT -07:00> expected but was
<Thu, 14 Apr 2011 23:59:59 PDT -07:00>.
Notice that the two show the same time and time zone. I checked and they are the same class type (ActiveSupport::TimeWithZone). So why aren't they equal?
It's a standard DateTime field in the database, which I think is only stored down to the second right?
I can get it to pass by converting them to integers or using assert_in_delta with a range of 1 minute. But was just wondering.
Btw this is Rails 2.3.8 and MySQL.
I'm getting the same error too. It looks like this was reported back in 2009:
I've seen this happen in tests before - typically caused by the database having a different time resolution than the system. So even though the two times print identically, one is really (for instance) 15:45:32.012445362 and the DB loads back 15:45:32, which doesn't compare as equal.
The suggested solution, which worked for me:
In your tests, you can try coercing to_a before comparing; usec value isn't returned in the to_a representation:
I have an Appointment model, and for one particular appointment, I saved it having a start_time of 12:15am on 3/5/2011. Look at this:
irb(main):002:0> a = Appointment.find(15)
=> #<Appointment id: 15, start_time: "2011-03-05 05:15:00", created_at: "2011-03-05 03:42:03", updated_at: "2011-03-05 03:42:03", stylist_id: 13, client_id: 8>
irb(main):003:0> a.start_time
=> Sat, 05 Mar 2011 00:15:00 EST -05:00
As you can see, the date got saved wrong. Interestingly, though, Rails compensates for it when the data comes back out.
I assume my app has always behaved this way and I just didn't notice. Recently, though, I wrote a query that pulls the dates out with raw SQL, so I'm getting the wrong time and it's causing problems.
Can anyone shed some light on why this is happening and what I can do to get around the problem?
Rails does this on purpose. Check your time zone settings:
config.active_record.default_timezone
config.time_zone
http://guides.rubyonrails.org/configuring.html#configuring-active-record
Time zone features were introduced in 2.1 and haven't changed much. This article gives a good explanation:
http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/
Rails save datetime in database in UTC time(zero offset) and converts the time to the time zone which we intend when it displays it. So, when we parse directly from the database, you will be getting UTC time. If you try to convert it into time like this:
time_string = #raw string obtained from database(like "2011-03-05 05:15:00")
time_object = Time.parse(time_string)
You will get the time with offset according to the timezone of your machine or server. Ruby parses time like that. It will take the time and give the timezone of your machine(which is incorrect here as the timezone is actually UTC as it is from database). I ran into this problem and solved it by adding UTC when I parse time from raw sql strings from database.
time_string << " UTC"
time_object = Time.parse(time_string) # gives time zone as UTC
then if you use it, the result will be correct.