aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
authorJon Moss <me@jonathanmoss.me>2016-09-01 18:02:55 -0400
committerJon Moss <me@jonathanmoss.me>2016-10-02 15:12:46 -0400
commit353122c9da6caa30f1d4a117d4c543cd567ca3bb (patch)
treed090cdec7d32affe9c2df398825d1f4611771511 /activesupport/lib
parentda0fdd6bf529df8806ddb4b97e4bb31c95249e0e (diff)
downloadrails-353122c9da6caa30f1d4a117d4c543cd567ca3bb.tar.gz
rails-353122c9da6caa30f1d4a117d4c543cd567ca3bb.tar.bz2
rails-353122c9da6caa30f1d4a117d4c543cd567ca3bb.zip
Speed up Time.zone.now
@amatsuda, during his RailsConf talk this past year, presented a benchmark that showed `Time.zone.now` (an Active Support joint) performing 24.97x slower than Ruby's `Time.now`. Rails master appears to be a _bit_ faster than that, currently clocking in at 18.25x slower than `Time.now`. Here's the exact benchmark data for that: ``` Warming up -------------------------------------- Time.now 127.923k i/100ms Time.zone.now 10.275k i/100ms Calculating ------------------------------------- Time.now 1.946M (± 5.9%) i/s - 9.722M in 5.010236s Time.zone.now 106.625k (± 4.3%) i/s - 534.300k in 5.020343s Comparison: Time.now: 1946220.1 i/s Time.zone.now: 106625.5 i/s - 18.25x slower ``` What if I told you we could make `Time.zone.now` _even_ faster? Well, that's exactly what this patch accomplishes. When creating `ActiveSupport::TimeWithZone` objects, we try to convert the provided time to be in a UTC format. All this patch does is, in the method where we convert a provided time to UTC, check if the provided time is already UTC, and is a `Time` object and then return early if that is the case, This sidesteps having to continue on, and create a new `Time` object from scratch. Here's the exact benchmark data for my patch: ``` Warming up -------------------------------------- Time.now 124.136k i/100ms Time.zone.now 26.260k i/100ms Calculating ------------------------------------- Time.now 1.894M (± 6.4%) i/s - 9.434M in 5.000153s Time.zone.now 301.654k (± 4.3%) i/s - 1.523M in 5.058328s Comparison: Time.now: 1893958.0 i/s Time.zone.now: 301653.7 i/s - 6.28x slower ``` With this patch, we go from `Time.zone.now` being 18.25x slower than `Time.now` to only being 6.28x slower than `Time.now`. I'd obviously love some verification on this patch, since these numbers sound pretty interesting... :) This is the benchmark-ips report I have been using while working on this: ```ruby require 'benchmark/ips' Time.zone = 'Eastern Time (US & Canada)' Benchmark.ips do |x| x.report('Time.now') { Time.now } x.report('Time.zone.now') { Time.zone.now } x.compare! end ``` cc @amatsuda cc performance folks @tenderlove and @schneems ![Pretty... pretty... pretty good.](https://media.giphy.com/media/bWeR8tA1QV4cM/giphy.gif)
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
1 files changed, 2 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index bee481e5f5..acea38176f 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -478,6 +478,8 @@ module ActiveSupport
end
def transfer_time_values_to_utc_constructor(time)
+ # avoid creating another Time object if possible
+ return time if time.instance_of?(::Time) && time.utc?
::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
end