In the year 2525

Is there a reason why Time.local can’t handle dates beyond 2038? I know
that’s when the number of second since 1970 exceeds 2^32, but can’t a
big, strong language like Ruby handle it?

irb(main):004:0> Time.local(2038)
=> Fri Jan 01 00:00:00 Pacific Standard Time 2038

irb(main):005:0> Time.local(2039)
ArgumentError: time out of range
from (irb):5:in `local’
from (irb):5

Jim v. Tess wrote:

Is there a reason why Time.local can’t handle dates beyond 2038? I know
that’s when the number of second since 1970 exceeds 2^32, but can’t a
big, strong language like Ruby handle it?

Because it uses the underlying platform’s time manipulation functions?
(Disclaimer: That’s a wild guess.) No point reinventing the wheel in
Ruby. The numbercrunching to process Unix timestamps would probably be
rather sluggish done in Ruby if done in large quantities - and dates /
times are a rather common datatype you need to handle.

Mebbe hack around the issue by providing Ruby replacements for large
timestamps? Then again, maybe that’s what the Date / DateTime classes
do. Buggered if I know, I could never remember which one did what.

David V.

On Sat, 7 Oct 2006, David V. wrote:

Jim v. Tess wrote:

Is there a reason why Time.local can’t handle dates beyond 2038? I know
that’s when the number of second since 1970 exceeds 2^32, but can’t a
big, strong language like Ruby handle it?

Because it uses the underlying platform’s time manipulation functions?

Yes.

Mebbe hack around the issue by providing Ruby replacements for large
timestamps? Then again, maybe that’s what the Date / DateTime classes
do. Buggered if I know, I could never remember which one did what.

Yes. DateTime uses Rational to represent time. 1 represents a day, not
a
second. It can be used with arbitrary dates well outside the range of
Time, but it is MUCH slower. Use Time everywhere one can.

Kirk H.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bill K. wrote:

range of Time, but it is MUCH slower. Use Time everywhere one can.
into a badass DateTime that could handle dinosaurs, and big bangs, etc.?
Furthermore, what about automatic Float -> BigDecimal conversion?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFFJ1FymV9O7RYnKMcRAkU/AKCRnJbfT6yq2kl/TXa2PD77kVEoxgCfVkZH
uZBiltQMjjiPdB2wgNFwDPU=
=mXTx
-----END PGP SIGNATURE-----

From: [email protected]

Yes.

Mebbe hack around the issue by providing Ruby replacements for large
timestamps? Then again, maybe that’s what the Date / DateTime classes
do. Buggered if I know, I could never remember which one did what.

Yes. DateTime uses Rational to represent time. 1 represents a day, not a
second. It can be used with arbitrary dates well outside the range of
Time, but it is MUCH slower. Use Time everywhere one can.

DateTime sounds nice. As cool as ruby’s automatic Fixnum → Bignum
auto-conversions are, one imagines a date where even someone learning
ruby might be able to specify “puts 2**256” (can already), or
Date.years_ago( -13_700_000_000 ).to_s
=> “Big Bang”

Is it not theoretically possible to make a “fixnum->bignum-like Date”,
where it would be fast until its precision was exceeded? Then morph
into a badass DateTime that could handle dinosaurs, and big bangs,
etc.?

With Respect,

Bill

Jim v. Tess:

irb(main):004:0> Time.local(2038)
=> Fri Jan 01 00:00:00 Pacific Standard Time 2038

irb(main):005:0> Time.local(2039)
ArgumentError: time out of range
from (irb):5:in `local’
from (irb):5

Never rely on future times…

irb> RUBY_PLATFORM
=> “x86_64-linux”

irb> Time.local(231-1)
=> Tue Jan 01 00:00:00 CET 2147483647
irb> Time.local(2
31)
=> Wed Jan 01 00:00:00 CET -2147483648

irb> n = 2147485547
=> 2147485547
irb> Time.local(n)
=> Wed Jan 01 00:00:00 CET -2147481749
irb> Time.local(n+1)
ArgumentError: argument out of range
from (irb):70:in `local’
from (irb):70
from :0

Kalman

Suraj N. Kurapati wrote:

Furthermore, what about automatic Float -> BigDecimal conversion?

Wouldn’t that only be possible if the processor reports if an IEEE
floating-point conversion / operation was inprecise / innacurate (can’t
for the heck of it remember which term applies here.)

Even if that was the case, that means that say a floating point division
would take would take one attempt, report that, convert the floating
point numbers to BigDecimals, and then perform the division in Ruby.
This isn’t something I’d like happening in code even casually working
with floating point numbers for performance reasons. Though it’s a valid
Shiny Thing to put as an optional mode of operation.

David V.

David V. wrote:

Jim v. Tess wrote:

Is there a reason why Time.local can’t handle dates beyond 2038? I know
that’s when the number of second since 1970 exceeds 2^32, but can’t a
big, strong language like Ruby handle it?

Because it uses the underlying platform’s time manipulation functions?

And brings interesting portability issues (not only for ruby).

$ irb

RUBY_PLATFORM
=> “x86_64-linux”

Time.local(2525)
=> Mon Jan 01 00:00:00 GMT 2525

David V. wrote:

Suraj N. Kurapati wrote:

Furthermore, what about automatic Float -> BigDecimal conversion?

Wouldn’t that only be possible if the processor reports if an IEEE
floating-point conversion / operation was inprecise / innacurate (can’t
for the heck of it remember which term applies here.)

Even if that was the case, that means that say a floating point division
would take would take one attempt, report that, convert the floating
point numbers to BigDecimals, and then perform the division in Ruby.

I think that basically every operation on a number which doesn’t have
a natural writing in base 2 would trigger the conversion. That is,
unless you do 2 * 0.5, you’ll switch automatically to BigDecimal. Bad
idea. Why don’t you use BigDecimal systematically, if you’re really
worried about precision ?

Cheers !

Vince

Suraj N. Kurapati wrote:

Well, manually applying BigDecimal wherever necessary for
performance reasons feels like programming in C (remember floats and
doubles? /me vomits).

Yes, but there’s performance losses, and performance losses. For the
fixnum -> bignum conversion, there’s a whole of two cutover numbers
where you have to convert from one to the other. For a Float ->
BigDecimal conversion, there’s probably an infinity of them.

Also:


require ‘bigdecimal’
require ‘benchmark’

N = 1000000

Benchmark.bmbm { |test|
test.report(“Float”) {
for i in 1…N
Math::PI / Math::E
end
}

test.report("BigDecimal") {
    for i in 1..N
        BigDecimal.new(String(Math::PI)) /
    BigDecimal(String(Math::E))
    end
}

}


Rehearsal ----------------------------------------------
Float 0.937000 0.000000 0.937000 ( 0.969000)
BigDecimal 30.594000 0.093000 30.687000 ( 30.922000)
------------------------------------ total: 31.624000sec

             user     system      total        real

Float 1.031000 0.000000 1.031000 ( 1.015000)
BigDecimal 30.453000 0.078000 30.531000 ( 30.766000)


That’s a slowdown by a factor of 30. Which means simple decimal maths in
Ruby could be slower by at least a factor of 20 on average by my wild
guess. That’s without the overhead of verifying if the result of a maths
operation can be represented in IEEE floats. Besides, even BigDecimals
lose precision eventually, and they don’t have nearly as many use cases
as either arbitrary-size integers (that help prevent counter overflows),
or fast floating-point maths.

For a more “interesting” benchmark, let’s see less trivial number
crunching.


require ‘bigdecimal’
require ‘bigdecimal/math’
require ‘benchmark’

N = 100000

include BigMath

Benchmark.bmbm { |test|
test.report(“Float”) {
for i in 1…N
Math.log(Math::PI) / Math.log(Math::E)
end
}

test.report("BigDecimal") {
    for i in 1..N
        log(BigDecimal(String(Math::PI)), 20) /

log(BigDecimal(String(Math::E)), 20)
end
}
}


Rehearsal ----------------------------------------------
Float 0.172000 0.000000 0.172000 ( 0.203000)
BigDecimal 278.641000 0.656000 279.297000 (279.422000)
----------------------------------- total: 279.469000sec

             user     system      total        real

Float 0.218000 0.000000 0.218000 ( 0.203000)
BigDecimal 276.266000 0.625000 276.891000 (286.234000)


That’s a slowdown by a factor of roughly 1267… I don’t need profiling
to see this would kill even casual use of nontrivial amounts of
numbercrunching.

I don’t care so much about performance; rather, I want to write code
quickly and elegantly using conceptual abstractions. If I really
need performance, I will profile the code and re-write the slow
parts in C.

Which turns your proposal into “Let’s make Ruby behave not like C,
crippling speed, so that everyone ends up rewriting maths code in C”. I
fail to see the gain. As I said, the automagical conversion is somewhere
on my list of Potential Shiny Things. I doubt it’s an essential feature
for, well, anyone. And it would be actively harmful to make it default
behaviour, or ever alter the behaviour to this in a library released
into the wild.

David V.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Vincent F. wrote:

I think that basically every operation on a number which doesn’t have
a natural writing in base 2 would trigger the conversion. That is,
unless you do 2 * 0.5, you’ll switch automatically to BigDecimal. Bad
idea. Why don’t you use BigDecimal systematically, if you’re really
worried about precision ?

Well, manually applying BigDecimal wherever necessary for
performance reasons feels like programming in C (remember floats and
doubles? /me vomits).

When I was learning Ruby, I absolutely loved the fact that Fixnum
automatically spills into Bignum and vice versa… good riddance to
short, int, long, and long long! Just think of how beneficial this
conceptual abstraction (I don’t care how many bits it occupies, I
just want to use this integer!) has been to your code and mode of
thinking. If Ruby didn’t have this, we would be manually checking
sizes, upcasting, and downcasting Fixnums and Bignums everywhere. :frowning:

I don’t care so much about performance; rather, I want to write code
quickly and elegantly using conceptual abstractions. If I really
need performance, I will profile the code and re-write the slow
parts in C.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFFJ8ZvmV9O7RYnKMcRAi5NAJ47Kby2Bo6OaZU2LWBeEJ8iJ9Sh+wCcDzqz
eAlA7MMIlci1VyaBmojAcL8=
=A4po
-----END PGP SIGNATURE-----

Suraj N. Kurapati wrote:

I don’t care so much about performance; rather, I want to write code
quickly and elegantly using conceptual abstractions. If I really
need performance, I will profile the code and re-write the slow
parts in C.

I completely agree with this approach. However, you will find that you
can’t have floats that behave the way you would like… For
Fixnum/Bignum the deal is really simple: when something goes too big,
you switch from one to the other. Simply because if not, you get an
arithmetic overflow. But for floats, it is completely different. I don’t
think you’ll ever get a too big float (do you often manipulate numbers
over 10300 or below 10-300 ?). But if you want to switch to
BigDecimals when you lose precision, then you should do it from the
beginning, because unless you compute with numbers in base 2, you always
lose precision with a float operation…

So my answer is: use BigDecimals, if you’re worried about precision
(but that still will not take care of all the problems; maybe Rationnal
is what you’re looking for ?).

Cheers !

Vince

PS: yes, I know it sucks to have to take care manually of the things in
C…

Charles Oliver N. wrote:

It works in JRuby…would that be considered an incompatibility, or is
it an ok diversion from the C impl?

irb(main):001:0> Time.local(2038)
=> Fri Jan 01 00:00:00 CST 2038
irb(main):002:0> Time.local(2039)
=> Sat Jan 01 00:00:00 CST 2039
irb(main):003:0> Time.local(10191)
=> Sat Jan 01 00:00:00 CST 10191

In light of the x86_64 responses, I’d wager it’s ok :slight_smile: I don’t know what
the performance is like, though, for Java’s Date compared to the POSIX
calls.

Jim v. Tess wrote:

Is there a reason why Time.local can’t handle dates beyond 2038? I know
that’s when the number of second since 1970 exceeds 2^32, but can’t a
big, strong language like Ruby handle it?

It works in JRuby…would that be considered an incompatibility, or is
it an ok diversion from the C impl?

irb(main):001:0> Time.local(2038)
=> Fri Jan 01 00:00:00 CST 2038
irb(main):002:0> Time.local(2039)
=> Sat Jan 01 00:00:00 CST 2039
irb(main):003:0> Time.local(10191)
=> Sat Jan 01 00:00:00 CST 10191

Hi,

In message “Re: In the year 2525”
on Sun, 8 Oct 2006 03:16:40 +0900, Charles Oliver N.
[email protected] writes:

|Jim v. Tess wrote:
|> Is there a reason why Time.local can’t handle dates beyond 2038? I know
|> that’s when the number of second since 1970 exceeds 2^32, but can’t a
|> big, strong language like Ruby handle it?
|
|It works in JRuby…would that be considered an incompatibility, or is
|it an ok diversion from the C impl?

I think it is an OK diversion.

						matz.

On Sun, 8 Oct 2006, Yukihiro M. wrote:

|It works in JRuby…would that be considered an incompatibility, or is
|it an ok diversion from the C impl?

I think it is an OK diversion.

you’ll put us all out of work matz - think of all the contracts in 2037!

-a

Hi –

On Sun, 8 Oct 2006, Yukihiro M. wrote:

|It works in JRuby…would that be considered an incompatibility, or is
|it an ok diversion from the C impl?

I think it is an OK diversion.

It’s definitely an incompatibility, though, in the sense that it has
the potential to create a category of programs that will run under
JRuby but not (original) Ruby.

David

[email protected] wrote:

On Sun, 8 Oct 2006, Yukihiro M. wrote:

|It works in JRuby…would that be considered an incompatibility, or is
|it an ok diversion from the C impl?

I think it is an OK diversion.

you’ll put us all out of work matz - think of all the contracts in 2037!

-a

Ah, but that assumes people will still be using 32-bit machines then. I
don’t know if I’ll be around to collect, but I’d bet a tidy sum that the
“default” home computer in 2030 will be a 128-bit multicore machine.

I’m not willing to predict how much RAM or disk space it will have, or
what the operating systems, programming languages and applications will
look like. But just like the supercomputers of the mid-1980s are dwarfed
by today’s laptops, I don’t think it’s a stretch to think that 20 years
from now, the laptops will dwarf today’s supercomputers.

I guess I need to take good care of myself. :slight_smile:

From: [email protected]

It’s definitely an incompatibility, though, in the sense that it has
the potential to create a category of programs that will run under
JRuby but not (original) Ruby.

I did have a surprise like this, just a couple days ago:

Linux:

$ ruby -ve ‘p Time.now.strftime(“%F %T”)’
ruby 1.8.4 (2005-12-24) [i686-linux]
“2006-10-07 19:05:01”

Windows:

ruby -ve ‘p Time.now.strftime(“%F %T”)’
ruby 1.8.4 (2005-12-24) [i386-mswin32]
" "

Regards,

Bill

Bill K. wrote:

$ ruby -ve ‘p Time.now.strftime("%F %T")’
ruby 1.8.4 (2005-12-24) [i686-linux]
“2006-10-07 19:05:01”

Windows:

ruby -ve ‘p Time.now.strftime("%F %T")’
ruby 1.8.4 (2005-12-24) [i386-mswin32]
" "

Thanks for the warning.

The moral of the story is trust ri more than man, if you care about
portability:

[~] ri strftime | grep ‘%[FT]’
[~] man strftime | grep ‘%[FT]’
Reformatting strftime(3), please wait…
%F Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)
ing the seconds, see %T below.
%T The time in 24-hour notation (%H:%M:%S). (SU)
%F conversion is in C99 and POSIX 1003.1-2001.