Is there a way to add 1 millisecond to a Time/DateTime object in Ruby?
For an Webservice Request i need a time scoping with milliseconds:
irb(main):034:0> time_start = Date.today.to_time.utc.iso8601(3)
=> "2016-09-27T22:00:00.000Z"
irb(main):035:0> time_end = ((Date.today + 1).to_time).utc.iso8601(3)
=> "2016-09-28T22:00:00.000Z"
-- or --
irb(main):036:0> time_end = ((Date.today + 1).to_time - 1).utc.iso8601(3)
=> "2016-09-28T21:59:59.000Z"
So I'm near my prefered solution, but time_end should be 2016-09-28T21:59:59.999Z.
I didn't find solutions that Ruby can handle calculating with milliseconds. I only did it with strftime, but it would be great if there is a possibility to calculate.
-- This works, but hard coded --
time_end = ((Date.today + 1).to_time - 1).utc.strftime("%Y-%m-%dT%H:%M:%S.999Z")
=> "2016-09-28T21:59:59.999Z"
FYI: I'm on plain Ruby, no Rails.
Ok i found a solution. With real calculation i looks like.
time_end = ((Date.today + 1).to_time - 1/1001).utc.iso8601(3)
=> "2016-09-28T21:59:59.999Z"
EXAMPLE
Formatting in iso8601(3) is only to show behavior.
irb(main):055:0> Date.today.to_time.iso8601(3)
=> "2016-09-28T00:00:00.000+02:00
Adding a millisecond"
irb(main):058:0> (Date.today.to_time + 1/1000.0).iso8601(3)
=> "2016-09-28T00:00:00.001+02:00"
Subtract a millisecond
!DONT USE, see result with subtracted 2 milliseconds!
irb(main):060:0> (Date.today.to_time - 1/1000.0).iso8601(3)
=> "2016-09-27T23:59:59.998+02:00"
USE
irb(main):061:0> (Date.today.to_time - 1/1001.0).iso8601(3)
=> "2016-09-27T23:59:59.999+02:00"
Related
I have this kind of data :
{"_id"=>BSON::ObjectId('560b5c5d80ec9700030035dc'), "active"=>true, "user_id"=>nil, "action"=>"connection", "shop_id"=>245929, "gold_id"=>23452349, "indexed"=>true, "created_at"=>2015-09-30 03:51:57 UTC}
I'm trying to get the first and last gold_id of the previous day. I'm getting arroung 10_000 logs per days.
I'm using the ruby driver
first_gold_in = Time.utc(Date.today.year, Date.today.month, (Date.today.day - 1), 00, 00)
first_gold_out = yesterday_o_clock + 5*60
first_gold_id = logs
.find("action" => "connection", "created_at" => {"$gte" => first_gold_in, "$lte" => first_gold_out} )
.first
.fetch("gold_id")
last_gold_in = Time.utc(Date.today.year, Date.today.month, (Date.today.day - 1), 23, 55)
last_gold_out = yesterday_o_clock + 5*60 - 1
last_gold_id = logs
.find("action" => "connection", "created_at" => {"$gte" => last_gold_in, "$lte" => last_gold_out} )
.first
.fetch("gold_id")
But It's very slow even with shorter date range. Is there a better way to do it?
Also is is possible to get the first and the last of the day in the same request?
Thanks
TL;DR: I need to get the difference between HH:MM:SS.ms and HH:MM:SS.ms as HH:MM:SS:ms
What I need:
Here's a tricky one. I'm trying to calculate the difference between two timestamps such as the following:
In: 00:00:10.520
Out: 00:00:23.720
Should deliver:
Diff: 00:00:13.200
I thought I'd parse the times into actual Time objects and use the difference there. This works great in the previous case, and returns 00:0:13.200.
What doesn't work:
However, for some, this doesn't work right, as Ruby uses usec instead of msec:
In: 00:2:22.760
Out: 00:2:31.520
Diff: 00:0:8.999760
Obviously, the difference should be 00:00:8:760 and not 00:00:8.999760. I'm really tempted to just tdiff.usec.to_s.gsub('999','') ……
My code so far:
Here's my code so far (these are parsed from the input strings like "0:00:10:520").
tin_first, tin_second = ins.split(".")
tin_hours, tin_minutes, tin_seconds = tin_first.split(":")
tin_usec = tin_second * 1000
tin = Time.gm(0, 1, 1, tin_hours, tin_minutes, tin_seconds, tin_usec)
The same happens for tout. Then:
tdiff = Time.at(tout-tin)
For the output, I use:
"00:#{tdiff.min}:#{tdiff.sec}.#{tdiff.usec}"
Is there any faster way to do this? Remember, I just want to have the difference between two times. What am I missing?
I'm using Ruby 1.9.3p6 at the moment.
Using Time:
require 'time' # Needed for Time.parse
def time_diff(time1_str, time2_str)
t = Time.at( Time.parse(time2_str) - Time.parse(time1_str) )
(t - t.gmt_offset).strftime("%H:%M:%S.%L")
end
out_time = "00:00:24.240"
in_time = "00:00:14.520"
p time_diff(in_time, out_time)
#=> "00:00:09.720"
Here's a solution that doesn't rely on Time:
def slhck_diff( t1, t2 )
ms_to_time( time_as_ms(t2) - time_as_ms(t1) )
end
# Converts "00:2:22.760" to 142760
def time_as_ms( time_str )
re = /(\d+):(\d+):(\d+)(?:\.(\d+))?/
parts = time_str.match(re).to_a.map(&:to_i)
parts[4]+(parts[3]+(parts[2]+parts[1]*60)*60)*1000
end
# Converts 142760 to "00:02:22.760"
def ms_to_time(ms)
m = ms.floor / 60000
"%02i:%02i:%06.3f" % [ m/60, m%60, ms/1000.0 % 60 ]
end
t1 = "00:00:10.520"
t2 = "01:00:23.720"
p slhck_diff(t1,t2)
#=> "01:00:13.200"
t1 = "00:2:22.760"
t2 = "00:2:31.520"
p slhck_diff(t1,t2)
#=> "00:00:08.760"
I figured the following could work:
out_time = "00:00:24.240"
in_time = "00:00:14.520"
diff = Time.parse(out_time) - Time.parse(in_time)
Time.at(diff).strftime("%H:%M:%S.%L")
# => "01:00:09.720"
It does print 01 for the hour, which I don't really understand.
In the meantime, I used:
Time.at(diff).strftime("00:%M:%S.%L")
# => "00:00:09.720"
Any answer that does this better will get an upvote or the accept, of course.
in_time = "00:02:22.760"
out_time = "00:02:31.520"
diff = (Time.parse(out_time) - Time.parse(in_time))*1000
puts diff
OUTPUT:
8760.0 millliseconds
Time.parse(out_time) - Time.parse(in_time) gives the result in seconds so multiplied by 1000 to convert into milliseconds.
When doing
startTime = DateTime.now
startTime = startTime.change(:min => (startTime.min / 5.to_f).ceil * 5)
our production server occasionally produces the following exception
A ArgumentError occurred in controller#action:
invalid date
/opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/1.8/date.rb:1519:in `civil'
vendor/bundle/ruby/1.8/gems/activesupport-3.0.9/lib/active_support/core_ext/date_time/calculations.rb:37:in `change'
And I just can't figure out what causes the problem nor reproduce it in my development environment. Am I doing something wrong, or what is happening here? What I want to do is create a DateTime instance which is rounded up to the closest 5 min from now.
If DateTime.now.min > 55, then you are setting the min value to 60.
If you only need the time part:
startTime = DateTime.now
new_minute = startTime.min / 5.to_f).ceil * 5
new_hour = DateTime.now.hour
if new_minute == 60
new_minute = 0
new_hour = new_hour + 1
end
new_time = startTime.change(:min => new_minute, :hour => new_hour)
if you need more than this, I'd suggest using activesupport. Then you could do
new_time = startTime + (new_minute - min).minutes
I have issues with mongoDB.
Currently i'm working with Ruby mongodb drivers and there r some strange things r going on:
i need to insert 20 documents in the capped collection but when i write the following code, it inserts only 3 docs and i can't get what's going on:
coll = db.create_collection("test",:capped => true, :max=>20)
1024.times{#pad_string +=" "}
20.times{coll.insert({
:HostName => #hostname,
:CommandLine => #cmdline,
:Pid => "1111",
:BlockName => #blockname,
:ExitCode => 0,
:StartTime => Time.now,
:EndTime => Time.utc(2000,"jan",1,00,00,00),
:StdErr => #pad_string,
:Stdout => #pad_string}
)}
actually the point is that i insert #pad_string with 1024 preallocated spaces. As soon as i do that before inserting 1024.times{#pad_string +=" "}, it inserts only 3 docs maximum.
When you cap a collection based on the number of objects you also have to cap it based on size - I wonder what size the ruby driver is sending down.
try this:
coll = db.create_collection("test",:capped => true, :size=>100000, :max=>20)
Then tweak the size to whatever works for you (it's in bytes).
Is there a built-in function to get the day in last month, same as today? Examples:
2010/05/02 -> 2010/04/02
2010/05/15 -> 2010/04/15
2010/05/31 -> 2010/04/30
Thanks!
You can subtract entire months with <<.
>> d = Date.parse('2010-05-31')
=> #<Date: 4910695/2,0,2299161>
>> d.to_s
=> "2010-05-31"
>> (d<<1).to_s
=> "2010-04-30"
More info
You could do this:
(Date.today - 1.month).strftime("%Y/%m/%d")
You can try using
Time.parse('2010/05/31').months_since(-1).
You could for instance make a time object
old_time = Time.now
Then create a new time object based on that
new_time = Time.local(old_time.year, (old_time.month - 1), old_time.day, old_time.hour, old_time.min, old_time.sec)
However, as deceze pointed out, what is the criterion for 5/31 becoming 4/30?
In irb, 4/31 'overflows' to 5/01.
Ruby's date class allows you to add, subtract days from a particular date.