Skip to content

Commit

Permalink
Added time:span type
Browse files Browse the repository at this point in the history
  • Loading branch information
crisward committed Jul 18, 2017
1 parent b4fa995 commit 900c346
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
3 changes: 3 additions & 0 deletions spec/db_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ DB::DriverSpecs(MySql::Any).run do
sample_value Time.new(2016, 2, 15), "datetime", "TIMESTAMP '2016-02-15 00:00:00.000'"
sample_value Time.new(2016, 2, 15, 10, 15, 30), "datetime", "TIMESTAMP '2016-02-15 10:15:30.000'"
sample_value Time.new(2016, 2, 15, 10, 15, 30), "timestamp", "TIMESTAMP '2016-02-15 10:15:30.000'"
sample_value Time::Span.new(0), "Time", "TIME('00:00:00')"
sample_value Time::Span.new(10, 25, 21), "Time", "TIME('10:25:21')"
sample_value Time::Span.new(0, 0, 10, 5, 0), "Time", "TIME('00:10:05.000')"

DB.open db_url do |db|
# needs to check version, microsecond support >= 5.7
Expand Down
2 changes: 1 addition & 1 deletion src/mysql.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ module MySql
end
end

alias Any = DB::Any | Int16 | Int8
alias Any = DB::Any | Int16 | Int8 | Time::Span
end
70 changes: 68 additions & 2 deletions src/mysql/types.cr
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ abstract struct MySql::Type
MySql::Type::DateTime
end

def self.type_for(t : ::Time::Span.class)
MySql::Type::Time
end

def self.type_for(t : ::Nil.class)
MySql::Type::Null
end
Expand Down Expand Up @@ -155,8 +159,70 @@ abstract struct MySql::Type
end
decl_type LongLong, 0x08u8, ::Int64
decl_type Int24, 0x09u8
decl_type Date, 0x0au8
decl_type Time, 0x0bu8

def self.datetime_read(packet)
pkt = packet.read_byte!
return ::Time.new(0) if pkt < 1
year = packet.read_fixed_int(2).to_i32
month = packet.read_byte!.to_i32
day = packet.read_byte!.to_i32
return ::Time.new(year, month, day) if pkt < 6
hour = packet.read_byte!.to_i32
minute = packet.read_byte!.to_i32
second = packet.read_byte!.to_i32
return ::Time.new(year, month, day, hour, minute, second) if pkt < 8
ms = packet.read_int.to_i32 / 1000 # returns microseconds, time only supports milliseconds
return ::Time.new(year, month, day, hour, minute, second, ms)
end

def self.datetime_write(packet, v : ::Time)
packet.write_blob UInt8.slice(v.year.to_i16, v.year.to_i16/256, v.month.to_i8, v.day.to_i8, v.hour.to_i8, v.minute.to_i8, v.second.to_i8, v.millisecond*1000, v.millisecond*1000/256, v.millisecond*1000/65536)
end

decl_type Date, 0x0au8, ::Time do
def self.write(packet, v : ::Time)
self.datetime_write(packet, v)
end

def self.read(packet)
self.datetime_read(packet)
end

def self.parse(str : ::String)
raise "TextProtocol::Time not implemented"
end
end
decl_type Time, 0x0bu8, ::Time::Span do
def self.write(packet, v : ::Time::Span)
negative = v.to_i < 0 ? 1 : 0
d = v.days
raise ArgumentError.new("MYSQL TIME over 34 days cannot be saved - https://dev.mysql.com/doc/refman/5.7/en/time.html") if d > 34
packet.write_blob UInt8.slice(negative, d.to_i8, (d >> 8).to_i8, (d >> 16).to_i8, (d >> 24).to_i8, v.hours.to_i8, v.minutes.to_i8, v.seconds.to_i8, v.milliseconds*1000, v.milliseconds*1000/256, v.milliseconds*1000/65536)
end

def self.read(packet)
pkt = packet.read_byte!
return ::Time::Span.new(0) if pkt < 1
negative = packet.read_byte!.to_i32
days = packet.read_fixed_int(4)
hour = packet.read_byte!.to_i32
minute = packet.read_byte!.to_i32
second = packet.read_byte!.to_i32
ms = pkt > 8 ? (packet.read_int.to_i32 / 1000) : nil
time = ms ? ::Time::Span.new(days, hour, minute, second, ms) : ::Time::Span.new(days, hour, minute, second)
negative > 0 ? (::Time::Span.new(0) - time) : time
end

def self.parse(str : ::String)
p "timespan #{str}"
begin
time = ::Time.parse(str, "%H:%M:%S.%L")
rescue
time = ::Time.parse(str, "%H:%M:%S")
end
::Time::Span.new(time.hour, time.minute, time.second)
end
end
decl_type DateTime, 0x0cu8, ::Time do
def self.write(packet, v : ::Time)
packet.write_blob UInt8.slice(v.year.to_i16, v.year.to_i16/256, v.month.to_i8, v.day.to_i8, v.hour.to_i8, v.minute.to_i8, v.second.to_i8, v.millisecond*1000, v.millisecond*1000/256, v.millisecond*1000/65536)
Expand Down

0 comments on commit 900c346

Please sign in to comment.