There are three statements like below:
print("first time", time.time())
self.wait(5)
print("second time", time.time())
I suppose the difference between "second time" and "first time" will be 5 seconds, however, they are the same, why?
I think the self.wait(5) should be async call, if so, how to get timestame in runtime?
If what you want is to print in the terminal the exact second of each moment of the animation you can do something like this (the time is saved in the variable self.time):
class TimeTest(Scene):
def print_time(self):
print("Time:",self.time)
def construct(self):
dot=Dot()
# 0 seconds
self.print_time()
self.play(Write(dot,run_time=2))
# 2 seconds
self.print_time()
self.wait()
# 3 seconds
self.print_time()
self.play(dot.shift,UP,run_time=1)
# 4 seconds
self.print_time()
self.play(FadeToColor(dot,RED,run_time=3))
# 7 seconds
self.print_time()
self.wait()
# 8 seconds
self.print_time()
It looks like in the recent version of Manim-CE time is no longer a member variable of Scene (although this might still be the way to go for ManimGL).
What worked for me was using self.renderer.time
Related
I'm taking a PCollection of sessions and trying to get average session duration per channel/connection. I'm doing something where my early triggers are firing for each window produced - if 60min windows sliding every 1 minute, an early trigger will fire 60 times. Looking at the timestamps on the outputs, there's a window every minute for 60minutes into the future. I'd like the trigger to fire once for the most recent window so that every 10 seconds I have an average of session durations for the last 60 minutes.
I've used sliding windows before and had the results I expected. By mixing sliding and sessions windows, I'm somehow causing this.
Let me paint you a picture of my pipeline:
First, I'm creating sessions based on active users:
.apply("Add Window Sessions",
Window.<KV<String, String>> into(Sessions.withGapDuration(Duration.standardMinutes(60)))
.withOnTimeBehavior(Window.OnTimeBehavior.FIRE_ALWAYS)
.triggering(
AfterWatermark.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime
.pastFirstElementInPane()
.plusDelayOf(Duration.standardSeconds(10))))
.withAllowedLateness(Duration.ZERO)
.discardingFiredPanes()
)
.apply("Group Sessions", Latest.perKey())
Steps after this create a session object, compute session duration, etc. This ends with a PCollection(Session).
I create a KV of connection,duration from the Pcollection(Session).
Then I apply the sliding window and then the mean.
.apply("Apply Rolling Minute Window",
Window. < KV < String, Integer >> into(
SlidingWindows
.of(Duration.standardMinutes(60))
.every(Duration.standardMinutes(1)))
.triggering(
Repeatedly.forever(
AfterWatermark.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime
.pastFirstElementInPane()
.plusDelayOf(Duration.standardSeconds(10)))
)
)
.withAllowedLateness(Duration.standardMinutes(1))
.discardingFiredPanes()
)
.apply("Get Average", Mean.perKey())
It's at this point where I'm seeing issues. What I'd like to see is a single output per key with the average duration. What I'm actually seeing is 60 outputs for the same key for each minute into the next 60 minutes.
With this log in a DoFn with C being the ProcessContext:
LOG.info(c.pane().getTiming() + " " + c.timestamp());
I get this output 60 times with timestamps 60 minutes into the future:
EARLY 2017-12-17T20:41:59.999Z
EARLY 2017-12-17T20:43:59.999Z
EARLY 2017-12-17T20:56:59.999Z
(cont)
The log was printed at Dec 17, 2017 19:35:19.
The number of outputs is always window size/slide duration. So if I did 60 minute windows every 5 minutes, I would get 12 output.
I think I've made sense of this.
Sliding windows create a new window with the .every() function. Setting early firings applies to each window so getting multiple firings makes sense.
In order to fit my use case and only output the "current window", I'm checking c.pane().isFirst() == true before outputting results and adjusting the .every() to control the frequency.
Looking at "How to recover an integer from an ActiveSupport::Duration object", I can see it should be possible, but for:
2.hours.parts
I get:
[[:seconds, 7200]]
How can this be done better so that I have:
[[:hours, 2]]
That may not be possible.
If you look at implementation of core-extensions in Active Support, time.rb, parts is set to :seconds for Duration instances constructed using Numeric#hours or Numeric#minutes or Numeric#seconds.
p 1.hour # 3600 seconds
p 2.minutes # 120 seconds
p 30.seconds # 30 seconds
Hence, you will always see something like below for all duration which are in hours, minutes or seconds, if you inspect the Duration#parts attribute
[[:seconds, 7200]]
I have the following method to convert a duration in seconds to hours. For example, 2 hours and a half would result in 2.30 Also, 2 hours and fifteen minutes would result in 2.15. So it outputs number of hours and number of minutes.
I want to modify the method to display 2.5 or 2.25 instead of the above. I need to do it that way to make calculations. For example, if there is a $30/hr salary and employee worked 10 hours and a half, I need to multiply 30*10.5 and not 30*10.30.
def hour_quantity
unless self.duration.blank?
hours = (self.duration/60)/60
minutes = (self.duration/60) % 60
hours.to_s + '.' + minutes.to_s
end
end
Jon is correct, as usual. Just use floating point division:
def hour_quantity
duration / 3600.0
end
When displaying, you might want to round:
puts '%.2f' % hour_quantity
This will give you 2 decimal places, always (e.g. "2.00", "2.25", "2.50"). Alternatively:
puts '%g' % hour_quantity
puts '%g' % 2.0 #=> "2"
puts '%g' % 2.25 #=> "2.25"
puts '%g' % 2.4999999 #=> "2.5"
Since Rails 6.1.0 you can do:
1800.seconds.in_hours # => 0.5
15.minutes.in_hours # => 0.25
These are the methods that were newly introduced: in_seconds, in_minutes, in_hours, in_days, in_weeks, in_months, and in_years.
I need to know how to do relative time in rails but not as a sentence, more like something i could do this with (when i input format like this 2008-08-05 23:48:04 -0400)
if time_ago < 1 hour, 3 weeks, 1 day, etc.
execute me
end
Basic relative time:
# If "time_ago" is more than 1 hour past the current time
if time_ago < 1.hour.ago
execute_me
end
Comparison:
Use a < to see if time_ago is older than 1.hour.ago, and > to see if time_ago is more recent than 1.hour.ago
Combining times, and using fractional times:
You can combine times, as davidb mentioned, and do:
(1.day + 3.hours + 2500.seconds).ago
You can also do fractional seconds, like:
0.5.seconds.ago
There is no .milliseconds.ago, so if you need millisecond precision, just break it out into a fractional second. That is, 1 millisecond ago is:
0.001.seconds.ago
.ago() in general:
Putting .ago at the end of just about any number will treat the number as a #of seconds.
You can even use fractions in paranthesis:
(1/2.0).hour.ago # half hour ago
(1/4.0).year.ago # quarter year ago
NOTE: to use fractions, either the numerator or denominator needs to be a floating point number, otherwise Ruby will automatically cast the answer to an integer, and throw off your math.
You mean sth. like this?
if time_ago < Time.now-(1.days+1.hour+1.minute)
execute me
end
I have a rails application and I want to display messages (Message) to the user based on the time the messages have arrived
every message (Message) has a property called created_at
for example
-- 20 minutes ago
-----message1
-----message2
-- 1 hour ago
-----message3
-----message4
-----message5
-- 2 days ago
-----message6
and so on and so forth.
how can I do this using rails?
I am using rails 3 b.t.w
You basically have two options. The first is to use the built-in Rails helper time_ago_in_words:
# in your views
<%= time_ago_in_words(message.created_at) %>
You can read more about this helper in the Rails documentation.
The downside with this is that it only works in views, and it might not be the entirely correct format. If that's the case, you can always define your own helper in an initializer. Here's a method I coded up for an old app, which you should be able to modify to suit your requirements:
class ActiveSupport::TimeWithZone
def how_long_ago
seconds = (Time.now - self)
# Keep adding days, weeks, months, years if necessary--same principle should apply
if seconds > 3600
(seconds / 3600).to_i.to_s + "h " + (seconds % 3600 / 60).to_i.to_s + "m"
elsif seconds > 60
(seconds / 60).to_i.to_s + "m " + (seconds % 60).to_i.to_s + "s"
else
seconds.to_i.to_s + "s"
end
end
end
Message.first.created_at.how_long_ago # => 3m 52s
To group the data based on this, you can use the group_by method on the messages array.
You can set default scope in your Message model:
default_scope order('messages.created_at DESC')
I found an answer on RailsCasts which is perfect for my needs
http://railscasts.com/episodes/29-group-by-month