Add 1 millisecond to a Time/DateTime object - ruby

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

Get the last and the previous "gold_id" of the previous day with mongo

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

Calculating the difference between durations with milliseconds in Ruby

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.

ArgumentError invalid date in DateTime#change

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

capped collection mongodb

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).

How to get today's day of previous month in ruby?

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.

Resources