A date-time string consists of a date string, optionally
followed by letter “T”
(case-insensitive) and a time string. T_PATTERN is a regular expression that matches
either case of “T”.
# - - - p a r s e D a t e t i m e
T_PATTERN = re.compile ( '[tT]' )
def parseDatetime ( s ):
"""Parse a date with optional time.
[ s is a string ->
if s is a valid date with optional time ->
return that timestamp as a datetime.datetime instance
else -> raise SyntaxError ]
"""
In general, date-time expressions can be quite complex.
Using Python's re package, we might write
a regular expression to match all the cases, but it would
be huge. Just for conceptual clarity, we'll break into
two sub-problems: we'll use Section 9.7, “parseDate(): Convert an external date
string”
to process the date, and we'll use Section 9.8, “parseTime(): Convert an external time
string” to process the time if there is one.
If s does not contain letter “T” or “t”,
then it must represent just a date; use parseDate() to convert it. If there is a
“T”, break the string in two
at that point, send the pieces to parseDate() and parseTime(), and
reassemble them.
The .search() method on a compiled regular
expression finds the first occurrence of a pattern
anywhere in its argument; the returned match object has methods .start() and .end() that delineate where the match occurred.
#-- 1 --
# [ if s contains "T" or "t" ->
# rawDate := s up to the first such character
# rawTime := s from just after the first such
# character to the end
# else ->
# rawDate := s
# rawTime := None ]
m = T_PATTERN.search ( s )
if m is None:
rawDate, rawTime = s, None
else:
rawDate = s[:m.start()]
rawTime = s[m.end():]
The parseDate() function will handle
checking and conversion of the date part.
#-- 2 --
# [ if rawDate is a valid date ->
# datePart := rawDate as a datetime.datetime instance
# else -> raise SyntaxError ]
datePart = parseDate ( rawDate )
If rawTime is not None, we
call Section 9.8, “parseTime(): Convert an external time
string” to validate and convert
it, and store the result in timePart. If
rawTime is None, there is
no time, so we'll set timePart to a datetime.time instance representing 00:00.
#-- 3 --
# [ if rawTime is None ->
# timePart := 00:00 as a datetime.time
# else if rawTime is valid ->
# timePart := rawTime as a datetime.time
# else -> raise SyntaxError ]
if rawTime is None:
timePart = datetime.time ( 0, 0 )
else:
timePart = parseTime ( rawTime )
The static .combine() method of class
datetime.datetime takes a datetime.date and a datetime.time
and combines them to produce a datetime.datetime instance.
#-- 4 --
return datetime.datetime.combine ( datePart, timePart )