Python regex to match dates

Python Programming

Question or problem about Python programming:

What regular expression in Python do I use to match dates like this: “11/12/98”?

How to solve the problem:

Solution 1:

Instead of using regex, it is generally better to parse the string as a datetime.datetime object:

In [140]: datetime.datetime.strptime("11/12/98","%m/%d/%y")
Out[140]: datetime.datetime(1998, 11, 12, 0, 0)

In [141]: datetime.datetime.strptime("11/12/98","%d/%m/%y")
Out[141]: datetime.datetime(1998, 12, 11, 0, 0)

You could then access the day, month, and year (and hour, minutes, and seconds) as attributes of the datetime.datetime object:

In [143]: date.year
Out[143]: 1998

In [144]: date.month
Out[144]: 11

In [145]: date.day
Out[145]: 12

To test if a sequence of digits separated by forward-slashes represents a valid date, you could use a try..except block. Invalid dates will raise a ValueError:

In [159]: try:
   .....:     datetime.datetime.strptime("99/99/99","%m/%d/%y")
   .....: except ValueError as err:
   .....:     print(err)
   .....:     
   .....:     
time data '99/99/99' does not match format '%m/%d/%y'

If you need to search a longer string for a date,
you could use regex to search for digits separated by forward-slashes:

In [146]: import re
In [152]: match = re.search(r'(\d+/\d+/\d+)','The date is 11/12/98')

In [153]: match.group(1)
Out[153]: '11/12/98'

Of course, invalid dates will also match:

In [154]: match = re.search(r'(\d+/\d+/\d+)','The date is 99/99/99')

In [155]: match.group(1)
Out[155]: '99/99/99'

To check that match.group(1) returns a valid date string, you could then parsing it using datetime.datetime.strptime as shown above.

Solution 2:

I find the below RE working fine for Date in the following format;

  1. 14-11-2017
  2. 14.11.2017
  3. 14|11|2017

It can accept year from 2000-2099

Please do not forget to add $ at the end,if not it accept 14-11-201 or 20177

date="13-11-2017"

x=re.search("^([1-9] |1[0-9]| 2[0-9]|3[0-1])(.|-)([1-9] |1[0-2])(.|-|)20[0-9][0-9]$",date)

x.group()

output = ’13-11-2017′

Solution 3:

Using this regular expression you can validate different kinds of Date/Time samples, just a little change is needed.

^\d\d\d\d/(0?[1-9]|1[0-2])/(0?[1-9]|[12][0-9]|3[01]) (00|[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$ –>validate this: 2018/7/12 13:00:00

for your format you cad change it to:

^(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[0-2])/\d\d$ –> validates this: 11/12/98

Solution 4:

Well, from my understanding, simply for matching this format in a given string, I prefer this regular expression:

pattern='[0-9|/]+'

to match the format in a more strict way, the following works:

pattern='(?:[0-9]{2}/){2}[0-9]{2}'

Personally, I cannot agree with unutbu’s answer since sometimes we use regular expression for “finding” and “extract”, not only “validating”.

Solution 5:

Sometimes we need to get the date from a string.
One example with grouping:

record = '1518-09-06 00:57 some-alphanumeric-charecter'
pattern_date_time = ([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}) .+
match = re.match(pattern_date_time, record)
if match is not None:
  group = match.group()
  date = group[0]
  print(date) // outputs 1518-09-06 00:57

Solution 6:

I built my solution on top of @aditya Prakash appraoch:

 print(re.search("^([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0-1])(\.|-|/)([1-9]|0[1-9]|1[0-2])(\.|-|/)([0-9][0-9]|19[0-9][0-9]|20[0-9][0-9])$|^([0-9][0-9]|19[0-9][0-9]|20[0-9][0-9])(\.|-|/)([1-9]|0[1-9]|1[0-2])(\.|-|/)([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0-1])$",'01/01/2018'))

The first part (^([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0-1])(\.|-|/)([1-9]|0[1-9]|1[0-2])(\.|-|/)([0-9][0-9]|19[0-9][0-9]|20[0-9][0-9])$) can handle the following formats:

  • 01.10.2019
  • 1.1.2019
  • 1.1.19
  • 12/03/2020
  • 01.05.1950

The second part (^([0-9][0-9]|19[0-9][0-9]|20[0-9][0-9])(\.|-|/)([1-9]|0[1-9]|1[0-2])(\.|-|/)([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0-1])$) can basically do the same, but in inverse order, where the year comes first, followed by month, and then day.

  • 2020/02/12

As delimiters it allows ., /, -. As years it allows everything from 1900-2099, also giving only two numbers is fine.

If you have suggestions for improvement please let me know in the comments, so I can update the answer.

Solution 7:

As the question title asks for a regex that finds many dates, I would like to propose a new solution, although there are many solutions already.

In order to find all dates of a string that are in this millennium (2000 – 2999), for me it worked the following:

dates = re.findall('([1-9]|1[0-9]|2[0-9]|3[0-1]|0[0-9])(.|-|\/)([1-9]|1[0-2]|0[0-9])(.|-|\/)(20[0-9][0-9])',dates_ele)

dates = [''.join(dates[i]) for i in range(len(dates))]

This regex is able to find multiple dates in the same string, like bla Bla 8.05/2020 \n BLAH bla15/05-2020 blaa. As one could observe, instead of / the date can have . or , not necessary at the same time.

Some explaining

More specifically it can find dates of format day , moth year. Day is an one digit integer or a zero followed by one digit integer or 1 or 2 followed by an one digit integer or a 3 followed by 0 or 1. Month is an one digit integer or a zero followed by one digit integer or 1 followed by 0, 1, or 2. Year is the number 20 followed by any number between 00 and 99.

Useful notes

One can add more date splitting symbols by adding | symbol at the end of both (.|-|\/). For example for adding one would do (.|-|\/|--)

To have years outside of this millennium one has to modify (20[0-9][0-9]) to ([0-9][0-9][0-9][0-9])

Solution 8:

I use something like this

>>> import datetime
>>> regex = datetime.datetime.strptime
>>>
>>> # TEST
>>> assert regex('2020-08-03', '%Y-%m-%d')
>>>

>>> assert regex('2020-08', '%Y-%m-%d')
ValueError: time data '2020-08' does not match format '%Y-%m-%d'

>>> assert regex('08/03/20', '%m/%d/%y')
>>>

>>> assert regex('08-03-2020', '%m/%d/%y')
ValueError: time data '08-03-2020' does not match format '%m/%d/%y'

Hope this helps!