Get hours, seconds and time from Date.day_fraction_to_time

Discussion in 'Ruby' started by Emanuele Ianni, Sep 17, 2010.

  1. start = DateTime.now
    sleep 15
    stop = DateTime.now
    #minutes
    puts ((stop-start) * 24 * 60).to_i

    hours,minutes,seconds,frac = Date.day_fraction_to_time(stop-start)

    I have the following error:

    `<main>': private method `day_fraction_to_time' called for
    Date:Class (NoMethodError)

    I've checked */usr/lib/ruby/1.9.1/date.rb* and I've found it:

    def day_fraction_to_time(fr) # :nodoc:
    ss, fr = fr.divmod(SECONDS_IN_DAY) # 4p
    h, ss = ss.divmod(3600)
    min, s = ss.divmod(60)
    return h, min, s, fr * 86400
    end

    But I have no problem if I run it with ruby1.8.
    */usr/lib/ruby/1.8/date.rb* gives me:

    def self.day_fraction_to_time(fr)
    ss, fr = fr.divmod(SECONDS_IN_DAY) # 4p
    h, ss = ss.divmod(3600)
    min, s = ss.divmod(60)
    return h, min, s, fr
    end

    So I went to see the documentation(1.9)[1] and there's no trace of this
    method. I know it's a dumb question, but why did they remove it? There
    is even this example on how to use the method in
    */usr/lib/ruby/1.9.1/date.rb*:

    def secs_to_new_year(now = DateTime::now())
    new_year = DateTime.new(now.year + 1, 1, 1)
    dif = new_year - now
    hours, mins, secs, ignore_fractions =
    Date::day_fraction_to_time(dif)
    return hours * 60 * 60 + mins * 60 + secs
    end

    but I'm still getting the error:

    test.rb:24:in `secs_to_new_year': private method
    `day_fraction_to_time' called for Date:Class (NoMethodError)
    from test.rb:28:in `<main>'


    [1]: http://ruby-doc.org/core-1.9/classes/Date.html
    --
    Posted via http://www.ruby-forum.com/.
    Emanuele Ianni, Sep 17, 2010
    #1
    1. Advertising

  2. [Note: parts of this message were removed to make it a legal post.]

    See below at *** for two "work-arounds" which seem to allow you to do what
    you want in Ruby 1.9 as well as in 1.8.6 and 1.8.7.

    Some links for explanations of private and public (and protected) methods:
    http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby
    Here (for example) under Access Control:
    http://ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html
    ...
    Private methods cannot be called with an explicit receiver. Because you
    cannot specify an object when using them, private methods can be called only
    in the defining class and by direct descendents within that same object.

    Compare the "full" code for the 1.8 and 1.9 versions of Date. (See just
    below.) The 1.8 version can only be used as a class method
    Date.day_fraction_to_time, but the 1.9 version can also be used as a
    *private* instance method.

    That said, I don't know why the class (singleton) method
    day_fraction_to_time was changed from public in Date before 1.9 to private
    in 1.9, and I would welcome any enlightened suggestions. (One reason for
    making a method private is, I assume, to warn people that an internal
    implementation detail might change, so it would be unwise to use such a
    private method in case its implementation changes in the future. That gives
    more freedom to the code originator for future changes.)

    # In 1.8:
    class Date
    #...
    def self.day_fraction_to_time(fr)
    #...
    end
    #...
    end

    # But in 1.9:
    class Date
    #...
    t = Module.new do
    private
    #...
    def day_fraction_to_time(fr) # :nodoc:
    #...
    end
    #...
    end
    extend t
    include t
    #...
    end


    *** work arounds

    require "date"

    start = DateTime.now
    sleep 3
    stop = DateTime.now
    # minutes
    puts( ((stop - start) * 24 * 60).to_i )

    puts "Date.day_fraction_to_time"
    begin
    hours, minutes, seconds, frac =
    Date.day_fraction_to_time( stop - start ) # works in 1.8.6 & 1.8.7
    p hours, minutes, seconds, frac
    rescue # raises exception in 1.9.1
    p $!
    end

    puts "Date.day_fraction_to_time using __send__"
    hours, minutes, seconds, frac =
    Date.__send__( :day_fraction_to_time, stop - start )
    p hours, minutes, seconds, frac

    puts "Date.day_fraction_to_time using wrapper"
    class Date
    class << self
    def wrap_day_fraction_to_time( day_frac )
    day_fraction_to_time( day_frac )
    end
    end
    end
    hours, minutes, seconds, frac =
    Date.wrap_day_fraction_to_time( stop - start )
    p hours, minutes, seconds, frac
    Colin Bartlett, Sep 18, 2010
    #2
    1. Advertising

  3. Colin Bartlett wrote:
    > puts "Date.day_fraction_to_time using wrapper"
    > class Date
    > class << self
    > def wrap_day_fraction_to_time( day_frac )
    > day_fraction_to_time( day_frac )
    > end
    > end
    > end
    > hours, minutes, seconds, frac =
    > Date.wrap_day_fraction_to_time( stop - start )
    > p hours, minutes, seconds, frac


    Thanks for the answer. Could you examplain me the wrapper in detail,
    please? I'm assuming you're extending the Date class with an anonymous
    class but it's really not clear to me the class << self declaration.
    --
    Posted via http://www.ruby-forum.com/.
    Emanuele Ianni, Sep 18, 2010
    #3
  4. Emanuele Ianni

    Rohit Sharma Guest

    Rohit Sharma, Sep 18, 2010
    #4
  5. [Note: parts of this message were removed to make it a legal post.]

    On Sat, Sep 18, 2010 at 12:09 PM, Emanuele Ianni <> wrote:

    > Colin Bartlett wrote:
    > > puts "Date.day_fraction_to_time using wrapper"
    > > class Date
    > > class << self
    > > def wrap_day_fraction_to_time( day_frac )
    > > day_fraction_to_time( day_frac )
    > > end
    > > end
    > > end
    > > hours, minutes, seconds, frac =
    > > Date.wrap_day_fraction_to_time( stop - start )
    > > p hours, minutes, seconds, frac

    >
    > Thanks for the answer. Could you explain me the wrapper in detail,
    > please? I'm assuming you're extending the Date class with an anonymous
    > class but it's really not clear to me the class << self declaration.


    I'm not surprised that "class << self" isn't clear to you. It wasn't clear
    to me when I first saw it, and I'm not sure I'm 100% there yet! I hope the
    following is right and helps. (Corrections are welcome.)

    Here's a link to the online first edition of Programming Ruby
    http://ruby-doc.org/docs/ProgrammingRuby/html/classes.html
    ... Object-Specific Classes ...

    Basically you can extend any object with methods which won't be available to
    any other object unless you also extend that other object.

    In the version of Date with Ruby 1.9 one way used is to set up an
    (anonymous?) module and then use "extend", as shown in the extract from
    (1.9) Date in my first post in this thread.

    Another way is to use the "class << object" notation, which (I think) says
    evaluate the code in "class<<...end" in the context of the specified object,
    extending that object (as singleton methods of that object) with any methods
    defined in "class<<...end". For example:
    obj = Array.new
    (r = obj.new_singleton_method) rescue p $! #=> undefined method error
    class << obj
    def new_singleton_method(); "Karel Capek"; end
    end
    r = obj.new_singleton_method #=> "Karel Capek"

    So in:
    class Date
    class << self
    def wrap_day_fraction_to_time( day_frac )
    day_fraction_to_time( day_frac )
    end
    end
    end
    the object being extended in "class<<self...end" is whatever "self" is, and
    in the context of the "class Date" self is the Date class. And the private
    method "day_fraction_to_time" is accessible from "within" the object, so we
    can write a public method (callable as Date.wrap_day_fraction_to_time) which
    calls the private method "day_fraction_to_time".

    Also, instead of writing a wrapper method, the following (simpler) way also
    seems to work:
    hours = mins = secs = nil
    hours, mins, secs = Date.day_fraction_to_time( 0.03125 ) rescue p $!
    p hours, mins, secs #=> nil, nil, nil
    class Date
    class << self
    public :day_fraction_to_time
    end
    end
    hours, mins, secs = Date.day_fraction_to_time( 0.03125 ) rescue p $!
    p hours, mins, secs #=> 0, 45, 0

    In the context of a private method, I'm not at all sure that putting a
    public wrapper method which calls it is better than simply making the
    private method public: I think that any downsides/problems with making the
    private method public will also apply to wrapping it. Does anyone know (or
    think) differently?
    Colin Bartlett, Sep 19, 2010
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. 00_CP_D12
    Replies:
    3
    Views:
    8,875
    dilipv
    Feb 22, 2008
  2. Stu
    Replies:
    7
    Views:
    1,727
    Dave Thompson
    Mar 7, 2005
  3. Michael Tan
    Replies:
    32
    Views:
    931
    Ara.T.Howard
    Jul 21, 2005
  4. `p
    Replies:
    7
    Views:
    352
    Steve Litt
    Dec 14, 2005
  5. rutherf
    Replies:
    2
    Views:
    410
    rutherf
    Oct 28, 2006
Loading...

Share This Page