I tried package dateutil to extract date part from string. It works good if the exact date included in the string, like:
from dateutil.parser import parse
try:
date = parse(string, fuzzy=True)
print(str(date)[:10])
except ValueError:
print("no date in text")
string = "an example of date:8 march 2019"
output: 2019-03-08
string = "an example of date: 2019/3/8"
output: 2019-03-08
string = "an example of pure string"
output: no date in text
But when a number is included in string instead of date, it goes wrong and considers it as a date:
string = "an example of wrong date: 8"
output: 2022-03-08
My question here is, how can I use this package or similar packages to solve this problem. There are some posts related to extracting dates, like Extract date from string in python, but they have not covered this topic and they work for specific date format.
Your help much appreciated!
It seems that you want to exploit the powerful ability of dateutil module to parse free-form dates but the default variety of dates it attempts to parse and the default normalization rules (using the current month/year when it is missing from the date) is not what you need.
One of the things you can do, is not to attempt parsing the value as a date using dateutil if it is parseable as integer value or when no digit is in the string to be parsed.
So my suggestion to satisfy these two pre-conditions (and you can extend the list therefore eliminating the default misinterpretations of dateutil in your case):
import re
from dateutil.parser import parse
try:
v = int(string)
print("Seems like integer.")
except ValueError: # requires that the date does not parse as proper int
if re.search( r'\d', string) is not None: # requires a digit in the string
try:
date = parse(string, fuzzy=True)
print(str(date)[:10])
except ValueError:
print("no date in text")
else:
print("Can't parse")
I have a .txt file that contains the string "2020-08-13T20:41:15.4227628Z"
What format code should I use in strptime function in Python 3.7? I tried the following but the '8' at end just before 'Z' is not a valid weekday
from datetime import datetime
timestamp_str = "2020-08-13T20:41:15.4227628Z"
timestamp = datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%f%uZ')
ValueError: time data '2020-08-13T20:41:15.4227628Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%uZ'
your timestamp's format is mostly in accordance with ISO 8601, except for the 7 digit fractional seconds.
The 7th digit would be 1/10th of a microsecond; normally you'd have 3, 6 or 9 digits resolution (milli-, micro or nanoseconds respectively).
The Z denotes UTC
In Python, you can parse this format conveniently as I show here.
The 7 digits following the . appear to be a number of nanoseconds. You may have a platform-specific format (defined by strftime(3)) available to use in place of %f, but if not, your best bet is to drop the trailing digit before attempting to parse the remaining string as a timestamp.
regex = "(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}).(\d.*)"
if (m := re.match(regex, timestamp_str) is not None:
timestamp_str = "".join(m.groups())
timestamp = datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%fZ')
My input to this is in the format 07:05:09PM
expected output:
19:05:09
output got:
19:5:9
def timeConversion(s):
if "AM" in s:
print(s[1:8])
else:
string=s.split(':')
print(string)
string.append(string[2][0:2])
string.remove(string[2])
print(string)
date=list(map(int, string))
print(date)
a=date[0]+12
b='%s:%s:%s' % (a, date[1], date[2])
return b
My question is when I convert the date from string to int using map the zero is not picked up, is there any way to get the integer as such???
If you don't want to use a custom function for formatting datetimes, you can get the intended output by formatting your string when you print it. Replace this line
b='%s:%s:%s' % (a, date[1], date[2])
with this:
b='%02d:%02d:%02d' % (a, date[1], date[2])
there are functions for converting 24h to 12h time :
Load the string into a datetime object via strptime(), then dump via strftime() in the desired format:
from datetime import datetime
d = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
d # d is a string '2016-04-28 07:46:32'
datetime.strptime(d, "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d %I:%M:%S %p")
'2016-04-28 07:46:32 AM'
Note that the %I here is a 12-hour clock
Conversion of 24 hours date/time to 12 hours format and vice-versa
if you want to use your solution you can add leading zeros to integrs like in How to add Trailing zeroes to an integer :
numbers = [1, 19, 255]
numbers = [int('{:<03}'.format(number)) for number in numbers]
you can print leading zeros like in Display number with leading zeros
Hi i have written regex to check where ther string have the char like - or . or / or : or AM or PM or space .The follworig regex work for that but i want to make case fail if the string contain the char other than AMP .
import re
Datere = re.compile("[-./\:?AMP ]+")
FD = { 'Date' : lambda date : bool(re.search(Datere,date)),}
def Validate(date):
for k,v in date.iteritems():
print k,v
print FD.get(k)(v)
Output:
Validate({'Date':'12/12/2010'})
Date 12/12/2010
True
Validate({'Date':'12/12/2010 12:30 AM'})
Date 12/12/2010
True
Validate({'Date':'12/12/2010 ZZ'})
Date 12/12/2010
True (Expecting False)
Edited:
Validate({'Date':'12122010'})
Date 12122010
False (Expecting False)
How could i find the string have other than the char APM any suggestion.Thanks a lot.
Give this a try:
^[-./\:?AMP \d]*$
The changes to your regex are
It's anchored with ^ and $ which means that the whole line should match and not partially
the \d is added to the character class to allow digits
Now the regex basically reads as list of symbols that are allowed on 1 lines
If you want the empty string not to match then change the * to a +
You could use an expression like this instead:
^[-0-9./:AMP ]+$
^ and $ anchor the expression at the beginning and end of string, making sure there is nothing else in it (except an optional new line after $).
The way you approach this is too naive to deal with garbled input like '-30/A-MP/2012/12', '-30/A-MP/20PA12/12'.
If you want to validate your dates robustly, how about:
import datetime
date = '12-12-2012 10:45 AM'
formats = ("%d-%m-%Y %I:%M %p", "%d/%m/%Y %I:%M %p", ...)
for fmt in formats:
try:
valid_date = datetime.datetime.strptime(date, fmt)
except ValueError as e:
print(e)
You would have to define all possible formats, but you will get full datetime objects (or time or date objects, they work similar), and you can be absolutely sure they are valid. For a full explanation of the available format specifiers: http://docs.python.org/library/time.html#time.strftime
Kind of elaborate, but does the trick.
import re
Datere = re.compile("""
^(?:\d\d[-./\:]){2} ## dd_SEP_dd
\d{4}\s* ## year may be followed by spaces
(?:\d\d[-./\:]\d\d\s+(?:AM|PM))? ## hh_SEP_mm spaces followed by AM/PM and this is optional
\s*$""",re.X)
FD = { 'Date' : lambda date : bool(re.search(Datere,date)),}
def Validate(date):
for k,v in date.iteritems():
print k,v
print FD.get(k)(v)
print Validate({'Date':'12/12/2010'})
print Validate({'Date':'12/12/2010 12:30 AM'})
print Validate({'Date':'12/12/2010 ZZ'})
What regular expression in Python do I use to match dates like this: "11/12/98"?
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.
I find the below RE working fine for Date in the following format;
14-11-2017
14.11.2017
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'
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.
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
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'
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".
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
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])
I use something like this :
string="text 24/02/2021 ... 24-02-2021 ... 24_02_2021 ... 24|02|2021 text"
new_string = re.sub(r"[0-9]{1,4}[\_|\-|\/|\|][0-9]{1,2}[\_|\-|\/|\|][0-9]{1,4}", ' ', string)
print(new_string)
out : text ... ... ... text
If you don't want to raise ValueError exception like in methods with datetime, you can use re. Maybe you should also check that day of month lower than 31 and month number is lower than 12, inclusive:
from re import search as re_search
date_input = '31.12.1998'
re_search(r'^(3[01]|[12][0-9]|0[1-9]).(1[0-2]|0[1-9]).[0-9]{4}$', date_input)
With datetime good answer gave #unutbu earlier.
In case anyone wants to match this type of date "24 November 2008"
you can use
import re
date = "24 November 2008"
regex = re.compile("\d+\s\w+\s\d+")
matchDate = regex.findall(date)
print(matchDate)
Or
import re
date = "24 November 2008"
matchDate = re.findall("\d+\s\w+\s\d+", date)
print(matchDate)
This regular expression for matching dates in this format "22/10/2021" works for me :
import re
date = "WHATEVER 22/10/2029 WHATEVER"
match = re.search("([0-9]|1[0-9]|2[0-9]|3[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-5])/([0-9][0-9][0-9][0-9])", date)
print(match)
OUTPUT = <re.Match object; span=(9, 19), match='22/10/2029'>
You can see in the fourth line that there is this string ([0-9]|1[0-9]|2[0-9]|3[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-5])/([0-9][0-9][0-9][0-9]), this is the regular expression that I made based in this page.