I have a ruby application where i need to get date-time difference in Days-Hours-Minutes format. For this i m using following function
def duration (from_time, to_time)
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
distance_in_seconds = ((to_time - from_time).abs).round
secs = distance_in_seconds.to_int
mins = secs / 60
hours = mins / 60
days = hours / 24
if days > 0
"#{days}d #{hours % 24}h"
elsif hours > 0
"#{hours}h #{mins % 60}m"
elsif mins > 0
"#{mins}m"
end
end
The above called like this from another function
duration(aw_updated, Time.now)
But some time it gives me wrong result,
when i display above values
aw_updated is 2012-09-19 04:23:34 UTC
Time.now is 2012-09-19 16:33:09 +0530
Time.now.utc is 2012-09-19 11:03:09 UTC
And
Diff is 6h 26m
But my system time is 2012-09-19 16:33:09
Not sure where i m doing wrong , some UTC issue?
please advise
For correct answer your both time should have same timezone utc in this case
So it is converting 2012-09-19 16:33:09 +0530 into utc which gives 2012-09-19 11:03:09 UTC and hence difference is Diff is 6h 26m
Would enter this as a comment but can't yet.
I haven't looked in detail at your function but do you have to build it from scratch? Why don't you use the Ruby in built DateTime class. You can parse strings to DateTime objects, do the calculation and use the strftime method to output the time in a format that you want
Related
I am using DatePipe to display Epoch time, the milliseconds time is in UTC, I want to keep it display on UTC so I am setting timezone option is '0'.
Here is my code:
<span class="description">{{epochTime | date:'dd/MM/yy hh:mm a':'0'}}</span>
with 'epochTime' = '1570274515223' <=> 'Sat Oct 05 2019 11:21:55 AM'.
But on the UI is: '05/10/19 06:21 PM'
It is getting local time zone here. Why I can not force pipe to use UTC time?
'0' is not valid. Instead, specify the offset in one of the following ways: 0, '+0','+00:00', 'UTC'
I have a date value like 2016-11-19 and a time value like 2000-01-01 20:14:00 +0000
I want to convert it to proper date format which will show utc time like below:
2016-11-20 04:14:00 +0000
There lots of questions regarding this, but I am confused.
You need to convert your date value to a time value:
>> date = Date.new(2016, 11, 19)
>> time = date.to_time
=> 2016-11-19 00:00:00 -0700
Note that time will be set to midnight in the time zone to which your server is set. Now that you have a time object, you can add seconds to it:
>> time_increment = Time.new(2000, 1, 1, 20, 14, 0)
>> seconds_increment = time_increment.seconds_since_midnight
=> 72840.0
>> new_time = time + seconds_increment
=> Sat, 19 Nov 2016 20:14:00 MST -07:00
You can use Ruby strftime datetime format.
Like
date_value.strftime('%Y-%m-%d %H:%M:%S') #=> 24-hour clock
date_value.strftime('%Y-%m-%d %I:%M:%S') #=> 12-hour clock
Full documentation
Thanks everyone! But, I could solve the problem on my own!
time = bid_end_time.hour.to_s + ":" + bid_end_time.min.to_s + ":" + bid_end_time.sec.to_s
date_time = bid_end_date.to_s + " " + time
bid_end_date_time = Time.zone.parse(date_time).utc
I see that typing 100.days gives me [edit: seems to give me] a Fixnum 8640000:
> 100.days.equal?(8640000)
=> true
I would have thought those two values were interchangable, until I tried this:
x = Time.now.to_date
=> Wed, 31 Oct 2012
> [x + 100.days, x + 8640000]
=> [Fri, 08 Feb 2013, Mon, 07 May 25668]
Why, and how, does adding apparently equal values to equal dates give different results?
The above results are from the Rails console, using Rails version 3.1.3 and Ruby version 1.9.2p320. (I know, I should upgrade to the latest version...)
100.days doesn't return a Fixnum, it returns an ActiveSupport::Duration, which tries pretty hard to look like a integer under most operations.
Date#+ and Time#+ are overridden to detect whether a Duration is being added, and if so does the calculation properly rather than just adding the integer value (While Time.+ expects a number of seconds, i.e. + 86400 advances by 1 day, Date.+ expects a number of days, so +86400 advances by 86400 days).
In addition some special cases like adding a day on the day daylight savings comes into effect are covered. This also allow Time.now + 1.month to advance by 1 calendar month irrespective of the number of days in the current month.
Besides what Frederick's answer supplies, adding 8640000 to a Date isn't the same as adding 8640000 to a Time, nor is 100.days the correct designation for 100 days.
Think of 100.days meaning "give me the number of seconds in 100 days", not "This value represents days". Rails used to return the number of seconds, but got fancy/smarter and changed it to a duration so the date math could do the right thing - mostly. That fancier/smarter thing causes problems like you encountered by masking what's really going on, and makes it harder to debug until you do know.
Date math assumes day values, not seconds, whereas Time wants seconds. So, working with 100 * 24 * 60 * 60 = 8640000:
100 * 24 * 60 * 60 => 8640000
date = Date.parse('31 Oct 2012') => Wed, 31 Oct 2012
time = Time.new(2012, 10, 31) => 2012-10-31 00:00:00 -0700
date + 8640000 => Mon, 07 May 25668
time + 8640000 => 2013-02-08 00:00:00 -0700
date + 100 => Fri, 08 Feb 2013
It's a pain sometimes dealing with Times and Dates, and you're sure to encounter bugs in code you've written where you forget. That's where the ActiveSupport::Duration part helps, by handling some of the date/time offsets for you. The best tactic is to use either Date/DateTime or Time, and not mix them unless absolutely necessary. If you do have to mix them, then bottleneck the code into methods so you have a single place to look if a problem crops up.
I use Date and DateTime if I need to handle larger ranges than Time can handle, plus DateTime has some other useful features, otherwise I use Time because it's more closely coupled to the OS and C. (And I revealed some of my roots there.)
when users sign up to one of my sites for a free trial, i set their account expiry to be "14.days.from_now". Then on the home page i show how many days they have remaining, which i get with:
(user.trial_expires - Time.now)/86400
(because there are 86400 seconds in a day, ie 60 * 60 * 24)
The funny thing is, this comes out as more than 14, so gets rounded up to 15. On closer investigation in the console this happens for just two days in the future (if you know what i mean). eg
>> Time.now
=> Fri Oct 29 11:09:26 0100 2010
>> future_1_day = 1.day.from_now
=> Sat, 30 Oct 2010 11:09:27 BST 01:00
#ten past eleven tomorrow
>> (future_1_day - Time.now)/86400
=> 0.999782301526931
#less than 1, what you'd expect right?
>> future_2_day = 2.day.from_now
=> Sun, 31 Oct 2010 11:09:52 GMT 00:00
>> (future_2_day - Time.now)/86400
=> 2.04162248861183
#greater than 2 - why?
I thought maybe it was to do with timezones - i noticed that the time from 1.day from now was in BST and the time 2 days from now was in GMT. So, i tried using localtime and got the same results!
>> future_2_day = 2.day.from_now.localtime
=> Sun Oct 31 11:11:24 0000 2010
>> (future_2_day - Time.now)/86400
=> 2.04160829127315
>> (future_2_day - Time.now.localtime)/86400
=> 2.04058651585648
I then wondered how big the difference is, and it turns out that it is exactly an hour out. So it looks like some time zone weirdness, or at least something to do with time zones that i don't understand. Currently my time zone is BST (british summer time) which is one hour later than UTC at the moment (till this sunday at which point it reverts to the same as UTC).
The extra hour seems to be introduced when i add two days to Time.now: check this out. I start with Time.now, add two days to it, subtract Time.now, then subtract two days of seconds from the result, and am left with an hour.
It just occurred to me, in a head slapping moment, that this is occurring BECAUSE the clocks go back on sunday morning: ie at 11.20 on sunday morning it will be two days AND an extra hour from now. I was about to delete all of this post, but then i noticed this: i thought 'ah, i can fix this by using (24*daynum).hours instead of daynum.days, but i still get the same result: even when i use seconds!
>> (Time.now + (2*24).hours - Time.now) - 86400*2
=> 3599.99969500001
>> (Time.now + (2*24*3600).seconds - Time.now) - 86400*2
=> 3599.999855
So now i'm confused again. How can now plus two days worth of seconds, minus now, minus two days worth of seconds be an hour worth of seconds? Where does the extra hour sneak in?
As willcodejavaforfood has commented, this is due to daylight saving time which ends this weekend.
When adding a duration ActiveSupport has some code in it to compensate for if the starting time is in DST and the resulting time isn't (or vice versa).
def since(seconds)
f = seconds.since(self)
if ActiveSupport::Duration === seconds
f
else
initial_dst = self.dst? ? 1 : 0
final_dst = f.dst? ? 1 : 0
(seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
end
rescue
self.to_datetime.since(seconds)
end
If you have 11:09:27 and add a number of days you will still get 11:09:27 on the resulting day even if the DST has changed. This results in an extra hour when you come to do calculations in seconds.
A couple of ideas:
Use the distance_of_time_in_words helper method to give the user an indication of how long is left in their trial.
Calculate the expiry as Time.now + (14 * 86400) instead of using 14.days.from_now - but some users might claim that they have lost an hour of their trial.
Set trials to expire at 23:59:59 on the expiry day regardless of the actual signup time.
You could use the Date class to calculate the number of days between today and the expire date.
expire_date = Date.new(user.trial_expires.year, user.trial_expires.month, user.trial_expires.day)
days_until_expiration = (expire_date - Date.today).to_i
Use since, example:
14.days.since.to_date
If in a database (MySQL), I have a datetime column (ex. 1899-12-30 19:00:00), how do I sum 1 day to it?
Following http://corelib.rubyonrails.org/classes/Time.html#M000240
If I want to add 1 day, it actually adds 60*60*24 days (86,400 days)
r=Record.find(:first)
=>Sat, 30 Dec 1899 19:00:00 -0600
r.date + (60*60*24)
=>Fri, 20 Jul 2136 19:00:00 -0600
But if I do this it actually adds 1 day:
t = Time.now
=>Mon Jun 14 10:32:51 -0600 2010
t + (60 * 60 * 24)
=>Tue Jun 15 10:33:21 -0600 2010
I guess it has to do with the format...how do I make this work?
You're actually adding 86,400 seconds (60 seconds * 60 minutes * 24 hours).
ActiveSupport has some built in helper methods for dealing with time:
Time.now + 1.day + 15.hours
In Rails,
its very simple to use times.
r = Record.find(:first)
r.created_at + 1.day # this will give you a day to one day ahead )
r.created_at + 2.days + 15.hours + 30.minutes + 5.seconds
or use Time.now
Also, if you want take a look at the by_star plugin/gem its makes some querying etc very easy.