Ruby on Rails 3 Time - Parse Milliseconds - ruby-on-rails

I'm trying to parse a date like: 2011-05-21 04:20:46.011 into a Time object in Rails. So far I have the following:
Time.strptime("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%3N")
But it doesn't seem to like the "%3N" at the end. How do I parse this date?

Use parse:
x = Time.parse("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%3N")
# => 2011-05-21 04:20:46 -0700
x.usec
# => 11000
In many case you don't need to pass in the format either:
x = Time.parse("2011-05-21 04:20:46.011")
# => 2011-05-21 04:20:46 -0700
x.usec
# => 11000

Try Time.parse("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%3N")

With Ruby v 2.3.2 and Rails v 5.0.0.1 in rails console
2.3.2 :035 > Time.parse("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%3N")
NoMethodError: undefined method `getlocal' for "%Y-%m-%d %H:%M:%S.%3N":String
from /home/jignesh/.rvm/rubies/ruby-2.3.2/lib/ruby/2.3.0/time.rb:264:in `make_time'
from /home/jignesh/.rvm/rubies/ruby-2.3.2/lib/ruby/2.3.0/time.rb:366:in `parse'
from (irb):35
Note: In code below in the parse format, NOT prefixed %N with the number of fractional digits like %3N and instead simply specified %N and it works
2.3.2 :037 > Time.strptime("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%N")
=> 2011-05-21 04:20:46 +0530
2.3.2 :038 > tt = Time.strptime("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%N")
=> 2011-05-21 04:20:46 +0530
2.3.2 :039 > tt.usec
=> 11000
The above code didn't worked when using parse
2.3.2 :040 > tt = Time.parse("2011-05-21 04:20:46.011", "%Y-%m-%d %H:%M:%S.%N")
NoMethodError: undefined method `getlocal' for "%Y-%m-%d %H:%M:%S.%N":String
from /home/jignesh/.rvm/rubies/ruby-2.3.2/lib/ruby/2.3.0/time.rb:264:in `make_time'
from /home/jignesh/.rvm/rubies/ruby-2.3.2/lib/ruby/2.3.0/time.rb:366:in `parse'
from (irb):40
It looks strange because Time.strptime(date, format, now=self.now) official documentation does mention about %3N, %6N and %9N explicitly and using them in the parse format doesn't work!
Rails does provide a counterpart strptime(str, format, now=now()) as part of ActiveSupport::TimeZone API and it internally does the parsing using Ruby's standard DateTime._strptime as shown in its source-code:
# File activesupport/lib/active_support/values/time_zone.rb, line 382
def strptime(str, format, now=now())
parts_to_time(DateTime._strptime(str, format), now)
end
And I guess DateTime._strptime internally delegates to Ruby's standard Time.strptime
For those who are looking for leveraging Rails's Time.zone.parse counterpart for parsing in a specific format they can use below code:
tt = Time.zone.strptime('1999-12-31 14:00:00.011111', '%Y-%m-%d %H:%M:%S.%N')
=> Fri, 31 Dec 1999 14:00:00 UTC +00:00
2.3.2 :031 > tt.usec
=> 11111
Hope someone from the core-team can clarify about this behaviour observed and if the behaviour is normal then at-least a note should be made about in the documentation.

Related

Calculating exact duration time from a DateTime column in Postgres using Rails

I am trying to get a more accurate output than "about 2 hours" for duration time.
Currently, we are using time_ago_in_words
This looks like the below function in .erb
Duration: <%= time_ago_in_words(#sitrep.incident.created_at) %>
# I found the gem `dotiw` which lets me use:
distance_of_time_in_words(#sitrep.incident.created_at)
# However, there is an error and I can't get either to work in irb
This is my console output when attempting both. All help is appreciated
[1] pry(main)> include ActionView::Helpers
=> Object
[2] pry(main)> t = Sitrep.last.incident.created_at
# redacted output
=> Wed, 28 Nov 2018 21:47:45 UTC +00:00
[3] pry(main)> t
=> Wed, 28 Nov 2018 21:47:45 UTC +00:00
[4] pry(main)> time_ago_in_words(t)
=> "<span class=\"translation_missing\" title=\"translation missing: en.weeks\">Weeks</span>, <span class=\"translation_missing\" title=\"translation missing: en.days\">Days</span>, <span class=\"translation_missing\" title=\"translation missing: en.hours\">Hours</span>, and <span class=\"translation_missing\" title=\"translation missing: en.minutes\">Minutes</span>"
[5] pry(main)> distance_of_time_in_words(t)
NoMethodError: undefined method `seconds' for Wed, 28 Nov 2018 21:47:45 UTC +00:00:Time
Did you mean? send
Did you mean? send
from /Users/mmowris/.rbenv/versions/2.3.8/lib/ruby/gems/2.3.0/gems/activesupport-4.2.7.1/lib/active_support/time_with_zone.rb:371:in `method_missing'
[6] pry(main)>
The first method, time_ago_in_words works for our rails app. This .erb file sends an email, and the output would look something like:
Duration: about 2 hours
Any ideas on how to proceed? Why does this work in our rails project, but not irb? Why can't I get dotiw to work with the same input? Why can't i get taiw to work with the same input that works in production?
Thanks!
use the helper instead of including the helpers manually
> helper.time_ago_in_words(2.hours.ago, true)
=> "2 hours"
> helper.time_ago_in_words((2.hours.ago + 5.seconds), true)
=> "1 hour, 59 minutes, and 55 seconds"

beginning_of_day doesn't calculate time correctly

I got two models Shift and ShiftDetail. I have a Shift model methods that adds ShiftDetails automatically:
def add_shift_details
(0..6).each do |i|
shift_detail = ShiftDetail.new
t1 = Time.now
shift_detail.weekday = i
shift_detail.start_time = t1.beginning_of_day
shift_detail.end_time = t1.end_of_day
self.shift_details << shift_detail
end
end
But when i save the instance the database is populated with
["start_time", "2016-03-02 23:00:00.000000"]
["end_time", "2016-03-03 22:59:59.999999"]
I am using Rails 4.2.5.1 and ruby 2.3.0p0
What am I doing wrong?
UPDATE:
When I test it in 'rails c', it works as expected:
2.3.0 :001 > Time.now.beginning_of_day
=> 2016-03-03 00:00:00 +0100
2.3.0 :002 > Time.now.end_of_day
=> 2016-03-03 23:59:59 +0100
Your database stores DateTime in the UTC timezone while Rails works with the Berlin timezone. Berlin's midnight (GMT+1) is not equal with UTC's (GMT) midnight :)
You have two options:
Have your algorithm work with an UTC timezone
You can use Time.now.utc or DateTime.now.new_offset(0)
Have your database store dates in your specific timezone (Berlin's in this case). I highly advise not to do this.
Check out this post for more information:
https://stackoverflow.com/a/32229086/4304188

Calculate total time in minutes between two timings in two diff. time zones (UTC and IST) - Rails 3.2.13

I have two datetimes formats to calculate the difference.
2013-08-29 22:48:00 UTC
2013-08-30 00:18:40 +0530
How can I get the first subtracted from the second one? What is actually the difference between them other than in time?
Below are the things I run in my console:
Loading development environment (Rails 3.2.13)
2.0.0-p247 :001 > #a = Time.parse('2013-08-29 22:48:00 UTC')
=> 2013-08-29 22:48:00 UTC
2.0.0-p247 :002 > #b = Time.parse('2013-08-29 22:48:00 +0530')
=> 2013-08-29 22:48:00 +0530
2.0.0-p247 :003 > #a > #b
=> true
2.0.0-p247 :004 > #a == #b
=> false
2.0.0-p247 :005 > #a < #b
=> false
2.0.0-p247 :006 >
Both are not the same, so the answer from cmwright is found to be incorrect. Please have a look and it would be great if you could tell me how can we convert UTC format to +5.30 format in Rails 3.2?
seconds_difference = Time.parse('2013-08-29 22:48:00 UTC') - Time.parse('2013-08-30 00:18:40 +0530')
Will give you the seconds difference, then you can get you need from there by doing
seconds_difference / 1.day or seconds_difference / 1.hour
What is actually the difference between them other than in time?
Well, one date is at UTC (+00:00) and the other is at UTC+05:30.
2013-08-29 22:48:00 UTC => 2013-08-30 04:18:00 +0530
- 2013-08-29 18:48:40 UTC <= - 2013-08-30 00:18:40 +0530
------------------------- ---------------------------
3:59:20 3:59:20
Whichever direction you convert, they are 3 hours, 59 minutes, and 20 seconds apart.
CMWright's answer shows how you can subtract them in code. The integers you get from the Time.parse function are both based on UTC.

How to change date format in rails

Is this normal that rails put something like this :
DateTime.now = 2013-07-28T16:21:13+02:00
Why this T is between date and time ? How can i remove it. In I18n i have default:
default: ! '%a, %d %b %Y %H:%M:%S %z'
In your IRB console, if you call puts variable, it will make an implicit call to the method to_s on the variable object:
1.9.3 > DateTime.now
# => Wed, 28 Aug 2013 10:39:30 -0400
1.9.3 > puts DateTime.now
2013-08-28T10:39:33-04:00
# => nil
1.9.3 > DateTime.now.to_s
# => "2013-08-28T10:39:37-04:00"
This is why you see a "T" in the output, its .to_s's fault!

Ruby on Rails: how do I convert this date

Wed Sep 22 13:15:02 -0400 2010 to this format 2010-08-23 13:15:02 -0400
The left is Time.now
The right is 30.days.ago =\
You can use the to_s(:db) method in Time class to convert it to a database-friendly format.
Time.now.to_s(:db) # => "2010-09-22 17:50:41"
If you really need the time zone offset info, you could add a custom format to Time::DATE_FORMATS, e.g.
Time::DATE_FORMATS[:db_with_zone_offset] = lambda { |time|
time.strftime("%Y-%m-%d %H:%M:%S #{time.formatted_offset(false)}")
}
after which you can simply call
Time.now.to_s(:db_with_zone_offset) => # "2010-09-22 17:48:21 +0000"
Both are different data types.
>> Time.now.class
=> Time
>> 30.days.ago.class
=> ActiveSupport::TimeWithZone
use the strftime method to format it.
If you want to have format in database format, then you can use:
Time.now
=> Wed Sep 22 19:54:24 +0200 2010
Time.now.to_s(:db)
=> "2010-09-22 19:54:48"
Time.now.utc.to_s(:db)
=> "2010-09-22 17:55:16"

Resources