Android Question Regular expression for date

Sergey_New

Well-Known Member
Licensed User
Longtime User
I made a pattern for the date in the format "dd MMM yyyy", for example 11 Jun 2025:
B4X: Copy
^([0-9]?|[0-2][0-9]||3[0-1])\s(\S+)\s(\d+)$
Please help me improve it so that if the day, month, year value is missing, the remaining data in each group is determined.
 
I made a pattern for the date in the format "dd MMM yyyy", for example 11 Jun 2025:
B4X: Copy
^([0-9]?|[0-2][0-9]||3[0-1])\s(\S+)\s(\d+)$
Please help me improve it so that if the day, month, year value is missing, the remaining data in each group is determined.
Rough and ready but this should help....

[Edit] Fixed for 3 letter months

B4X: Copy
Sub ParseDate(Input As String) As String
    Dim pattern As String = _
      "^(?:([0-9]|[12][0-9]|3[01])\s*)?" & _  '
      "(?:([A-Za-z]{3,}))?\s*"       & _     '
      "(\d{4})?$"
 
    Dim m As Matcher = Regex.Matcher(pattern, Input.Trim)
    If Not (m.Find) Then
        Log("Invalid date format: " & Input)
        Return ""
    End If

    Dim dayStr   As String = m.Group(1)
    Dim monthStr As String = m.Group(2)
    Dim yearStr  As String = m.Group(3)

    If dayStr = Null Or dayStr = "" Then
        dayStr = DateTime.GetDayOfMonth(DateTime.Now)
    End If

    If monthStr = Null Or monthStr = "" Then
        Dim mn As Int = DateTime.GetMonth(DateTime.Now)
        monthStr = Array As String( _
          "Jan","Feb","Mar","Apr","May","Jun", _
          "Jul","Aug","Sep","Oct","Nov","Dec" )(mn - 1)
    Else
        monthStr = monthStr.SubString2(0,1).ToUpperCase & _
                   monthStr.SubString2(1,3).ToLowerCase
    End If

    If yearStr = Null Or yearStr = "" Then
        yearStr = DateTime.GetYear(DateTime.Now)
    End If

    If dayStr.Length = 1 Then dayStr = "0" & dayStr

    Return dayStr & " " & monthStr & " " & yearStr
End Sub

Each of these work as expected

B4X: Copy
    ' Assuming today Is June 11, 2025
    Log(ParseDate("5"))             '05 Jun 2025
    Log(ParseDate("5 2023"))        '05 Jun 2023
    Log(ParseDate("5 Jul"))         '05 Jul 2025
    Log(ParseDate("Apr"))           '11 Apr 2025
    Log(ParseDate("5 July 2023"))   '05 Jul 2023
    Log(ParseDate("2024"))          '11 Jul 2024
 
Last edited:
Upvote 0
John Naylor, thanks!
I probably didn't explain it well.
The string to parse could be:
11
11 Jun
11 Jun 2025
2025
3 groups of values should be returned:
Day in group 1
Month in group 2
Year in group 3
 
Upvote 0
Lol we used to have a date parsing routine that you could throw anything at, and it would give you back the most-likely interpretation, including knowing that a number > 12 then it must be a day-of-month, and not a month, and likewise that a number > 31 must be a year.

I would still have that code, but on a cd buried in the garage, so... probably simpler to rewrite.

Is this for something where the user types in a date manually, ie not parsing an input file?
 
Upvote 0
Are the months *ALWAYS* in letter form?

Because that makes things a crapload easier, especially if you can also guarantee that there will also always be a non-alphanumeric separator between fields and/or that years are always 4 digits, so that we're not left wondering if eg "18" means the 18th day or 2018 (or perhaps 1918 if it is a birthdate).
 
Upvote 0
This seems to do the parsing, and then you just have to replace the blank fields with the current date values:

Code: Copy
(\d{0,2})\D?([A-Z]*[a-z]*|)\D?(\d{4}|)

It should also work even if there are no separators (relying on the year being 4 digits, if present).
 
Last edited:
Upvote 0
John Naylor, thanks!
I probably didn't explain it well.
The string to parse could be:
11
11 Jun
11 Jun 2025
2025
3 groups of values should be returned:
Day in group 1
Month in group 2
Year in group 3
That's easy enough just return a map


B4X: Copy
Sub ParseDate(Input As String) As Map        'Change this

'and return a map

    Dim rMap As Map
    rMap.Initialize
    rMap.Put ("Day", dayStr)
    rMap.Put ("Month", monthStr)
    rMap.Put ("Year", yearStr)

    Return rMap

From what I can see it works as you need now
 
Upvote 0
From my log -

11 becomes - (MyMap) {Day=11, Month=Jun, Year=2025}
11 Jun becomes - (MyMap) {Day=11, Month=Jun, Year=2025}
11 Jun 2025 becomes - (MyMap) {Day=11, Month=Jun, Year=2025}
2025 becomes - (MyMap) {Day=11, Month=Jun, Year=2025}
 

Attachments

Upvote 0
From my log
I need to get:
11 becomes - (MyMap) {Day=11, Month="", Year=""}
11 Jun becomes - (MyMap) {Day=11, Month=Jun, Year=""}
11 Jun 2025 becomes - (MyMap) {Day=11, Month=Jun, Year=2025}
2025 becomes - (MyMap) {Day="", Month="", Year=2025}
 
Upvote 0
Rethink to give the result how you need it - Give this a try

B4X: Copy
Sub ParseDate(Input As String) As Map
    Dim rMap As Map
    rMap.Initialize
    rMap.Put("Day", "")
    rMap.Put("Month", "")
    rMap.Put("Year", "")
    
    ' Split into tokens on spaces
    Dim tokens() As String = Regex.Split(" +", Input.Trim)
    
    ' Lower-case list of month names/abbrevs
    Dim monthNames As List
    monthNames.Initialize
    monthNames.AddAll(Array As String( _
        "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec", _
        "january","february","march","april","may","june","july","august","september","october","november","december" _
    ))
    
    For Each t As String In tokens
        Dim lc As String = t.ToLowerCase
        
        ' 1–2 digit day?
        If Regex.IsMatch("^[0-9]{1,2}$", lc) Then
            rMap.Put("Day", t)
            
            ' 4-digit year?
        Else If Regex.IsMatch("^[0-9]{4}$", lc) Then
            rMap.Put("Year", t)
            
            ' month name/abbr?
        Else If monthNames.IndexOf(lc) > -1 Then
            rMap.Put("Month", t)
        End If
    Next
    
    Return rMap
End Sub

[Code edited so the words Day, Month, Year in the map are capitalized]

Results -

6 becomes - (MyMap) {day=6, Month=, Year=}
11 becomes - (MyMap) {day=11, Month=, Year=}
11 Jun becomes - (MyMap) {day=11, Month=Jun, Year=}
11 Jun 2025 becomes - (MyMap) {day=11, Month=Jun, Year=2025}
2025 becomes - (MyMap) {day=, Month=, Year=2025}
 
Last edited:
Upvote 0
It doesn't work
I am running your test code


B4X: Copy
Sub Activity_Create(FirstTime As Boolean)
    Dim s As String
    s="11 Jun 2025"
   ' s="11 Jun"
    's="11"
    's="2025"
    Dim m1 As Map=ParseDate(s)
    Log(m1.Get("Day"))
    Log(m1.Get("Month"))
    Log(m1.Get("Year"))
End Sub

gives me

Day:11
Month:Jun
Year:2025

s="11 Jun" gives
Day: 11
Month: Jun

s="11" gives
Day: 11

s="2025" gives
Year: 2025
 
Upvote 0
See post #11
I was wrong, I didn't see that empty lines are not visible. I'm testing again now.
 
Upvote 0
11 Jun 2025
(MyMap) {Day=11, Month=Jun, Year=2025}
Day - 11
Month - Jun
Year - 2025

11 Jun
(MyMap) {Day=11, Month=Jun, Year=}
Day - 11
Month - Jun
Year -

11
(MyMap) {Day=11, Month=, Year=}
Day - 11
Month -
Year -

2025
(MyMap) {Day=, Month=, Year=2025}
Day -
Month -
Year - 2025
 

Attachments

Upvote 0
Everything is OK.
Tell me why this is:
B4X: Copy
Dim lc As String = t.ToLowerCase
Because month names should only be like this:
B4X: Copy
monthNames.AddAll(Array As String("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"))
If the name is incorrect, there should be an error message.
If possible, please correct your code.
 
Upvote 0
Back
Top