There is a nifty function called TextCases
. One way to use it is to find text that can be interpreted as an entity type.
reportData = {"Los Angeles REPORT November 30, 2019 - December 31, 2020", "Chicago REPORT February 01, 2023 - February 28, 2023"};
TextCases[reportData, "Date"]
{{"November 30, 2019", "December 31, 2020"}, {"February 01, 2023", "February 28, 2023"}}
You can extract a "property" for the found cases:
TextCases[reportData, "Date" -> "Interpretation"]
The result now will be data entities. Since you only want the first instance for each string, you can use the optional third argument:
startDates = TextCases[reportData, "Date" -> "Interpretation", 1]
Finally, you can use DateValue to extract the year:
DateValue[#, "Year"] & /@ startDates
{{2019}, {2023}}
You can bundle this up into a function:
ExtractFirstDate[string_String] :=
With[
{first = TextCases[string, "Date" -> "Interpretation", 1]},
If[{} == first, Missing["No dates found"],
DateValue[first[[1]], "Year"]]]
...and apply it:
ExtractFirstDate /@ reportData
{2019, 2023}
(Note, these are integers.)
If you don't want to use TextCases or Date-specific functions, you could just use string pattern matching:
ExtractFirstDate2[string_String] :=
With[
{first =
StringCases[string,
WordCharacter .. ~~ Whitespace ~~ DigitCharacter .. ~~ "," ~~
Whitespace ~~ DigitCharacter .., 1]},
If[{} == first, Missing["No dates found"],
StringTrim@Last@StringSplit[first[[1]], ","]]]
...and
ExtractFirstDate2 /@ reportData
{"2019", "2023"}
(Note, these are strings.)