File: date.rb

# date.rb

Path: | date.rb
Last Update: | Sat Oct 15 23:44:27 AUS Eastern Standard Time 2005

date.rb - date and time library

Author: Tadayoshi Funaba 1998-2005

Documentation: William Webber <william@williamwebber.com>

## Overview

This file provides two classes for working with dates and times.

The first class, Date, represents dates. It works with years, months, weeks, and days. See the Date class documentation for more details.

The second, DateTime, extends Date to include hours, minutes, seconds, and fractions of a second. It provides basic support for time zones. See the DateTime class documentation for more details.

### Ways of calculating the date.

In common usage, the date is reckoned in years since or before the Common Era (CE/BCE, also known as AD/BC), then as a month and day-of-the-month within the current year. This is known as the Civil Date, and abbreviated as `civil` in the Date class.

Instead of year, month-of-the-year, and day-of-the-month, the date can also be reckoned in terms of year and day-of-the-year. This is known as the Ordinal Date, and is abbreviated as `ordinal` in the Date class. (Note that referring to this as the Julian date is incorrect.)

The date can also be reckoned in terms of year, week-of-the-year, and day-of-the-week. This is known as the Commercial Date, and is abbreviated as `commercial` in the Date class. The commercial week runs Monday (day-of-the-week 1) to Sunday (day-of-the-week 7), in contrast to the civil week which runs Sunday (day-of-the-week 0) to Saturday (day-of-the-week 6). The first week of the commercial year starts on the Monday on or before January 1, and the commercial year itself starts on this Monday, not January 1.

For scientific purposes, it is convenient to refer to a date simply as a day count, counting from an arbitrary initial day. The date first chosen for this was January 1, 4713 BCE. A count of days from this date is the Julian Day Number or Julian Date, which is abbreviated as `jd` in the Date class. This is in local time, and counts from midnight on the initial day. The stricter usage is in UTC, and counts from midday on the initial day. This is referred to in the Date class as the Astronomical Julian Day Number, and abbreviated as `ajd`. In the Date class, the Astronomical Julian Day Number includes fractional days.

Another absolute day count is the Modified Julian Day Number, which takes November 17, 1858 as its initial day. This is abbreviated as `mjd` in the Date class. There is also an Astronomical Modified Julian Day Number, which is in UTC and includes fractional days. This is abbreviated as `amjd` in the Date class. Like the Modified Julian Day Number (and unlike the Astronomical Julian Day Number), it counts from midnight.

Alternative calendars such as the Chinese Lunar Calendar, the Islamic Calendar, or the French Revolutionary Calendar are not supported by the Date class; nor are calendars that are based on an Era different from the Common Era, such as the Japanese Imperial Calendar or the Republic of China Calendar.

### Calendar Reform

The standard civil year is 365 days long. However, the solar year is fractionally longer than this. To account for this, a leap year is occasionally inserted. This is a year with 366 days, the extra day falling on February 29. In the early days of the civil calendar, every fourth year without exception was a leap year. This way of reckoning leap years is the Julian Calendar.

However, the solar year is marginally shorter than 365 1/4 days, and so the Julian Calendar gradually ran slow over the centuries. To correct this, every 100th year (but not every 400th year) was excluded as a leap year. This way of reckoning leap years, which we use today, is the Gregorian Calendar.

The Gregorian Calendar was introduced at different times in different regions. The day on which it was introduced for a particular region is the Day of Calendar Reform for that region. This is abbreviated as `sg` (for Start of Gregorian calendar) in the Date class.

Two such days are of particular significance. The first is October 15, 1582, which was the Day of Calendar Reform for Italy and most Catholic countries. The second is September 14, 1752, which was the Day of Calendar Reform for England and its colonies (including what is now the United States). These two dates are available as the constants Date::ITALY and Date::ENGLAND, respectively. (By comparison, Germany and Holland, less Catholic than Italy but less stubborn than England, changed over in 1698; Sweden in 1753; Russia not till 1918, after the Revolution; and Greece in 1923. Many Orthodox churches still use the Julian Calendar. A complete list of Days of Calendar Reform can be found at www.polysyllabic.com/GregConv.html.)

Switching from the Julian to the Gregorian calendar involved skipping a number of days to make up for the accumulated lag, and the later the switch was (or is) done, the more days need to be skipped. So in 1582 in Italy, 4th October was followed by 15th October, skipping 10 days; in 1752 in England, 2nd September was followed by 14th September, skipping 11 days; and if I decided to switch from Julian to Gregorian Calendar this midnight, I would go from 27th July 2003 (Julian) today to 10th August 2003 (Gregorian) tomorrow, skipping 13 days. The Date class is aware of this gap, and a supposed date that would fall in the middle of it is regarded as invalid.

The Day of Calendar Reform is relevant to all date representations involving years. It is not relevant to the Julian Day Numbers, except for converting between them and year-based representations.

In the Date and DateTime classes, the Day of Calendar Reform or `sg` can be specified a number of ways. First, it can be as the Julian Day Number of the Day of Calendar Reform. Second, it can be using the constants Date::ITALY or Date::ENGLAND; these are in fact the Julian Day Numbers of the Day of Calendar Reform of the respective regions. Third, it can be as the constant Date::JULIAN, which means to always use the Julian Calendar. Finally, it can be as the constant Date::GREGORIAN, which means to always use the Gregorian Calendar.

Note: in the Julian Calendar, New Years Day was March 25. The Date class does not follow this convention.

### Time Zones

DateTime objects support a simple representation of time zones. Time zones are represented as an offset from UTC, as a fraction of a day. This offset is the how much local time is later (or earlier) than UTC. UTC offset 0 is centred on England (also known as GMT). As you travel east, the offset increases until you reach the dateline in the middle of the Pacific Ocean; as you travel west, the offset decreases. This offset is abbreviated as `of` in the Date class.

This simple representation of time zones does not take into account the common practice of Daylight Savings Time or Summer Time.

Most DateTime methods return the date and the time in local time. The two exceptions are ajd() and amjd(), which return the date and time in UTC time, including fractional days.

The Date class does not support time zone offsets, in that there is no way to create a Date object with a time zone. However, methods of the Date class when used by a DateTime instance will use the time zone offset of this instance.

## Examples of use

### 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|
                puts "#{Date::MONTHNAMES[date.mon]} #{date.day}"
            end
        end

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

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

        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

        puts secs_to_new_year()

### Required files

rational date/format

[Validate]