Skip to content

Instantly share code, notes, and snippets.

@will
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save will/e1ac8ce634cdb8ee07d5 to your computer and use it in GitHub Desktop.
Save will/e1ac8ce634cdb8ee07d5 to your computer and use it in GitHub Desktop.
time parsing benchmark
require "string_scanner"
require "benchmark"
class Common
# Postgres returns microseconds, Crystal Time only supports miliseconds
private def fraction_to_mili(frac)
if frac < 10
frac * 100
elsif frac < 100
frac * 10
elsif frac > 1000
frac / 1000
else
frac
end
end
private def apply_offset(t, offset)
if offset == 0
t
else
t - TimeSpan.new(offset,0,0)
end
end
end
class TimeDecoder < Common
def decode(value_ptr)
str = StringScanner.new(String.new(value_ptr))
year = str.scan(/(\d+)/).to_i; str.scan(/-/)
month = str.scan(/(\d+)/).to_i; str.scan(/-/)
day = str.scan(/(\d+)/).to_i; str.scan(/ /)
hour = str.scan(/(\d+)/).to_i; str.scan(/:/)
minute = str.scan(/(\d+)/).to_i; str.scan(/:/)
second = str.scan(/(\d+)/).to_i; str.scan(/\./)
fraction = str.scan(/(\d+)/).to_i
offset = str.scan(/([\+|\-]\d+)/).to_i
milisecond = fraction_to_mili(fraction)
t = Time.new(year, month, day, hour, minute, second, milisecond, Time::Kind::Utc)
return apply_offset(t, offset)
end
end
class TimeDecoderNew < Common
def initialize
super
@curr = Pointer(UInt8).new(0)
end
def decode(value_ptr)
@curr = value_ptr + 0
year = get_next_int
month = get_next_int
day = get_next_int
hour = get_next_int
minute = get_next_int
second = get_next_int
fraction = (@curr-1).value == '.'.ord ? get_next_int : 0
sign = (@curr-1).value == '-'.ord ? -1 : 1
offset = get_next_int * sign
milisecond = fraction_to_mili(fraction)
t = Time.new(year, month, day, hour, minute, second, milisecond, Time::Kind::Utc)
return apply_offset(t, offset)
end
private def get_next_int
return 0 if @curr.value == 0
int = 0
while @curr.value >= 48 && @curr.value <= 57
int = (int*10) + (@curr.value - 48)
@curr += 1
end
@curr += 1 unless @curr.value == 0
return int
end
end
ptr = "2015-05-01 13:10:01.23442-07".cstr
td = TimeDecoder.new
td2 = TimeDecoderNew.new
p td.decode(ptr)
p td2.decode(ptr)
n = 1_000_000
Benchmark.bm do |x|
x.report("orig") { n.times { td.decode(ptr) }}
x.report("new") { n.times { td2.decode(ptr) }}
end
2015-05-01 20:10:01 UTC
2015-05-01 20:10:01 UTC
user system total real
orig 9.850000 1.620000 11.470000 ( 9.641641)
new 0.050000 0.000000 0.050000 ( 0.054071)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment