Ruby Time#to_json as a float
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
add a comment |
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
If you really want a float thenTime#to_f
will return a float for you. or evenBigDecimal.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
add a comment |
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
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
json ruby
asked Nov 13 '18 at 20:15
jessebsjessebs
444311
444311
If you really want a float thenTime#to_f
will return a float for you. or evenBigDecimal.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
add a comment |
If you really want a float thenTime#to_f
will return a float for you. or evenBigDecimal.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
add a comment |
2 Answers
2
active
oldest
votes
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"
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 intoobj.to_json
. The alternative is to implementaround
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. TheTime
class does not have a specificto_json
method so it falls back toObject#to_json
which is just theto_s
representation as shown Here so patching it in really has no specific impact although the signature should probably beto_json(*)
to remain consistent with all other implementations. However you could just useTime.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 to9
, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I executeTime.now.nsec
I get7
significant digits (Bash on Ubuntu on Windows 10). You can shortenreturn self.iso8601(6).to_json
toiso8601(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 ofTime#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 byfoo
not being equivalent toself.foo
, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with thearound
implementation and might generalize it and turn it into a library.
– Schwern
Nov 15 '18 at 22:27
add a comment |
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
.
1
require 'json/add/time'
thenTime.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000"
wheres
is seconds andn
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 addsTime::json_create
soth= 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 avoidjson/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
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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"
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 intoobj.to_json
. The alternative is to implementaround
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. TheTime
class does not have a specificto_json
method so it falls back toObject#to_json
which is just theto_s
representation as shown Here so patching it in really has no specific impact although the signature should probably beto_json(*)
to remain consistent with all other implementations. However you could just useTime.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 to9
, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I executeTime.now.nsec
I get7
significant digits (Bash on Ubuntu on Windows 10). You can shortenreturn self.iso8601(6).to_json
toiso8601(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 ofTime#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 byfoo
not being equivalent toself.foo
, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with thearound
implementation and might generalize it and turn it into a library.
– Schwern
Nov 15 '18 at 22:27
add a comment |
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"
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 intoobj.to_json
. The alternative is to implementaround
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. TheTime
class does not have a specificto_json
method so it falls back toObject#to_json
which is just theto_s
representation as shown Here so patching it in really has no specific impact although the signature should probably beto_json(*)
to remain consistent with all other implementations. However you could just useTime.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 to9
, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I executeTime.now.nsec
I get7
significant digits (Bash on Ubuntu on Windows 10). You can shortenreturn self.iso8601(6).to_json
toiso8601(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 ofTime#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 byfoo
not being equivalent toself.foo
, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with thearound
implementation and might generalize it and turn it into a library.
– Schwern
Nov 15 '18 at 22:27
add a comment |
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"
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"
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 intoobj.to_json
. The alternative is to implementaround
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. TheTime
class does not have a specificto_json
method so it falls back toObject#to_json
which is just theto_s
representation as shown Here so patching it in really has no specific impact although the signature should probably beto_json(*)
to remain consistent with all other implementations. However you could just useTime.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 to9
, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I executeTime.now.nsec
I get7
significant digits (Bash on Ubuntu on Windows 10). You can shortenreturn self.iso8601(6).to_json
toiso8601(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 ofTime#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 byfoo
not being equivalent toself.foo
, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with thearound
implementation and might generalize it and turn it into a library.
– Schwern
Nov 15 '18 at 22:27
add a comment |
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 intoobj.to_json
. The alternative is to implementaround
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. TheTime
class does not have a specificto_json
method so it falls back toObject#to_json
which is just theto_s
representation as shown Here so patching it in really has no specific impact although the signature should probably beto_json(*)
to remain consistent with all other implementations. However you could just useTime.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 to9
, to get full precision on numbers of nanoseconds without inspecting numbers of significant digits. When I executeTime.now.nsec
I get7
significant digits (Bash on Ubuntu on Windows 10). You can shortenreturn self.iso8601(6).to_json
toiso8601(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 ofTime#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 byfoo
not being equivalent toself.foo
, possibly variable/method ambiguities, so sometimes I'm conservative. I'm quite happy with thearound
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
add a comment |
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
.
1
require 'json/add/time'
thenTime.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000"
wheres
is seconds andn
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 addsTime::json_create
soth= 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 avoidjson/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
add a comment |
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
.
1
require 'json/add/time'
thenTime.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000"
wheres
is seconds andn
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 addsTime::json_create
soth= 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 avoidjson/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
add a comment |
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
.
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
.
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'
thenTime.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000"
wheres
is seconds andn
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 addsTime::json_create
soth= 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 avoidjson/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
add a comment |
1
require 'json/add/time'
thenTime.now.to_json #=> ""json_class":"Time","s":1542145917,"n":74844000"
wheres
is seconds andn
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 addsTime::json_create
soth= 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 avoidjson/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
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
If you really want a float then
Time#to_f
will return a float for you. or evenBigDecimal.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