Times and Dates

 
   

Ruby Way
By Hal Fulton
Slots : 1.0
Table of Contents
 


Does anybody really know what time it is?

Chicago, Chicago IV

One of the most complex and confusing areas of human life is that of measuring time. To come to a complete understanding of the subject, you would need to study physics, astronomy, history, law, business, and religion. Astronomers know (as most of us don't!) that solar time and sidereal time aren't quite the same thing, and why a leap second is occasionally added to the end of the year. Historians know that the calendar skipped several days in October 1582, when Italy converted from the Julian calendar to the Gregorian. Very few people know the difference between astronomical Easter and ecclesiastical Easter (which are almost always the same). Many people don't know that century years not divisible by 400 (such as the year 1900) aren't leap years.

Performing calculations with times and dates is common in computing, but it has traditionally been somewhat tedious in most programming languages. It is tedious in Ruby, too, because of the nature of the data. However, Ruby has taken some incremental steps toward making these operations easier.

As a courtesy to you, we'll go over a few terms that might not be familiar to you. Most of these come from standard usage or from other programming languages.

Greenwich Mean Time (GMT) is an old term not really in official use anymore. The new global standard is Coordinated Universal Time (or UTC), which is from the French version of the name. GMT and UTC are virtually the same thing; over a period of years, the difference will be on the order of seconds. Much of the software in the industry doesn't distinguish between the two at all (nor does Ruby).

Daylight Saving Time is a semiannual shift in the official time, amounting to a difference of one hour. Thus the U.S. time zones usually end in "ST" (standard time) or "DT" (daylight savings time). This annoying trick is used in most (although not all) of the U.S.A. Other countries need not worry about it.

The epoch is a term borrowed from UNIX lore. In this realm, a time is typically stored internally as a number of seconds from a specific point in time (called the epoch), which was midnight January 1, 1970 GMT. (Note that in U.S. time zones, this will actually be the preceding December 31.) The same term is used to denote not only the point of origin, but also the distance in time from that point.

The Time class is used for most operations. The Date and ParseDate libraries extend its capabilities somewhat. We will look at the basic techniques and the problems they enable us to solve.

Determining the Current Time

The most fundamental problem in time/date manipulation is to answer the question: What is the time and date right now? In Ruby, when we create a Time object with no parameters, it is set to the current date and time.

 

 t0 = Time.new 

Time.now is a synonym.

 

 t0 = Time.now 

Note that the resolution of system clocks varies from one architecture to another. It might include microseconds; in which case, two Time objects created in succession might actually record different times.

Working with Specific Times (Post-epoch)

Most software only needs to work with dates in the future or in the recent past. For these circumstances, the Time class is adequate. The relevant class methods are mktime, local, gm, and utc.

The mktime method will create a new Time object based on the parameters passed to it. These time units are given in reverse from longest to shortest: year, month, day, hours, minutes, seconds, microseconds. All but the year are optional; they default to the lowest possible value. The microseconds can be ignored on many architectures. The hours must be between 0 and 23 (that is, a 24-hour clock).

 

 t1 = Time.mktime(2001)                # January 1, 2001 at 0:00:00 t2 = Time.mktime(2001,3) t3 = Time.mktime(2001,3,15) t4 = Time.mktime(2001,3,15,21) t5 = Time.mktime(2001,3,15,21,30) t6 = Time.mktime(2001,3,15,21,30,15)  # March 15, 2001 9:30:15 pm 

Note that mktime assumes the local time zone. In fact, Time.local is a synonym for it.

 

 t7 = Time.local(2001,3,15,21,30,15)   # March 15, 2001 9:30:15 pm 

The Time.gm method is basically the same, except that it assumes GMT (or UTC). Because the authors are in the U.S. Central time zone, we would see an eight-hour difference here.

 

 t8 = Time.gm(2001,3,15,21,30,15)      # March 15, 2001 9:30:15 pm # This is only 1:30:15 pm in Central time! 

The Time.utc method is a synonym.

 

 t9 = Time.utc(2001,3,15,21,30,15)     # March 15, 2001 9:30:15 pm # Again, 1:30:15 pm Central time. 

There is one more important item to note. All these methods can take an alternative set of parameters. The instance method to_a (which converts a time to an array of relevant values) returns a set of values in this order: seconds, minutes, hours, day, month, year, day of week (0..6), day of year (1..366), daylight saving (true or false), and time zone (as a string).

Thus, these are also valid calls:

 

 t0 = Time.local(0,15,3,20,11,1979,2,324,false,"GMT-8:00") t1 = Time.gm(*Time.now.to_a) 

However, in the first example, don't fall into the trap of thinking that you can change the computable parameters such as the day of the week (in this case, 2 meaning Tuesday). A change like this simply contradicts the way our calendar works, and it will have no effect on the time object created. November 20, 1979, was a Tuesday regardless of how we might write our code.

Finally, note that there are obviously many ways to attempt coding incorrect times, such as a thirteenth month or a 35th day of the month. In cases like these, an ArgumentError will be raised.

Determining Day of the Week

There are several ways to do this. First of all, the instance method to_a will return an array of time information. You can access the seventh element, which is a number from 0 to 6 (0 meaning Sunday and 6 meaning Saturday).

 

 time = Time.now day = time.to_a[6]            # 2 (meaning Tuesday) 

It's better to use the instance method wday as shown here:

 

 day = time.wday               # 2 (meaning Tuesday) 

But both these techniques are a little cumbersome. Sometimes we want the value coded as a number, but more often we don't. To get the actual name of the weekday as a string, we can use the strftime method. This name will be familiar to C programmers. There are nearly two dozen different specifiers that it recognizes, enabling us to format dates and times more or less as we please. (See the section "Formatting and Printing Date/Time Values.")

 

 day = time.strftime("%a")     # "Tuesday" 

It's also possible to obtain an abbreviated name.

 

 long  = time.strftime("%A")   # "Tuesday" 

Determining the Date of Easter

Traditionally, this holiday is one of the hardest to compute because it is tied to the lunar cycle. The lunar month doesn't go evenly into the solar year, and thus anything based on the moon can be expected to vary from year to year.

The algorithm we present here is a well-known one that has made the rounds. We have seen it coded in BASIC, Pascal, and C. We now present it to you in Ruby.

 

 def easter(year)   c = year/100   n = year - 19*(year/19)   k = (c-17)/25   i = c - c/4 - (c-k)/3 + 19*n + 15   i = i - 30*(i/30)   i = i - (i/28)*(1 -(i/28)*(29/(i+1))*((21-n)/11))   j = year + year/4 + i + 2 - c + c/4   j = j - 7*(j/7)   l = i - j   month = 3 + (l+40)/44   day = l + 28 - 31*(month/4)   [month, day] end date = easter 2001      # Find month/day for 2001 date = [2001] + date    # Tack year on front t = Time.local *date    # Pass parameters to Time.local puts t                  # Sun Apr 15 01:00:00 GMT-8:00 2001 

We would love to explain this algorithm to you, but we don't understand it ourselves. Some things must be taken on faith, and in the case of Easter, this might be especially appropriate.

Finding the Nth Weekday in a Month

Sometimes for a given month and year, we want to find the date of the third Monday in the month, or the second Tuesday, and so on. Listing 2.9 makes that calculation simple.

If we are looking for the nth occurrence of a certain weekday, we pass n as the first parameter. The second parameter is the number of that weekday (0 meaning Sunday, 1 meaning Monday, and so on). The third and fourth parameters are the month and year, respectively.

Listing 2.9 Finding the Nth Weekday
 def nth_wday(n, wday, month, year)   if (!n.between? 1,5) or      (!wday.between? 0,6) or      (!month.between? 1,12)     raise ArgumentError   end   t = Time.local year, month, 1   first = t.wday   if first == wday      fwd = 1    elsif first < wday      fwd = wday - first + 1    elsif first > wday      fwd = (wday+7) - first + 1    end    target = fwd + (n-1)*7    begin      t2 = Time.local year, month, target    rescue ArgumentError      return nil    end    if t2.mday == target      t2    else      nil    end end puts nth_wday(ARGV[0].to_i, ARGV[1].to_i, ARGV[2].to_i, ARGV[3].to_i) 

The peculiar-looking code near the end of the method is put there to counteract a long-standing tradition in the underlying time-handling routines. You might expect that trying to create a date of November 31 would result in an error of some kind. You would be mistaken. Most systems would happily (and silently) convert this to December 1. If you are an old-time UNIX hacker, you might think this is a feature; otherwise, you might consider it a bug.

We won't venture an opinion here as to what the underlying library code ought to do or whether Ruby ought to change that behavior. But we don't want to have this routine perpetuate the tradition. If you are looking for the date of, say, the fifth Friday in November 2000, you will get a nil value back (rather than December 1, 2000).

Converting Between Seconds and Larger Units

Sometimes we want to take a number of seconds and convert to days, hours, minutes, and seconds. This little routine will do just that.

 

 def sec2dhms(secs)   time = secs.round          # Get rid of microseconds   sec = time % 60            # Extract seconds   time /= 60                 # Get rid of seconds   mins = time % 60           # Extract minutes   time /= 60                 # Get rid of minutes   hrs = time % 24            # Extract hours   time /= 24                 # Get rid of hours   days = time                # Days (final remainder)   [days, hrs, mins, sec]     # Return array [d,h,m,s] end t = sec2dhms(1000000)        # A million seconds is... puts "#{ t[0]}  days,"         # 11 days, puts "#{ t[1]}  hours,"        # 13 hours, puts "#{ t[2]}  minutes,"      # 46 minutes, puts " and #{ t[3]}  seconds." # and 40 seconds. 

We could, of course, go up to higher units. But a week isn't an overly useful unit, a month isn't a well-defined term, and a year is far from being an integral number of days.

We also present here the inverse of that function.

 

 def dhms2sec(days,hrs=0,min=0,sec=0)   days*86400 + hrs*3600 + min*60 + sec end 

Converting to and from the Epoch

For various reasons, we might want to convert back and forth between the internal (or traditional) measure and the standard date form. Internally, dates are stored as a number of seconds since the epoch.

The Time.at class method will create a new time given the number of seconds since the epoch.

 

 epoch = Time.at(0)          # Find the epoch (1 Jan 1970 GMT) newmil = Time.at(978307200) # Happy New Millennium! (1 Jan 2001) 

The inverse is the instance method to_i, which converts to an integer.

 

 now = Time.now              # 16 Nov 2000 17:24:28 sec = now.to_i              # 974424268 

If you need microseconds and your system supports that resolution, you can use to_f to convert to a floating-point number.

Working with Leap Seconds: Don't!

Ah, but my calculations, people say,

Reduced the year to better reckoning? Nay,

'Twas only striking from the calendar

Unborn Tomorrow and dead Yesterday.

Omar Khayyam, The Rubaiyat (translation by Fitzgerald)

You want to work with leap seconds? Our advice is: Don't do it.

Although leap seconds are very real and for years the library routines have for years allowed for the possibility of a 61-second minute, our experience has been that most systems don't keep track of leap seconds. By most, we mean all the ones we've ever checked.

For example, a leap second is known to have been inserted at the end of the last day of 1998. Immediately following 23:59:59 came that rare event 23:59:60. But the underlying C libraries on which Ruby is built are ignorant of this.

 

 t0 = Time.gm(1998, 12, 31, 23, 59, 59) t1 = t0 + 1 puts t1      # Fri Jan 01 00:00:00 GMT 1999 

It is (barely) conceivable that Ruby could add a layer of intelligence to correct for this. At the time of this writing, however, there are no plans to add such functionality.

Finding the Day of the Year

The day number within the year is sometimes called the Julian date, which isn't directly related to the Julian calendar that has gone out of style. Other people insist that this usage isn't correct, so we won't use it from here on.

No matter what you call it, there will be times you want to know what day of the year it is, from 1 to 366. This is easy in Ruby; we use the yday method.

 

 t = Time.now day = t.yday      # 315 

Validating a Date/Time

As you saw in "Finding the Nth Weekday in a Month," the standard date/time functions don't check the validity of a date, but roll it over as needed. For example, November 31 will be translated to December 1.

At times, this might be the behavior you want. If it isn't, you will be happy to know that the standard library date doesn't regard such a date as valid. We can use this fact to perform validation of a date as we instantiate it.

 

 class Time   def Time.validate(year, month=1, day=1,                     hour=0, min=0, sec=0, usec=0)     require "date"     begin       d = Date.new(year,month,day)     rescue       return nil     end     Time.local(year,month,day,hour,min,sec,usec)   end end t1 = Time.validate(2000,11,30)  # Instantiates a valid object t2 = Time.validate(2000,11,31)  # Returns nil 

Here we have taken the lazy way out; we simply set the return value to nil if the parameters passed in don't form a valid date (as determined by the Date class). We have made this method a class method of Time by analogy with the other methods that instantiate objects.

Note that the Date class can work with dates prior to the epoch. This means that passing in a date such as 31 May 1961 will succeed as far as the Date class is concerned. But when these values are passed into the Time class, an ArgumentError will result. We don't attempt to catch that exception here because we think it's appropriate to let it be caught at the same level as (for example) Time.local, in the user code.

Speaking of Time.local, we used that method in the preceding; but if we wanted GMT instead, we could have called the gmt method. It would be a good idea to implement both flavors.

Finding the Week of the Year

The definition of week number isn't absolute and fixed. Various businesses, coalitions, government agencies, and standards bodies have differing concepts of what it means. This stems, of course, from the fact that the year can start on any day of the week; we might or might not want to count partial weeks, and we might start on Sunday or Monday.

We offer only three alternatives here. The first two are made available by the Time method strftime. The %U specifier numbers the weeks starting from Sunday, and the %W specifier starts with Monday.

The third possibility comes from the Date class. It has an accessor called cweek, which returns the week number based on the ISO 8601 definition (which says that week 1 is the week containing the first Thursday of the year).

If none of these three suits you, you might have to roll your own. We present these three in a single code fragment.

 

 require "date" # Let's look at May 1 in the years # 2002 and 2005. t1 = Time.local(2002,5,1) d1 = Date.new(2002,5,1) week1a = t1.strftime("%U").to_i   # 17 week1b = t1.strftime("%W").to_i   # 17 week1c = d1.cweek                 # 18 t2 = Time.local(2005,5,1) d2 = Date.new(2005,5,1) week2a = t2.strftime("%U").to_i   # 18 week2b = t2.strftime("%W").to_i   # 18 week2c = d2.cweek                 # 17 

Detecting Leap Years

The Date class has two class methods julian_leap? and gregorian_leap?; only the latter is of use in recent years. It also has a method leap?, which is an alias for the gregorian_leap? method.

 

 require "date" flag1 = Date.julian_leap? 1700     # true flag2 = Date.gregorian_leap? 1700  # false flag3 = Date.leap? 1700            # false 

Every child knows the first rule for leap years: The year number must be divisible by four. Fewer people know the second rule, that the year number must not be divisible by 100; and fewer still know the exception, that the year can be divisible by 400. In other words: A century year is a leap year only if it is divisible by 400, so 1900 wasn't a leap year, but 2000 was.

The Time class doesn't have a method like this, but if we needed one, it would be simple to create.

 

 class Time   def Time.leap? year     if year % 400 == 0       true     elsif year % 100 == 0       false     elsif year % 4 == 0       true     else       false   end end 

We implement this as a class method by analogy with the Date class methods. It could also be implemented as an instance method.

Obtaining the Time Zone

The accessor zone in the Time class will return a String representation of the time zone name.

 

 z1 = Time.gm(2000,11,10,22,5,0).zone     # "GMT-6:00" z2 = Time.local(2000,11,10,22,5,0).zone  # "GMT-6:00" 

Unfortunately, times are stored relative to the current time zone, not the one with which the object was created.

Working with Hours and Minutes Only

We might want to work with times of day as strings. Once again, strftime comes to our aid.

We can print the time with hours, minutes, and seconds if we want.

 

 t = Time.now puts t.strftime("%H:%M:%S")    # Prints 22:07:45 

We can print hours and minutes only (and, using the trick of adding 30 seconds to the time, we can even round to the nearest minute).

 

 puts t.strftime("%H:%M")       # Prints 22:07 puts (t+30).strftime("%H:%M")  # Prints 22:08 

Finally, if we don't like the standard 24-hour (or military) clock, we can switch to the 12-hour clock. It's appropriate to add a meridian indicator then (AM/PM).

 

 puts t.strftime("%I:%M %p")    # Prints 10:07 PM 

There are other possibilities, of course. Use your imagination.

Comparing Date/Time Values

The Time class conveniently mixes in the Comparable module, so dates and times might be compared in a straightforward way.

 

 t0 = Time.local(2000,11,10,22,15)      # 10 Nov 2000 22:15 t1 = Time.local(2000,11,9,23,45)       #  9 Nov 2000 23:45 t2 = Time.local(2000,11,12,8,10)       # 12 Nov 2000  8:10 t3 = Time.local(2000,11,11,10,25)      # 11 Nov 2000 10:25 if t0 < t1 then puts "t0 < t1" end if t1 != t2 then puts "t1 != t2" end if t1 <= t2 then puts "t1 <= t2" end if t3.between?(t1,t2)   puts "t3 is between t1 and t2" end # All four if statements test true 

Adding Intervals to Date/Time Values

We can obtain a new time by adding an interval to a specified time. The number is interpreted as a number of seconds.

 

 t0 = Time.now t1 = t0 + 60         # Exactly one minute past t0 t2 = t0 + 3600       # Exactly one hour past t0 t3 = t0 + 86400      # Exactly one day past t0 

The function dhms2sec (defined in "Converting Between Seconds and Larger Units") might be helpful here. Recall that the hours, minutes, and seconds all default to 0.

 

 t4 = t0 + dhms2sec(5,10)       # Ahead 5 days, 10 hours t5 = t0 + dhms2sec(22,18,15)   # Ahead 22 days, 18 hrs, 15 min t6 = t0 - dhms2sec(7)          # Exactly one week ago 

Don't forget that we can move backward in time by subtracting. This is shown in the preceding calculation of t6.

Computing the Difference in Two Date/Time Values

We can find the interval of time between two points in time. Subtracting one Time object from another gives us a number of seconds.

 

 today = Time.local(2000,11,10) yesterday = Time.local(2000,11,9) diff = today - yesterday           # 86400 seconds 

Once again, the function sec2dhms comes in handy. (This is defined in "Converting Between Seconds and Larger Units.")

 

 past = Time.local(1998,9,13,4,15) now = Time.local(2000,11,10,22,42) diff = now - past unit = sec2dhms(diff) puts "#{ unit[0]}  days,"            # 789 days, puts "#{ unit[1]}  hours,"           # 18 hours, puts "#{ unit[2]}  minutes,"         # 27 minutes, puts "and #{ unit[3]}  seconds."     # and 0 seconds. 

Working with Specific Dates (Pre-epoch)

The standard library Date provides a class of the same name for working with dates that precede midnight GMT, January 1, 1970.

Although there is some overlap in functionality with the Time class, there are significant differences. Most notably, the Date class doesn't handle the time of day at all. Its resolution is a single day. Also, the Date class performs more rigorous error-checking than the Time class; if you attempt to refer to a date such as June 31 (or even February 29 in a nonleap year), you will get an error. The code is smart enough to know the different cutoff dates for Italy and England switching to the Gregorian calendar (in 1582 and 1752, respectively), and it can detect nonexistent dates that are a result of this switchover. This standard library is a tangle of interesting and arcane code. We don't have space to document it further here.

Retrieving a Date/Time Value from a String

A date and time can be formatted as a string in many different ways because of abbreviations, varying punctuation, different orderings, and so on. Because of the various ways of formatting, writing code to decipher such a character string can be daunting. Consider these examples:

 

 s1 = "9/13/98 2:15am" s2 = "1961-05-31" s3 = "11 July 1924" s4 = "April 17, 1929" s5 = "20 July 1969 16:17 EDT"  # That's one small step... s6 = "Mon Nov 13 2000" s7 = "August 24, 79"           # Destruction of Pompeii s8 = "8/24/79" 

Fortunately, much of the work has already been done for us. The ParseDate module has a single class of the same name, which has a single method called parsedate. This method returns an array of elements in this order: year, month, day, hour, minute, second, time zone, day of week. Any fields that cannot be determined are returned as nil values.

 

 require "parsedate.rb" include ParseDate p parsedate(s1)      # [98, 9, 13, 2, 15, nil, nil, nil] p parsedate(s2)      # [1961, 5, 31, nil, nil, nil, nil, nil] p parsedate(s3)      # [1924, 7, 11, nil, nil, nil, nil, nil] p parsedate(s4)      # [1929, 4, 17, nil, nil, nil, nil, nil] p parsedate(s5)      # [1969, 7, 20, 16, 17, nil, "EDT", nil] p parsedate(s6)      # [2000, 11, 13, nil, nil, nil, nil, 1] p parsedate(s7)      # [79, 8, 24, nil, nil, nil, nil, nil] p parsedate(s8,true) # [1979, 8, 24, nil, nil, nil, nil, nil] 

The last two strings illustrate the purpose of parsedate's second parameter guess_year; because of our cultural habit of representing a year as two digits, ambiguity can result. Thus the last two strings are interpreted differently because we parse s8 with guess_year set to true, resulting in its conversion to a four-digit year. On the other hand, s7 refers to the eruption of Vesuvius in 79 A.D., so we definitely want a two-digit year there.

The rule for guess_year is this: If the year is less than 100 and guess_year is true, convert to a four-digit year. The conversion will be done as follows: If the year is 70 or greater, add 1900 to it; otherwise add 2000. Thus 75 will translate to 1975, but 65 will translate to 2065. This rule isn't uncommon in the computing world.

What about s1, where we probably intended 1998 as the year? All is not lost as long as we pass this number to some other piece of code that interprets it as 1998.

Note that parsedate does virtually no error checking. For example, if you feed it a date with a weekday and a date that don't correspond correctly, it won't detect this discrepancy. It is only a parser, and it does this job pretty well, but no other.

Also note an American bias in this code. An American writing 3/4/2001 usually means March 4, 2001; in Europe and most other places, this would mean April 3 instead. But if all the data is consistent, this isn't a huge problem. Because the return value is simply an array, you can mentally switch the meaning of elements 1 and 2. Be aware also that this bias happens even with a date such as 15/3/2000, where it is clear (to us) that 15 is the day. The parsedate method will happily return 15 as the month value.

Although this method is very flexible, it is far from perfect. We have observed that it tends not to capture the time zone if it follows a meridian indicator such as p.m. We have also noted that it doesn't recognize a year such as '79 (with a leading apostrophe).

Formatting and Printing Date/Time Values

You can obtain the canonical representation of the date and time by calling the asctime method (ASCII time); it has an alias called ctime, for those who already know it by that name.

You can obtain a similar result by calling the to_s method. This is the same as the result you would get if doing a simple puts of a date/time value.

The strftime method of class Time will format a date and time in almost any form you can think of. Other examples in this chapter have shown the use of the directives %a, %A, %U, %W, %H, %M, %S, %I, and %p; we list here all the remaining directives that strftime recognizes.

 

 %b    Abbreviated month name ("Jan") %B    Full month name ("January") %c    Preferred local date/time representation %d    Day of the month (1..31) %j    Day of the year (1..366); so-called "Julian date" %m    Month as a number (1..12) %w    Day of the week as a number (0..6) %x    Preferred representation for date (no time) %y    Two-digit year (no century) %Y    Four-digit year %Z    Time zone name %%    A literal "%" character 

For more information, consult a Ruby reference.

Time Zone Conversions

It is only convenient to work with two time zones: GMT (or UTC) is one, and the other is whatever time zone you happen to be in.

The gmtime method will convert a time to GMT (changing the receiver in place). There is an alias named utc.

You might expect that it would be possible to convert a time to an array, tweak the time zone, and convert it back. The trouble with this is that all the class methods such as local and gm (or their aliases mktime and utc) want to create a Time object using either your local time zone or GMT.

It is possible to fake time zone conversions. This does require that you know the time difference in advance.

 

 mississippi = Time.local(2000,11,13,9,35) # 9:35 am CST california  = mississippi - 2*3600        # Minus two hours time1 = mississippi.strftime("%X CST")    # 09:35:00 CST time2 = california.strftime("%X PST")     # 07:35:00 PST 

The %X directive to strftime that we see here simply uses the hh:mm:ss format as shown.

Finding the Internet Time (@nnn)

Time is an illusion created by the Swiss to sell watches.

Douglas Adams

We offer this next item mostly as a curiosity. The Swiss watch manufacturer Swatch has created a trendy way of measuring time in cyberspace, a metric-like time that they call Internet Time. This time standard has no time zones and is thus usable, for example, by people meeting each other in chat rooms when they are physically thousands of miles apart. It was inaugurated on October 23, 1998, in the presence of Nicholas Negroponte, founder and director of MIT's Media Lab.

Not surprisingly, Internet Time is based on the meridian of Biel, Switzerland. The day is divided into 1000 beats, each 86.4 seconds long (or 1 minute, 26.4 seconds). The three digit number representing the time of day is prefixed by an at (@) sign.

This method will find the current time in Internet Time. It returns a number, unless true is passed in; then it returns a string, with an @ and any leading zeroes. Mimicking the behavior of the applications we have seen, we truncate any fractional part rather than rounding up.

 

 def internet_time(str=false)   t = Time.now.gmtime + 3600   # Biel, Switzerland   midnight = Time.gm(t.year, t.month, t.day)   secs = t - midnight   beats = (secs/86.4).to_i   if str     "@%03d" % beats   else     beats   end end time_now = internet_time     # 27 now = internet_time(true)    # "@027" 


   

 

 



The Ruby Way
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2000
Pages: 119
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net