.parsetime; da.parsetime.muf - parse a string into a systime


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.


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.


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: 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.
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.
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.

Implied dates

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.


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:

Date is overspecified. Part of the date was given twice.
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.
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 of valid times

5 pm
Today or tomorrow.
As above.
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.
Underspecified - no time given.


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).


Deborah Pickett (<Ariel> on FDCMuck).