NAME
.parsetime
; da.parsetime.muf - parse a string
into a systime
SYNOPSIS
- Input parameters:
- S[4]: dbref, object whose locale to use for language.
S[3]: dbref, object whose locale to use for time zone.
S[2]: integer, local systime representing "now".
S[1]: integer, local systime to force inferences to be after.
S[0]: string, description of time to parse.
- Output parameters:
- S[1]: integer, local systime containing parsed time.
-
S[0]: integer, flags indicating validity of S[1]. Bit values:
- 1: Date is overspecified.
2: String contains an unknown word.
4: Date is underspecified.
DESCRIPTION
da.parsetime.muf is a program which understands many date and time
specifications in English (or whatever language you have set for your
time locale; type date
-locale
to set this information, or timelib for detailed
information about locales).
You can use parsetime to process a user-supplied date or time
and return an integer similar to that returned by the
systime
MUF primitive. In this respect it fills a niche
somewhat opposite in function to strftime
.
Invocation
To use parsetime you need to give it two dbrefs. Often these
will be the same, but in the case of needing to use different language
locale and time zone information (such as used by date
in its time conversions) they
may differ. The language locale dbref in S[4] is only used for
determining the names of weekdays, months and 12-hour time indicators,
so that they can be matched against words. The time zone locale dbref
in S[3] is used only to convert the time from UTC if the
"utc" word is used.
Then you must give two times, as a local systime, i.e., the number of
seconds since 00:00:00 January 1, 1970 in the current time
zone (not necessarily UTC). The first time in S[2] is used whenever
parsetime needs to refer to the current time, in such words
as "now" or "tomorrow".
While you would normally want this to be the actual current time when
you call parsetime you might conceivably want otherwise (as
events does). The second
time is only used if parsetime needs to make inferences about the date.
parsetime will only choose an implied date on or after the
time in S[1]. Again, this will usually be the current time, but there
are times when you want to imply a time that is definitely later than
now, in which case you would add 1 to S[1] (events does
this). Finally you push the string to parse onto the stack and call
parsetime with the convenient macro .parsetime
.
parsetime examines its input one word at a time, in strict
left-to-right order. It does not employ any lookahead, so that when a
word depends on context, it only depends on the context of previous
words. Words are separated by spaces. This means that
spacing is very important! If you don't place spaces in the right
spots, you will get an error or occasionally the wrong time.
String format
To satisfy parsetime, you will have to give it one or more
words until you have specified the time enough for parsetime
to guess the rest. The words must collectively specify each of:
- time of day
- day of month
- month
- year
for parsetime to successfully process the entire string. If
parts are unspecified (with the exception of certain inferences parsetime knows about)
then the parsing fails. Conversely, if parts of the date are
overspecified, then parsing also fails, even if the two parts
concur. For instance, don't say "Thursday April 11
1996", because that specifies the date twice. Leave off the
weekday name.
The words may be:
now
- specifies time, day, month, year
- The current time.
today
- specifies day, month, year
- The current date.
tomorrow
- specifies day, month, year
- The day after the current date.
utc
- specifies that the time is given in Universal Coordinated Time (GMT)
and should be converted to local time.
noon
- specifies time
- 12:00:00, the middle of the day.
midnight
- specifies time
- 00:00:00, the middle of the night, considered to belong to the day
following it.
- weekday - specifies day, month, year
- These names are the same as your locale names for the weekdays, and
default to the English ones that exist in the Unix "C" locale.
You can use both short and long names. These always refer to the next
day after today with that name (note that this will never be today's
date).
- month - specifies month
- These names are the same as your locale names for the months, and
default to the English ones that exist in the Unix "C" locale.
You can use both short and long names.
- hour
:
minute:
second - specifies time
- Two or three numbers separated by colons (
:
) or full
stops (.
) indicate the time of day. You can omit the
seconds. The time is considered 24-hour unless you give am
or pm
too.
am
or pm
- To tell that a time given in 12-hour format is before or after noon,
use one of these words, or your own locale strings if you have changed
them. "12 am" is midnight; "12 pm" is noon.
- [
+
|-
]number[s
|m
|h
|d
|w
]
- Add or subtract a specified number of seconds, minutes, hours, days
or weeks to or from the time. Note that months and years are not
allowed since they are not all the same size. No spaces are allowed
within the word.
- number - specifies time or day or year
- The meaning of a lone number depends very much on the context.
If the number is over 1900, then it specifies a year (two-digit years are
not recognised, and in any case, they are a bad habit to be in this
close to a change of century).
If it looks like a date (for instance, the month has already been
specified but not the day, or the time of day is already specified, or it is over 23) then it specifies a day.
Otherwise it specifies a time. (Beware! This means that the 14 in
"14 February" means "2 pm on an unspecified
day in February". If you like
giving your days before months, use the syntax immediately
below. Alternatively, get into the habit of always giving the time of
day before the date.)
- number letters - specifies day
- Any number immediately followed by a non-number specifies a day of
the month,
even if the month has not been given. Thus "14th
February" means
"an unspecified time on the fourteenth day of February".
(Beware! This word format is intended to be used for appending the
strings
"st",
"nd",
"rd" and
"th" to numbers. You can in fact use any
letters, and indeed any symbol other than colon or full stop. But
parsetime will happily accept "2pm"
and assume that you mean the second day of a month. There must always
be a space before "pm" in this case.
Sometimes you can leave off information about a date and have
parsetime infer that you mean the next occurrence of this
date. If you leave off the day, month and year, then
parsetime will assume that you mean today, or tomorrow if
that time has already been passed today. This is usually what you want,
and you can always force today or tomorrow by saying
"today" or
"tomorrow".
If you specify the day of the month, but not the month or year, then
parsetime will assume you mean this month, or next month if
that date would be in the past. Note that no check is made that the
month actually has that many days.
If you give both the day and the month, but leave off the year, then
parsetime will assume that you mean this year or next year,
by the same reasoning as before.
No other inferences are done. For instance, you can't omit the time of
day, or give the day and year but not the month.
RETURN VALUE
parsetime returns two integers on the stack. The top of
stack is a bit vector which says if the value just beneath it is valid.
If the top of stack is zero, then all went according to plan and the
time in S[1] is the requested time.
Otherwise, S[0] is made up of the sum of the following numbers, and
indicates the according error condition:
- 1
- Date is overspecified. Part of the date was given twice.
- 2
- Unknown word. An unknown word was given. Note that this could be
because you are using the wrong language locale in S[4] on the input
stack.
- 4
- Date is underspecified. Part of the date hasn't been given. The
value returned in S[1] may or may not be close to what you want.
EXAMPLES
Examples of valid times
5 pm
- Today or tomorrow.
17:00
- As above.
now
- Always the current time (actually the time in S[2] on calling).
midnight Tuesday
- Just after 11:59 pm next Monday (and not today if today is a
Tuesday).
8:30 am 19 January
- This year or next year.
8:30 am 19 January -2w
- Two weeks before the above time (if it's now between 8:30 am on
January 5 and 8:30 am on January 19, then this will give the time for
next year because subtracting two weeks made the date in the past).
now +1d
- This time tomorrow.
noon tomorrow utc
- My local time when it is 12 noon on tomorrow's date in the Greenwich
Mean Time zone.
Examples of invalid times
19 January 8:30 am
- 19 is interpreted as an hour, so the time is given twice
and the date is thus overspecified. To fix, swap date and time order in
the string, or type "19th" instead for force a
day-of-month.
now tomorrow
- Not this time tomorrow; date overspecified. See above for how to do
this.
today
- Underspecified - no time given.
BUGS
The strings "now",
"today",
"tomorrow",
"midnight",
"noon" and
"utc" are fixed and not really very
locale-friendly.
Not having look-ahead for context is perhaps a bit unfair, but it would
make the code many times more complex. Implementing a full grammar
would permit such wonderful syntaxes as "The second Sunday after
Easter", but it would tie down the grammar to a paricular language.
Few checks are made that the date actually exists. It is perfectly
possible to ask for 93 o'clock on the 39th day of February.
parsetime would return a date 93 hours after 38 days have
elapsed since the start of February, in other words 9 pm on March 14 (or
13 in a leap year).
AUTHOR
Deborah Pickett (<Ariel> on FDCMuck).