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:
^([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.
 

John Naylor

Active Member
Licensed User
Longtime User
I made a pattern for the date in the format "dd MMM yyyy", for example 11 Jun 2025:
B4X:
^([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:
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:
    ' 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

Sergey_New

Well-Known Member
Licensed User
Longtime User
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

emexes

Expert
Licensed User
Longtime User
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

emexes

Expert
Licensed User
Longtime User
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

emexes

Expert
Licensed User
Longtime User
This seems to do the parsing, and then you just have to replace the blank fields with the current date values:

Code:
(\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

Active Member
Licensed User
Longtime User
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:
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

John Naylor

Active Member
Licensed User
Longtime User
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

  • Project.zip
    14.2 KB · Views: 79
Upvote 0

Sergey_New

Well-Known Member
Licensed User
Longtime User
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

John Naylor

Active Member
Licensed User
Longtime User
Rethink to give the result how you need it - Give this a try

B4X:
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

Sergey_New

Well-Known Member
Licensed User
Longtime User
It doesn't work as I need it to. Also, all three required values should be returned in the map.
I've attached an example for testing.
 

Attachments

  • test.zip
    2.6 KB · Views: 77
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
It doesn't work
I am running your test code


B4X:
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

Sergey_New

Well-Known Member
Licensed User
Longtime User
See post #11
I was wrong, I didn't see that empty lines are not visible. I'm testing again now.
 
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
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

  • Project.zip
    14.2 KB · Views: 79
Upvote 0

Sergey_New

Well-Known Member
Licensed User
Longtime User
Everything is OK.
Tell me why this is:
B4X:
Dim lc As String = t.ToLowerCase
Because month names should only be like this:
B4X:
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
Top