The Timing of Time

Alan Lovejoy squeak-dev.sourcery at forum-mail.net
Tue Apr 18 06:12:31 UTC 2006


Hernan, Garau:

It seems that, if I just rely on memory instead of actually looking at what
methods are available, I don't always use my own code in the optimal manner.
It turns out the last-day-of-the-month payment schedule can be coded in
Chronos thusly:

(Timeperiod
	from: (YearMonthDay year: 2006 month: 4 day: 1)
	duration: (CalendarDuration years: 1))
		every: (CalendarDuration months: 1) collect: [:month | month
last]

Or even:

((YearMonthDay year: 2006 month: 4 day: 1) withDuration: (CalendarDuration
years: 1))
	every: (CalendarDuration months: 1) collect: [:month | month last]

In VW or Dolphin, "(CalendarDuration years: 1)" could instead be "1 years"
and "(CalendarDuration months: 1)" could instead be "1 months".  But not in
Squeak, since I didn't add the equivalent convenience methods. I also see
that, although Chronology has already defined most of the convenience
methods using Chronology classes/methods, it does leave a few
unclaimed--such as #years and #months. Yet another example of the dangers of
relying on memory instead of fully checking :-)

Also, I should have shown the protocol for adding "holiday" rules to a
Chronos SemanticDatePolicy instance.  The following code snippet is derived
from the method that initializes the instance of SemanticDatePolicy answered
by "SemanticDatePolicy unitedStates":

	inaugurationDayObservanceRule :=
		(SemanticDateObservanceRule
			yearBase: 1
			period: 4 "Occurrence function: occur(year) = year -
1 \\ 4 = 0"
			dayOfWeekPolicy: #(0 -1 0 0 0 0 0)) "Shift
observance to Monday if nominally occurs on Sunday".
	semanticAnnualDate :=
		SemanticAnnualDateRule
			semanticKey: #InaugurationDay
			effectiveYear: 1789
			nominalAnnualDate: (DayOfMonth month: March day: 4)
			observanceRule: inaugurationDayObservanceRule.
	"US Federal Holiday."
	aSemanticDatePolicy addSemanticAnnualDateRule: semanticAnnualDate.

	semanticAnnualDate :=
		SemanticAnnualDateRule
			semanticKey: #InaugurationDay
			effectiveYear: 1933
			nominalAnnualDate: (DayOfMonth month: January day:
20)
			observanceRule: inaugurationDayObservanceRule.
	"US Federal Holiday--date changed by Consitutional Ammendment."
	aSemanticDatePolicy addSemanticAnnualDateRule: semanticAnnualDate.

	semanticAnnualDate :=
		SemanticAnnualDateRule
			semanticKey: #MartinLutherKingDay "Honoring Dr.
Martin Luther King--actual birthday January 15"
			effectiveYear: 1986
			nominalAnnualDate: (WeekOfMonthDayOfWeek month:
January week: 3 dayOfWeek: Monday)
			observanceRule: nil. "Always observed on the nominal
day"
	"Established as a Federal legal holiday by Act of Congress in 1983
(signed into law by President Reagan in a Rose Garden ceremony in that
year,) but was not observed until 1986-Jan-20."
	aSemanticDatePolicy addSemanticAnnualDateRule: semanticAnnualDate.

	semanticAnnualDate :=
		SemanticAnnualDateRule
			semanticKey: #GroundhogDay
			effectiveYear: 1841 "Earliest attested observance."
			nominalAnnualDate: (DayOfMonth month: February day:
2)
			observanceRule: nil. "Always observed on the nominal
day"
	"Normal business day."
	aSemanticDatePolicy addSemanticAnnualDateRule: semanticAnnualDate.

The concept represented by a SemanticDatePolicy is more general than
"holidays," which is why it's not named "HolidayPolicy." A
SemanticDatePolicy's job is to compute when semantically-significant dates
nominally occur, and when they will be officially observed.  Which of those
dates will be "holidays" (and for whom) is a matter left to application
software to determine.  The date of a national election is set by the
national legislature; the date of a religious observance is set by custom
and/or religious authorities; but whether such dates are company holidays is
usually a policy decision unique to each company.

Eventually, I would like to have the "semantic date occurrence rules"
defined and accessed as reference data from persistent storage (as is
already the case for time zone rules,) and not "hard coded" in the client
image. The rules that determine what dates "semantically-significant dates"
officially occur are subject to change, after all. Also, note the ability to
handle rule changes diachronically, just like Chronos time zones.

Chronos' SemanticDatePolicy and Chalten's TimeLineFilter have only partial
functional overlap--and the possibility of useful synergy between the two
seems high. I was intrigued by the semantics/behavior of the #negated
message.

Here's another example of what a SemanticDatePolicy can do. Execution of the
example causes every date on which the NYSE was closed for the whole day
(other than on weekends,) from 1969-04-01 through 1973-09-30, to be
displayed on the Transcript:

| list |
list := SortedCollection sortBlock: [:a :b | a key < b key].
SemanticDatePolicy nyse
	observedEventOccurenceDatesFrom: (YearMonthDay year: 1969 month: 4
day: 1)
	through: (YearMonthDay year: 1973 month: 9 day: 30)
	do: [:semanticKey :date :observanceType |
		semanticKey == #weekend
			ifFalse: [list add: date->(Array with: semanticKey
with: observanceType)].
Transcript cr.
list do: [:assoc |
	Transcript cr; show: (assoc key printStringUsing: #rfc2822); show:
':'; tab.
	assoc value do: [:key |
		key == #nominal
			ifFalse:
				[key == #observed
					ifTrue:
						[Transcript show: ' (';
show: key; show: ')']
					ifFalse: [Transcript show: key]]]]]

Here's the output (with added commentary):

Fri, 04 Apr 1969:	GoodFriday
Fri, 30 May 1969:	MemorialDay
Fri, 04 Jul 1969:	IndependenceDay
Mon, 21 Jul 1969:	FirstLunarLanding -- Not all NYSE closures are "rule
based." Betcha didn't know this one!
Mon, 01 Sep 1969:	LaborDay
Thu, 27 Nov 1969:	Thanksgiving
Thu, 25 Dec 1969:	Christmas
Thu, 01 Jan 1970:	NewYearsDay
Mon, 23 Feb 1970:	WashingtonsBirthday (observed)
Fri, 27 Mar 1970:	GoodFriday
Fri, 29 May 1970:	MemorialDay (observed)
Fri, 03 Jul 1970:	IndependenceDay (observed)
Mon, 07 Sep 1970:	LaborDay
Thu, 26 Nov 1970:	Thanksgiving
Fri, 25 Dec 1970:	Christmas
Fri, 01 Jan 1971:	NewYearsDay
Mon, 15 Feb 1971:	WashingtonsBirthday
Fri, 09 Apr 1971:	GoodFriday
Mon, 31 May 1971:	MemorialDay
Mon, 05 Jul 1971:	IndependenceDay (observed)
Mon, 06 Sep 1971:	LaborDay
Thu, 25 Nov 1971:	Thanksgiving
Fri, 24 Dec 1971:	Christmas (observed)
Mon, 21 Feb 1972:	WashingtonsBirthday
Fri, 31 Mar 1972:	GoodFriday
Mon, 29 May 1972:	MemorialDay
Tue, 04 Jul 1972:	IndependenceDay
Mon, 04 Sep 1972:	LaborDay
Tue, 07 Nov 1972:	ElectionDay
Thu, 23 Nov 1972:	Thanksgiving
Mon, 25 Dec 1972:	Christmas
Thu, 28 Dec 1972:	PresidentialFuneral-HarryTruman -- Yet another
unique event
Mon, 01 Jan 1973:	NewYearsDay
Thu, 25 Jan 1973:	PresidentialFuneral-LyndonJohnson -- A bad time for
former US Presidents...
Mon, 19 Feb 1973:	WashingtonsBirthday
Fri, 20 Apr 1973:	GoodFriday
Mon, 28 May 1973:	MemorialDay
Wed, 04 Jul 1973:	IndependenceDay
Mon, 03 Sep 1973:	LaborDay

Why this functionality? Certain forms of "technical analysis" depend on
precise counts of the number of trading days between dates--and writing
technical analysis software is one of the use cases motivating the
design/implementation of Chronos.

You get quite a bit more than simple "dates and times" from Chronos.

-----Original Message-----
From: squeak-dev-bounces at lists.squeakfoundation.org
[mailto:squeak-dev-bounces at lists.squeakfoundation.org] On Behalf Of Hernan
Wilkinson
Sent: Monday, April 17, 2006 7:30 AM
To: The general-purpose Squeak developers list
Subject: Re: The Timing of Time

Hi Alan, Francisco,
    we also created a model to deal with dates and time issues because of
the same issues you and Brent mentioned. We uploaded last week to squeak
source, it is named Chalten.
Alan Lovejoy wrote:

>Garau wrote:
>
>"- Starting on the 31Mar2006 generate a schedule of payments every
>month until 31Mar2007.
>That should return 30Apr06 31May06 30Jun06 ... 28Feb07 31Mar07"
>
>| schedule |
>schedule := OrderedCollection new.
>(Timeperiod from: (YearMonthDay year: 2006 month: 4 day: 1) duration:
>(CalendarDuration years: 1 months: 0 days: 0))
>	monthsDo: [:month | schedule add: month last].
>schedule => OrderedCollection (2006-04-30 2006-05-31 2006-06-30
>2006-07-31
>2006-08-31 2006-09-30 2006-10-31 2006-11-30 2006-12-31 2007-01-31
>2007-02-28
>2007-03-31)
>
>
With Chalten, the code would be:
(April, 2006 to: March, 2007) collect: [ :aMonthOfYear | aMonthOfYear
lastDate ]

or:

((GregorianMonth april yearNumber: 2006) to: (GregorianMonth march
yearNumber: 2007)) collect: [ :aMonthOfYear | aMonthOfYear lastDate ]

>"- Adjust the previous schedule to the british and japanese calendar,
>making sure all dates are 'good business days'. So, for example, if
>30Apr06 falls on Sunday or a british bank holiday, change it according to
some rule.
>Examples of such rules are:
>next business day, next calendar day, etc.
>
>It gets more complicated when you think about DCC (day count conventions).
>In the first example we were dealing with actual months. But under the
>30/360 DCC, every month has 30 days."
>
>Chronos doesn't currently support the Japanese Imperial Calendar. I
>haven't actually looked at that one, so I don't know how easy or hard
>it may be to implement.  However, once implemented, adding new
>calendars to Chronos is quite easy.
>
>SemanticDatePolicy instances can be used to define holiday schedules
>using any combination of supported calendars.  Extensible observance
>rules are supported.  US Holidays (including all rule-based and
>one-time-only-historical NYSE holidays) are predefined; others must be
>added by the programmer.
>
>So, modifying the first example to handle US banking holidays would
>look like this:
>
>| sdp holidays schedule dateSelector |
>sdp := SemanticDatePolicy unitedStates.
>holidays := SemanticDatePolicy usFederalHolidaySemanticKeys.
>schedule := OrderedCollection new.
>dateSelector :=
>	[:date |
>	date dayOfWeekKey == #Sunday
>		ifTrue: [dateSelector value: (date addingDays: 1)]
>		ifFalse:
>			[(date annualDateSemanticKeyFrom: sdp satisfies:
>[:semanticKey | holidays includes: semanticKey])
>				ifTrue: [dateSelector value: (date
>addingDays: 1)]
>				ifFalse: [date]]].
>(Timeperiod from: (YearMonthDay year: 2006 month: 4 day: 1) duration:
>(CalendarDuration years: 1 months: 0 days: 0))
>	monthsDo: [:month | schedule add: (dateSelector value: month last)].
>schedule => OrderedCollection (2006-05-01 2006-05-31 2006-06-30
>2006-07-31
>2006-08-31 2006-09-30 2006-10-31 2006-11-30 2007-01-02 2007-01-31
>2007-02-28
>2007-03-31)
>
>The 30/360 DCC is trivial to implement, using CalendarDurations and
>Timeperiods.
>
>
Because we created Chalten to deal with financial software, this kind of
problem are easy to solved.
There is an abstraction called "TimeLineFilter" that allows you to filter
the time line of any granularity and walk over the filtered time points.
So, to get due working days, the code would be:

(April, 2006 to: March, 2007) collect: [ :aMonthOfYear | MonthBasedDueDate
for: aMonthOfYear lastDate in: britishWorkingDays ]

With this code you will get all the due date in as working days of the
british working calendar.
The britishWorkingDays object is a TimeLineFilter, that can be created this
way:

britishNonWorkingDays := TimeLineFilter new.
britisNonWorkingDays
    addDayRule: GregorianDay saturday;
    addDayRule: GregorianDay sunday;
    addDayOfMonthRule: December twentyFifth.
britishWorkingDays := britishNonWorkingDays negated.

As you can see, you first create a filter that includes the non working days
(because they are less that the working days) and the you the the "negated"
filter, that is the working days.

About the day count conventions like 30/360, 30/365, Actual/Actual, etc.
that are used to calculate the "real" interest rate to pay for an
investment, we also have objects to deal with that but they are not part of
Chalten because that is a pure financial problem. But to deal with them we
use an abstraction that we have in Aconcagua (the measure's model that we
opened too) called "Evaluation". An Evaluation is an object that has a
meaning by itself but it is used in arithmetic operations. A good example of
Evaluation is a class we called Interest.
For example:

(Interest simpleFor: 1000 * dollar with: (InterestRate yearlyOf: 1/10)
during: 2 * TimeUnits year) value --> This will return 200 dollars.
(dollar is a unit, 1000 * dollar creates the measure 1000 dollars. 2 *
TimeUnits year create the measure 2 years).

Another example of Evaluation in the financial domain InterestRate,
NetPayment, GrossPayment, etc. (In physics Speed, Aceleration, etc. are good
examples).

Hernan.

>"Dates can be seen from many different points of view. In a financial
>system we are certainly not interested in the duration of a date. Not
>in nanoseconds, not in milliseconds or even hours. A date is a business
date."
>
>The class Chronos YearMonthDay is implemented just that way, for just
>that reason.
>
>Thanks for your questions. I'll be adding the second example to the
website.
>
>--Alan
>
>-----Original Message-----
>From: squeak-dev-bounces at lists.squeakfoundation.org
>[mailto:squeak-dev-bounces at lists.squeakfoundation.org] On Behalf Of
>Francisco Garau
>Sent: Friday, April 14, 2006 3:31 AM
>To: The general-purpose Squeak developers list; Alan Lovejoy
>Subject: Re: The Timing of Time
>
>Hi Alan,
>
>As yourself, I am also interested in date and times. I tried loading
>the Chronos package following the instructions from your website [1],
>but something went awry.
>
>I succesfully loaded:
>    1- Passport-Kernel
>    2- Passport-Squeak
>    3- Chronos-System-Squeak
>    4- Chronos-System-Squeak-PostV3.6
>
>The problem happens on step 3. The last two lines of that fileOut says:
>
>    ChronosSqueakEnvironment initialize !
>    ChronosEnvironment canonical install !
>
>I guess that ChronosEnvironment should be a class and canonical a message.
>But neither of them are in the image.
>
>My interest on dates is more biased towards dates than towards times.
>Dates, months, years and calendars are central objects in financial
systems.
>Amongst the many problems that arises in such systems, here a couple of
>examples:
>
>- Starting on the 31Mar2006 generate a schedule of payments every month
>until 31Mar2007.
>That should return 30Apr06 31May06 30Jun06 ... 28Feb07 31Mar07
>
>- Adjust the previous schedule to the british and japanese calendar,
>making sure all dates are 'good business days'. So, for example, if
>30Apr06 falls on Sunday or a british bank holiday, change it according to
some rule.
>Examples of such rules are:
>next business day, next calendar day, etc.
>
>It gets more complicated when you think about DCC (day count conventions).
>In the first example we were dealing with actual months. But under the
>30/360 DCC, every month has 30 days.
>
>Dates can be seen from many different points of view. In a financial
>system we are certainly not interested in the duration of a date. Not
>in nanoseconds, not in milliseconds or even hours. A date is a business
date.
>
>I agree with the Mercap guys that dates, months and years are views of
>the same time-line at different levels of granularity. In financial
>systems we don't need to go further down that date. For other type of
>systems requiring global syncronization, you probably need to go down
>to the millisecond level. Furthermore, you need every time to be
>expressed as an offset from a central location (Greenwich?).
>
>That is my poor understanding of time-zones and the reason why I want
>to play with the Chronos package.
>
>Cheers,
>Francisco
>
>[1] http://chronos-st.org/frames/Squeak-Downloads.html
>[2]
>http://article.gmane.org/gmane.comp.lang.smalltalk.squeak.general/10014
>8
>
>
>
>
>
>
>
>


--
______________________________
Lic. Hernán A. Wilkinson
Gerente de Desarrollo y Tecnología
Mercap S.R.L.
Tacuari 202 - 7mo Piso - Tel: 54-11-4878-1118 Buenos Aires - Argentina
http://www.mercapsoftware.com
---------------------------------------------------------------------
Este mensaje es confidencial. Puede contener informacion amparada por el
secreto profesional. Si usted ha recibido este e-mail por error, por favor
comuniquenoslo inmediatamente via e-mail y tenga la amabilidad de eliminarlo
de su sistema; no debera copiar el mensaje ni divulgar su contenido a
ninguna persona. Muchas gracias.

This message is confidential. It may also contain information that is
privileged or otherwise legally exempt from disclosure. If you have received
it by mistake please let us know by e-mail immediately and delete it from
your system; you should also not copy the message nor disclose its contents
to anyone. Thanks.
 ---------------------------------------------------------------------






More information about the Squeak-dev mailing list