Error: Bignum too big to convert into `long'

Discussion in 'Ruby' started by Matt Mencel, Aug 9, 2010.

  1. Matt Mencel

    Matt Mencel Guest

    Hi,

    I've got a bit of code that I borrowed from here http://www.ruby-forum.com/topic/77821. I use it to convert MS timestamps into a ruby Time object.
    It works fine on Mac/Linux, but not on a Solaris SPARC system. The error is "bignum too big to convert into `long'" and it occurs on the line that begins...
    Time.at(.....)

    I'm wondering if it's because SPARC is Big-Endian that I get the error?


    def self.ad2time(timestamp)
    ad_epoch = 116_444_736_000_000_000
    ad_multiplier = 10_000_000

    # DEBUG
    ap ad_epoch.class
    puts "TIMESTAMP: #{timestamp}"
    ap timestamp.class

    Time.at((timestamp.to_i - ad_epoch) / ad_multiplier)
    end



    On my Mac (Snow Leopard x86_64) the DEBUG output looks like this...
    Fixnum < Integer
    TIMESTAMP: 9223372036854775807
    Net::BER::BerIdentifiedString < String

    On Solaris SPARC it's this...
    Bignum < Integer
    TIMESTAMP: 9223372036854775807
    String < Object



    Looks like on Solaris it forces the 'ad_epoch' to a Bignum instead of a Fixnum? Should I try to cast it to a Fixnum on Solaris maybe?

    Matt
     
    Matt Mencel, Aug 9, 2010
    #1
    1. Advertisements

  2. Ah, note the x86_64 part? That's a 64-bit system so Fixnum holds up to
    (2^62)-1
    I suspect your SPARC system is only 32-bit where 2^30 and beyond
    becomes Bignum.

    If your timestamp is a Net::BER::BerIdentifiedString, perhaps it has
    other properties that would help convert it into an Integer. (Notice
    that both Fixnum and Bignum are subclasses of Integer)

    On a 32-bit system, the divide between Fixnum and Bignum is:

    irb> 2**30-1
    => 1073741823
    irb> _.class
    => Fixnum
    irb> 2**30
    => 1073741824
    irb> _.class
    => Bignum

    So 910692730085 is far too big for a Fixnum and Time.at is likely
    wanting a number of seconds since 1970. Maybe you can see a pattern
    if you compare Time.now.to_i on your platform with your expected
    timestamp value.

    -Rob

    Rob Biedenharn
    http://AgileConsultingLLC.com/
    http://GaslightSoftware.com/
     
    Rob Biedenharn, Aug 10, 2010
    #2
    1. Advertisements

  3. Try your example values in irb:

    irb(main):003:0> (9223372036854775807 - 116_444_736_000_000_000) /
    10_000_000
    => 910692730085
    irb(main):004:0> Time.at(910692730085)
    RangeError: bignum too big to convert into `long'
    from (irb):4:in `at'
    from (irb):4

    Time.at expects number of seconds since Jan 1, 1970.

    The value you have given it is some time in the year 30,828 :)

    I suspect either your epoch or your multiplier is wrong.

    B.
     
    Brian Candler, Aug 10, 2010
    #3
  4. Actually, I think you're just reading a dummy value. Note the following:

    irb(main):001:0> 9223372036854775807.to_s(16)
    => "7fffffffffffffff"

    (i.e. the largest possible signed 64-bit value)

    A quick Google suggests the Microsoft epoch is Jan 1, 1601, and Windows
    uses 100-nanosecond ticks.

    Using a 64-bit machine:

    irb(main):002:0> require 'time'
    => true
    irb(main):003:0> Time.parse("Jan 1 1601")
    => Mon Jan 01 00:00:00 -0001 1601
    irb(main):004:0> Time.parse("Jan 1 1601").to_i
    => -11644473525
    irb(main):005:0> 11644473525 * 10_000_000
    => 116444735250000000

    This value agrees with your epoch, within 75 leap seconds anyway.

    If I use ldapsearch against an AD server, and look at attributes like
    lastLogon, they give plausible answers when parsed using your function
    (and succeed on a 32-bit machine)

    Regards,

    Brian.
     
    Brian Candler, Aug 10, 2010
    #4
  5. The largest Time you can have in a 32-bit value is:

    irb(main):001:0> Time.at(0x7fffffff)
    => Tue Jan 19 03:14:07 +0000 2038
    irb(main):002:0> Time.at(0x7fffffff+1)
    RangeError: bignum too big to convert into `long'
    from (irb):2:in `at'
    from (irb):2
    from :0

    Being Ruby, you are not constrained to using a numeric value. You could
    use nil, or a symbol like :never, or a custom object which has
    sufficient Time-like behaviours:

    Never = Object.new
    def Never.to_s; "Never"; end
     
    Brian Candler, Aug 11, 2010
    #5
  6. You can get 64-bit Solaris SPARC can't you?

    The example I posted (showing the limit for 32-bit Time) was on a 32-bit
    Ubuntu machine.

    Linux xxx 2.6.24-28-386 #1 Sat Jul 31 15:36:51 UTC 2010 i686 GNU/Linux

    ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]

    I'm sure an older Mac would be the same.
     
    Brian Candler, Aug 11, 2010
    #6
  7. Remember that ruby 1.9 is a significantly different language to ruby
    1.8. Unless you are lucky, or fancy modifying your app to work with 1.9
    (and maybe its dependent libs too), I think you'd be better off finding
    a 64-bit build of ruby 1.8.7.
     
    Brian Candler, Aug 11, 2010
    #7
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.