Ruby Time#to_json as a float










0















Ruby's json library defaults to converting Time objects to Strings



require 'json'
Time.at(1000).utc.to_json # => ""1970-01-01 00:16:40 UTC""


The problem with this is that we lose precision. I'd like to_json to produce a float instead.



I also know there are some workarounds using oj or requiring json/add/time, but both of these add excess data to the output and aren't the most portable.



A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes



class Time
def to_json(*a)
self.to_f.to_json(*a)
end
end


Are there any better approaches?










share|improve this question






















  • If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

    – engineersmnky
    Nov 13 '18 at 21:45
















0















Ruby's json library defaults to converting Time objects to Strings



require 'json'
Time.at(1000).utc.to_json # => ""1970-01-01 00:16:40 UTC""


The problem with this is that we lose precision. I'd like to_json to produce a float instead.



I also know there are some workarounds using oj or requiring json/add/time, but both of these add excess data to the output and aren't the most portable.



A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes



class Time
def to_json(*a)
self.to_f.to_json(*a)
end
end


Are there any better approaches?










share|improve this question






















  • If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

    – engineersmnky
    Nov 13 '18 at 21:45














0












0








0








Ruby's json library defaults to converting Time objects to Strings



require 'json'
Time.at(1000).utc.to_json # => ""1970-01-01 00:16:40 UTC""


The problem with this is that we lose precision. I'd like to_json to produce a float instead.



I also know there are some workarounds using oj or requiring json/add/time, but both of these add excess data to the output and aren't the most portable.



A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes



class Time
def to_json(*a)
self.to_f.to_json(*a)
end
end


Are there any better approaches?










share|improve this question














Ruby's json library defaults to converting Time objects to Strings



require 'json'
Time.at(1000).utc.to_json # => ""1970-01-01 00:16:40 UTC""


The problem with this is that we lose precision. I'd like to_json to produce a float instead.



I also know there are some workarounds using oj or requiring json/add/time, but both of these add excess data to the output and aren't the most portable.



A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes



class Time
def to_json(*a)
self.to_f.to_json(*a)
end
end


Are there any better approaches?







json ruby






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 20:15









jessebsjessebs

444311




444311












  • If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

    – engineersmnky
    Nov 13 '18 at 21:45


















  • If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

    – engineersmnky
    Nov 13 '18 at 21:45

















If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

– engineersmnky
Nov 13 '18 at 21:45






If you really want a float then Time#to_f will return a float for you. or even BigDecimal.new(Time.at(1000.123456).to_r,24).to_s('24F').to_json if the yoctosecond precision is really important

– engineersmnky
Nov 13 '18 at 21:45













2 Answers
2






active

oldest

votes


















3















A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes




There's no JSON format for dates, as far as JSON cares they're just strings. Most languages understand ISO 8601, and that's what Time#to_json produces. So long as Time#to_json continues to produce an ISO 8601 datetime you'll remain backwards compatible.



require 'json'
require 'time' # for Time#iso8601 and Time.parse

class Time
def to_json
return self.iso8601(6).to_json
end
end

time = Time.at(1000.123456)
puts "Before: #time.iso8601(6)"

json_time = Time.at(1000.123456).to_json
puts "As JSON: #json_time"

# Demonstrate round tripping.
puts "Round trip: #Time.parse(JSON.parse(json_time)).iso8601(6)"




Before: 1969-12-31T16:16:40.123456-08:00
As JSON: "1969-12-31T16:16:40.123456-08:00"
Round trip: 1969-12-31T16:16:40.123456-08:00



If you're not comfortable with monkey patching globally, you can monkey patch in isolation by implementing around.



class Time
require 'time'
require 'json'

def precise_to_json(*args)
return iso8601(6).to_json(*args)
end

alias_method :original_to_json, :to_json
end

module PreciseJson
def self.around
# Swap in our precise_to_json as Time#to_json
Time.class_eval
alias_method :to_json, :precise_to_json


# This block will use Time#precise_to_json as Time#to_json
yield

# Always put the original Time#to_json back.
ensure
Time.class_eval
alias_method :to_json, :original_to_json

end
end

obj =
time: Time.at(1000.123456),
string: "Basset Hounds Got Long Ears"


puts "Before: #obj.to_json"

PreciseJson.around
puts "Around: #obj.to_json"


puts "After: #obj.to_json"

begin
PreciseJson.around
raise Exception

rescue Exception
end

puts "After exception: #obj.to_json"




Before: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
Around: "time":"1969-12-31T16:16:40.123456-08:00","string":"Basset Hounds Got Long Ears"
After: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
After exception: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"





share|improve this answer

























  • Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

    – jessebs
    Nov 13 '18 at 20:42











  • @jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

    – Schwern
    Nov 13 '18 at 21:28












  • @jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

    – engineersmnky
    Nov 13 '18 at 21:31











  • Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

    – Cary Swoveland
    Nov 15 '18 at 22:19











  • @CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

    – Schwern
    Nov 15 '18 at 22:27



















0














You could save the number of nanoseconds since the Epoch.



require 'time'
require 'json'

t = Time.now
#=> 2018-11-13 13:23:32 -0800
json = [t.to_i, t.nsec].to_json
#=> "[1542144212,883611300]"

secs, nsecs = JSON.parse(json)
#=> [1542144212, 883611300]
r = secs + 10**-9 * nsecs
#=> (15421442128836113/10000000)
tt = Time.at r
#=> 2018-11-13 13:23:32 -0800

t == tt
#=> true


Note (10**-9).class #=> Rational.






share|improve this answer




















  • 1





    require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

    – engineersmnky
    Nov 13 '18 at 22:06











  • @engineersmnky, that's very cool! I'll do an edit. Thanks.

    – Cary Swoveland
    Nov 13 '18 at 22:14






  • 1





    It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

    – engineersmnky
    Nov 13 '18 at 22:36












  • I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

    – jessebs
    Nov 15 '18 at 21:28











  • jessebs, I missed that, so rolled back to my original answer.

    – Cary Swoveland
    Nov 15 '18 at 21:45










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288831%2fruby-timeto-json-as-a-float%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









3















A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes




There's no JSON format for dates, as far as JSON cares they're just strings. Most languages understand ISO 8601, and that's what Time#to_json produces. So long as Time#to_json continues to produce an ISO 8601 datetime you'll remain backwards compatible.



require 'json'
require 'time' # for Time#iso8601 and Time.parse

class Time
def to_json
return self.iso8601(6).to_json
end
end

time = Time.at(1000.123456)
puts "Before: #time.iso8601(6)"

json_time = Time.at(1000.123456).to_json
puts "As JSON: #json_time"

# Demonstrate round tripping.
puts "Round trip: #Time.parse(JSON.parse(json_time)).iso8601(6)"




Before: 1969-12-31T16:16:40.123456-08:00
As JSON: "1969-12-31T16:16:40.123456-08:00"
Round trip: 1969-12-31T16:16:40.123456-08:00



If you're not comfortable with monkey patching globally, you can monkey patch in isolation by implementing around.



class Time
require 'time'
require 'json'

def precise_to_json(*args)
return iso8601(6).to_json(*args)
end

alias_method :original_to_json, :to_json
end

module PreciseJson
def self.around
# Swap in our precise_to_json as Time#to_json
Time.class_eval
alias_method :to_json, :precise_to_json


# This block will use Time#precise_to_json as Time#to_json
yield

# Always put the original Time#to_json back.
ensure
Time.class_eval
alias_method :to_json, :original_to_json

end
end

obj =
time: Time.at(1000.123456),
string: "Basset Hounds Got Long Ears"


puts "Before: #obj.to_json"

PreciseJson.around
puts "Around: #obj.to_json"


puts "After: #obj.to_json"

begin
PreciseJson.around
raise Exception

rescue Exception
end

puts "After exception: #obj.to_json"




Before: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
Around: "time":"1969-12-31T16:16:40.123456-08:00","string":"Basset Hounds Got Long Ears"
After: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
After exception: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"





share|improve this answer

























  • Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

    – jessebs
    Nov 13 '18 at 20:42











  • @jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

    – Schwern
    Nov 13 '18 at 21:28












  • @jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

    – engineersmnky
    Nov 13 '18 at 21:31











  • Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

    – Cary Swoveland
    Nov 15 '18 at 22:19











  • @CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

    – Schwern
    Nov 15 '18 at 22:27
















3















A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes




There's no JSON format for dates, as far as JSON cares they're just strings. Most languages understand ISO 8601, and that's what Time#to_json produces. So long as Time#to_json continues to produce an ISO 8601 datetime you'll remain backwards compatible.



require 'json'
require 'time' # for Time#iso8601 and Time.parse

class Time
def to_json
return self.iso8601(6).to_json
end
end

time = Time.at(1000.123456)
puts "Before: #time.iso8601(6)"

json_time = Time.at(1000.123456).to_json
puts "As JSON: #json_time"

# Demonstrate round tripping.
puts "Round trip: #Time.parse(JSON.parse(json_time)).iso8601(6)"




Before: 1969-12-31T16:16:40.123456-08:00
As JSON: "1969-12-31T16:16:40.123456-08:00"
Round trip: 1969-12-31T16:16:40.123456-08:00



If you're not comfortable with monkey patching globally, you can monkey patch in isolation by implementing around.



class Time
require 'time'
require 'json'

def precise_to_json(*args)
return iso8601(6).to_json(*args)
end

alias_method :original_to_json, :to_json
end

module PreciseJson
def self.around
# Swap in our precise_to_json as Time#to_json
Time.class_eval
alias_method :to_json, :precise_to_json


# This block will use Time#precise_to_json as Time#to_json
yield

# Always put the original Time#to_json back.
ensure
Time.class_eval
alias_method :to_json, :original_to_json

end
end

obj =
time: Time.at(1000.123456),
string: "Basset Hounds Got Long Ears"


puts "Before: #obj.to_json"

PreciseJson.around
puts "Around: #obj.to_json"


puts "After: #obj.to_json"

begin
PreciseJson.around
raise Exception

rescue Exception
end

puts "After exception: #obj.to_json"




Before: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
Around: "time":"1969-12-31T16:16:40.123456-08:00","string":"Basset Hounds Got Long Ears"
After: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
After exception: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"





share|improve this answer

























  • Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

    – jessebs
    Nov 13 '18 at 20:42











  • @jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

    – Schwern
    Nov 13 '18 at 21:28












  • @jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

    – engineersmnky
    Nov 13 '18 at 21:31











  • Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

    – Cary Swoveland
    Nov 15 '18 at 22:19











  • @CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

    – Schwern
    Nov 15 '18 at 22:27














3












3








3








A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes




There's no JSON format for dates, as far as JSON cares they're just strings. Most languages understand ISO 8601, and that's what Time#to_json produces. So long as Time#to_json continues to produce an ISO 8601 datetime you'll remain backwards compatible.



require 'json'
require 'time' # for Time#iso8601 and Time.parse

class Time
def to_json
return self.iso8601(6).to_json
end
end

time = Time.at(1000.123456)
puts "Before: #time.iso8601(6)"

json_time = Time.at(1000.123456).to_json
puts "As JSON: #json_time"

# Demonstrate round tripping.
puts "Round trip: #Time.parse(JSON.parse(json_time)).iso8601(6)"




Before: 1969-12-31T16:16:40.123456-08:00
As JSON: "1969-12-31T16:16:40.123456-08:00"
Round trip: 1969-12-31T16:16:40.123456-08:00



If you're not comfortable with monkey patching globally, you can monkey patch in isolation by implementing around.



class Time
require 'time'
require 'json'

def precise_to_json(*args)
return iso8601(6).to_json(*args)
end

alias_method :original_to_json, :to_json
end

module PreciseJson
def self.around
# Swap in our precise_to_json as Time#to_json
Time.class_eval
alias_method :to_json, :precise_to_json


# This block will use Time#precise_to_json as Time#to_json
yield

# Always put the original Time#to_json back.
ensure
Time.class_eval
alias_method :to_json, :original_to_json

end
end

obj =
time: Time.at(1000.123456),
string: "Basset Hounds Got Long Ears"


puts "Before: #obj.to_json"

PreciseJson.around
puts "Around: #obj.to_json"


puts "After: #obj.to_json"

begin
PreciseJson.around
raise Exception

rescue Exception
end

puts "After exception: #obj.to_json"




Before: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
Around: "time":"1969-12-31T16:16:40.123456-08:00","string":"Basset Hounds Got Long Ears"
After: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
After exception: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"





share|improve this answer
















A straightforward approach is to monkey patch Time, although I'm not fond of doing that, especially to core classes




There's no JSON format for dates, as far as JSON cares they're just strings. Most languages understand ISO 8601, and that's what Time#to_json produces. So long as Time#to_json continues to produce an ISO 8601 datetime you'll remain backwards compatible.



require 'json'
require 'time' # for Time#iso8601 and Time.parse

class Time
def to_json
return self.iso8601(6).to_json
end
end

time = Time.at(1000.123456)
puts "Before: #time.iso8601(6)"

json_time = Time.at(1000.123456).to_json
puts "As JSON: #json_time"

# Demonstrate round tripping.
puts "Round trip: #Time.parse(JSON.parse(json_time)).iso8601(6)"




Before: 1969-12-31T16:16:40.123456-08:00
As JSON: "1969-12-31T16:16:40.123456-08:00"
Round trip: 1969-12-31T16:16:40.123456-08:00



If you're not comfortable with monkey patching globally, you can monkey patch in isolation by implementing around.



class Time
require 'time'
require 'json'

def precise_to_json(*args)
return iso8601(6).to_json(*args)
end

alias_method :original_to_json, :to_json
end

module PreciseJson
def self.around
# Swap in our precise_to_json as Time#to_json
Time.class_eval
alias_method :to_json, :precise_to_json


# This block will use Time#precise_to_json as Time#to_json
yield

# Always put the original Time#to_json back.
ensure
Time.class_eval
alias_method :to_json, :original_to_json

end
end

obj =
time: Time.at(1000.123456),
string: "Basset Hounds Got Long Ears"


puts "Before: #obj.to_json"

PreciseJson.around
puts "Around: #obj.to_json"


puts "After: #obj.to_json"

begin
PreciseJson.around
raise Exception

rescue Exception
end

puts "After exception: #obj.to_json"




Before: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
Around: "time":"1969-12-31T16:16:40.123456-08:00","string":"Basset Hounds Got Long Ears"
After: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"
After exception: "time":"1969-12-31 16:16:40 -0800","string":"Basset Hounds Got Long Ears"






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 13 '18 at 21:27

























answered Nov 13 '18 at 20:40









SchwernSchwern

89.2k17102232




89.2k17102232












  • Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

    – jessebs
    Nov 13 '18 at 20:42











  • @jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

    – Schwern
    Nov 13 '18 at 21:28












  • @jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

    – engineersmnky
    Nov 13 '18 at 21:31











  • Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

    – Cary Swoveland
    Nov 15 '18 at 22:19











  • @CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

    – Schwern
    Nov 15 '18 at 22:27


















  • Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

    – jessebs
    Nov 13 '18 at 20:42











  • @jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

    – Schwern
    Nov 13 '18 at 21:28












  • @jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

    – engineersmnky
    Nov 13 '18 at 21:31











  • Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

    – Cary Swoveland
    Nov 15 '18 at 22:19











  • @CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

    – Schwern
    Nov 15 '18 at 22:27

















Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

– jessebs
Nov 13 '18 at 20:42





Thanks. Great point and iso8601 is probably a good way for me to go. That's still modifying the Time class, though. Any thoughts on avoiding that?

– jessebs
Nov 13 '18 at 20:42













@jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

– Schwern
Nov 13 '18 at 21:28






@jessebs You need to monkey patch for it to work on Time objects embedded in other objects. You could use refinements but they're lexical in scope and so don't recurse into obj.to_json. The alternative is to implement around to only monkey patch for a certain block of code. I've updated the answer to demonstrate.

– Schwern
Nov 13 '18 at 21:28














@jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

– engineersmnky
Nov 13 '18 at 21:31





@jessebs it is really not an issue in this case. The Time class does not have a specific to_json method so it falls back to Object#to_json which is just the to_s representation as shown Here so patching it in really has no specific impact although the signature should probably be to_json(*) to remain consistent with all other implementations. However you could just use Time.at(1000.123456).strftime("%Y-%m-%dT%H:%M:%S.%6N%z").to_json

– engineersmnky
Nov 13 '18 at 21:31













Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

– Cary Swoveland
Nov 15 '18 at 22:19





Very interesting. You may wish to make DateTime#iso8601's argument equal to 9, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I execute Time.now.nsec I get 7 significant digits (Bash on Ubuntu on Windows 10). You can shorten return self.iso8601(6).to_json to iso8601(6).to_json. (I'm sure you know that. I'm guessing you probably spend most of your time these days working with a language other than Ruby.)

– Cary Swoveland
Nov 15 '18 at 22:19













@CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

– Schwern
Nov 15 '18 at 22:27






@CarySwoveland Thanks for the notes. I spend most of my time in Ruby now. I largely left the particular details of Time#to_json to the OP (microseconds seemed safe) and focused on making it work transparently and recursively without a global monkey patch. I do occasionally get bit by foo not being equivalent to self.foo, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with the around implementation and might generalize it and turn it into a library.

– Schwern
Nov 15 '18 at 22:27














0














You could save the number of nanoseconds since the Epoch.



require 'time'
require 'json'

t = Time.now
#=> 2018-11-13 13:23:32 -0800
json = [t.to_i, t.nsec].to_json
#=> "[1542144212,883611300]"

secs, nsecs = JSON.parse(json)
#=> [1542144212, 883611300]
r = secs + 10**-9 * nsecs
#=> (15421442128836113/10000000)
tt = Time.at r
#=> 2018-11-13 13:23:32 -0800

t == tt
#=> true


Note (10**-9).class #=> Rational.






share|improve this answer




















  • 1





    require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

    – engineersmnky
    Nov 13 '18 at 22:06











  • @engineersmnky, that's very cool! I'll do an edit. Thanks.

    – Cary Swoveland
    Nov 13 '18 at 22:14






  • 1





    It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

    – engineersmnky
    Nov 13 '18 at 22:36












  • I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

    – jessebs
    Nov 15 '18 at 21:28











  • jessebs, I missed that, so rolled back to my original answer.

    – Cary Swoveland
    Nov 15 '18 at 21:45















0














You could save the number of nanoseconds since the Epoch.



require 'time'
require 'json'

t = Time.now
#=> 2018-11-13 13:23:32 -0800
json = [t.to_i, t.nsec].to_json
#=> "[1542144212,883611300]"

secs, nsecs = JSON.parse(json)
#=> [1542144212, 883611300]
r = secs + 10**-9 * nsecs
#=> (15421442128836113/10000000)
tt = Time.at r
#=> 2018-11-13 13:23:32 -0800

t == tt
#=> true


Note (10**-9).class #=> Rational.






share|improve this answer




















  • 1





    require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

    – engineersmnky
    Nov 13 '18 at 22:06











  • @engineersmnky, that's very cool! I'll do an edit. Thanks.

    – Cary Swoveland
    Nov 13 '18 at 22:14






  • 1





    It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

    – engineersmnky
    Nov 13 '18 at 22:36












  • I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

    – jessebs
    Nov 15 '18 at 21:28











  • jessebs, I missed that, so rolled back to my original answer.

    – Cary Swoveland
    Nov 15 '18 at 21:45













0












0








0







You could save the number of nanoseconds since the Epoch.



require 'time'
require 'json'

t = Time.now
#=> 2018-11-13 13:23:32 -0800
json = [t.to_i, t.nsec].to_json
#=> "[1542144212,883611300]"

secs, nsecs = JSON.parse(json)
#=> [1542144212, 883611300]
r = secs + 10**-9 * nsecs
#=> (15421442128836113/10000000)
tt = Time.at r
#=> 2018-11-13 13:23:32 -0800

t == tt
#=> true


Note (10**-9).class #=> Rational.






share|improve this answer















You could save the number of nanoseconds since the Epoch.



require 'time'
require 'json'

t = Time.now
#=> 2018-11-13 13:23:32 -0800
json = [t.to_i, t.nsec].to_json
#=> "[1542144212,883611300]"

secs, nsecs = JSON.parse(json)
#=> [1542144212, 883611300]
r = secs + 10**-9 * nsecs
#=> (15421442128836113/10000000)
tt = Time.at r
#=> 2018-11-13 13:23:32 -0800

t == tt
#=> true


Note (10**-9).class #=> Rational.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 15 '18 at 21:44

























answered Nov 13 '18 at 21:30









Cary SwovelandCary Swoveland

68.8k54065




68.8k54065







  • 1





    require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

    – engineersmnky
    Nov 13 '18 at 22:06











  • @engineersmnky, that's very cool! I'll do an edit. Thanks.

    – Cary Swoveland
    Nov 13 '18 at 22:14






  • 1





    It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

    – engineersmnky
    Nov 13 '18 at 22:36












  • I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

    – jessebs
    Nov 15 '18 at 21:28











  • jessebs, I missed that, so rolled back to my original answer.

    – Cary Swoveland
    Nov 15 '18 at 21:45












  • 1





    require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

    – engineersmnky
    Nov 13 '18 at 22:06











  • @engineersmnky, that's very cool! I'll do an edit. Thanks.

    – Cary Swoveland
    Nov 13 '18 at 22:14






  • 1





    It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

    – engineersmnky
    Nov 13 '18 at 22:36












  • I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

    – jessebs
    Nov 15 '18 at 21:28











  • jessebs, I missed that, so rolled back to my original answer.

    – Cary Swoveland
    Nov 15 '18 at 21:45







1




1





require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

– engineersmnky
Nov 13 '18 at 22:06





require 'json/add/time' then Time.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000" where s is seconds and n is nanoseconds

– engineersmnky
Nov 13 '18 at 22:06













@engineersmnky, that's very cool! I'll do an edit. Thanks.

– Cary Swoveland
Nov 13 '18 at 22:14





@engineersmnky, that's very cool! I'll do an edit. Thanks.

– Cary Swoveland
Nov 13 '18 at 22:14




1




1





It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

– engineersmnky
Nov 13 '18 at 22:36






It also adds Time::json_create so th= JSON.parse(Time.now.to_json); t= Object.const_get(th.delete("json_class")).json_create(th)

– engineersmnky
Nov 13 '18 at 22:36














I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

– jessebs
Nov 15 '18 at 21:28





I mentioned wanting to avoid json/add/time in the original question. It makes json parsing between languages more difficult

– jessebs
Nov 15 '18 at 21:28













jessebs, I missed that, so rolled back to my original answer.

– Cary Swoveland
Nov 15 '18 at 21:45





jessebs, I missed that, so rolled back to my original answer.

– Cary Swoveland
Nov 15 '18 at 21:45

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53288831%2fruby-timeto-json-as-a-float%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Barbados

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3