Chronos is one of the many Smalltalk-related blogs syndicated on Planet Smalltalk

Discussion of the Essence# programming language, and related issues and technologies.

Blog Timezone: America/Los_Angeles [Winter: -0800 hhmm | Summer: -0700 hhmm] 
Your local time:  


Comparative Examples: Chronos/Smalltalk vs. Ruby

The documentation of the Ruby "Date.rb" module contains some example code for the usage of Ruby's Date and DateTime classes.

The Ruby examples, and the Chronos code to do the same things, are presented below:

Print out the date of every Sunday between two dates:


def print_sundays(d1, d2)
d1 +=1 while (d1.wday != 0)
d1.step(d2, 7) do |date| // It's not clear whether this means [d1, d2] or [d1, d2)
puts "#{Date::MONTHNAMES[date.mon]} #{}"

print_sundays(Date::civil(2003, 4, 8), Date::civil(2003, 5, 23))


DateAndTimeUtility class>>printSundaysFrom: startDate through: endDate
"Left-closed, right-closed interval: [startDate, endDate]"
| nextSunday |
nextSunday := startDate nextDayOfWeek: Sunday.
through: endDate
every: 1
weeksDo: [:eachSunday |
show: eachSunday localePrintString]

printSundaysFrom: (YearMonthDay year: 2003 month: April day: 8)
through: (YearMonthDay year: 2003 month: May day: 23)

Note that instead of "startDate nextDayOfWeek: Sunday" one could also do exactly what the Ruby code does: "[date dayOfWeek = Sunday] whileFalse: [date := date tomorrow]."

The Chronos/Smalltalk output:

April 13, 2003
April 20, 2003
April 27, 2003
May 4, 2003
May 11, 2003
May 18, 2003

Calculate how many seconds to go till midnight on New Year’s Day:


def secs_to_new_year(now = DateTime::now())
new_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

puts secs_to_new_year()


| now |
now := DateAndTime now.
now secondsUntil:
subtractingYears: 0
months: 0
days: now daysSinceStartOfYear - now daysInYear
seconds: now secondsSinceStartOfDay
nanoseconds: now nanosecondsSinceSecond).

It should be noted that, once Chronos implements leap seconds, the Chronos code will correctly answer the number of UTC seconds--including any leap seconds. The Ruby example wouldn't, even if Date.rb ever implements leap second support. If we didn't care about leap seconds, we could instead use the following Chronos code:

| now |
now := DateAndTime now.
days: now daysInYear - now daysSinceStartOfYear
hours: 0
minutes: 0
seconds: now fractionalSecondsSinceStartOfDay negated) asSeconds

And there are yet other ways to do this in Chronos. A few examples:

  • In one line of code:

    | now | (now := DateAndTime now) nextYear atFirstDayOfYear atStartOfDay secondsSince: now

  • Efficient, with logic that's easy to follow:

    | now |
    now := DateAndTime now.
    (YearMonthDay year: now year + 1 day: 1) secondsSince: now

I should also point out that the Ruby code in the example above (as well as the last Chronos variation) would be subject to a possible bug, in the following situation: a) the current time is in the year before the year 1, and b) the calendar system in use forbids the year zero. But that's not a situation most of you would ever have to worry about. I, on the other hand, do have to worry about such issues when writing the logic internal to Chronos, since Chronos deals with multiple calendars--and new calendrical systems can easily be defined and added.

Ever want to design and implement your own Calendar?

No comments: