Irwin1985 / JSONFox

JSONFox is a free JSON parser written in Visual FoxPro 9.0
59 stars 34 forks source link

dateTime was being Parsed as String #49

Closed DanielCarlos231 closed 1 year ago

DanielCarlos231 commented 1 year ago

I had a dateTime format in "DD/MM/YYYY" and also "DD/MM/YYYY HH:MM:SS" After analizing the code I could detect that the jsonutils in the this.aPattern did not had a RegEx Pattern for that. So I Add those Patterns and some other date and dateTime formats. heres the code I changed:

&& jsonutils.Init()
Function init
  && Match a date format in the following pattern 
  && "YYYY-MM-DD"
  this.aPattern[1,1] = "^\d\d\d\d-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01])$"
  this.aPattern[1,2] = .f.

  && Match a date and time format in the following pattern
  && "YYYY-MM-DD HH:MM:SS"
  this.aPattern[2,1] = "^\d\d\d\d-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01]) (00|0?[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9])$"
  this.aPattern[2,2] = .f.

  && Match ISO 8601 date and time formats that include a time zone offset
  && "YYYY-MM-DDTHH:MM:SSZ" OR "YYYY-MM-DDTHH:MM:SS+HH:MM" OR "YYYY-MM-DDTHH:MM:SS-HH:MM"
  this.aPattern[3,1] = "^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})(\:(\d{2}))?(Z|[+-](\d{2})\:(\d{2}))?$"
  this.aPattern[3,2] = .f.

  && Match a date and time format in ISO 8601 combined with a single-character time zone identifier
  && "YYYY-MM-DDTHH:MM(:SS)?.SSS(W)" 
  this.aPattern[4,1] = "^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})(\:(\d{2}))?[.](\d{3})(\w{1})$"
  this.aPattern[4,2] = .f.

  && "DD/MM/YYYY" OR "DD-MM-YYYY"
  this.aPattern[5,1] = "^([0-2][0-9]|(3)[0-1])[\/-](((0)[0-9])|((1)[0-2]))[\/-]\d{4}$"
  this.aPattern[5,2] = .t.

  && "DD/MM/YYYY HH:MM:SS" or "DD-MM-YYYY HH:MM:SS"
  this.aPattern[6,1] = "^(\d{2})([\/-])(\d{2})\2(\d{4}) (\d{2}):(\d{2}):(\d{2})$"
  this.aPattern[6,2] = .t.

  && "DD/MM/YY HH:MM:SS" or "DD-MM-YY HH:MM:SS"
  this.aPattern[7,1] = "^(\d{2})([\/-])(\d{2})\2(\d{2}) ([0-1]\d|2[0-3]):([0-5]\d):([0-5]\d)$"
  this.aPattern[7,2] = .t.

  && "DD/MM/YY" or "DD-MM-YY"
  this.aPattern[8,1] = "^(\d{2})([\/-])(\d{2})\2(\d{2})$"
  this.aPattern[8,2] = .t.

  _screen.oRegEx.global = .t.

EndFunc

I just wanted to tell you about this, and check if you think that adding this dates formats are usefull. Also ask if in the RegEx I added to the version I have, setting the this.aPattern[x,2] as true is the correct approach. I know that it has to do with the date format DMY.

Irwin1985 commented 1 year ago

Yes, the second parameters indicates the YMD pattern in order to proper parse the string to DATE data type. The first 4th indexes are set to .F. because of the format (YMD).

BTW: you can send pull request and I merge your changes into the main branch, now you are an active colaborator and that's a great new for me and for this project.

DanielCarlos231 commented 1 year ago

The dateTime Format DD/MM/YYYY HH:MM:SS and also the DD-MM-YYYY HH:MM:SS were returning a null DateTime because they were not verifying the date format in the case occurs(':', tcDate) >= 2

&& Method formatDate() on jsonutils Class
do case
case 'T' $ tcDate && JavaScript or ISO 8601 format.
    do case
    case '+' $ tcDate
        tcDate = getwordnum(tcDate, 1, '+')
    case at('-', tcDate, 3) > 0
        tcDate = substr(tcDate, 1, at('-', tcDate, 3)-1)
    otherwise
    endcase
    try
        setDateAct = set('Date')
        set date ymd
        lDate = ctot('^'+tcDate)
    catch
        lDate = {//::}
    finally
        set date &setDateAct
    endtry
case occurs(':', tcDate) >= 2 && VFP Date Time Format. 'YYYY-mm-dd HH:mm:ss' 

    try
        setDateAct = set('Date')
        set date ymd    
        lDate = ctot(tcDate)
    catch
        lDate = {//::}
    finally
        set date &setDateAct
    endtry
otherwise
    try
        setDateAct = set('Date')
        if !tlUseDMY
            set date ymd
        else
            set date dmy
        endif
        lDate = ctod(tcDate)
    catch
        lDate = {//}
    finally
        set date &setDateAct
    endtry
endcase

So I added the

&& Also verify if the Date or DateTime is DMY Format
if !tlUseDMY
    set date ymd
else
    set date dmy
endif

Now it is like this:

&& ======================================================================== &&
&& Function FormatDate
&& return a valid date or datetime date type.
&& ======================================================================== &&
function formatDate as variant
  lparameters tcDate as string, tlUseDMY as Boolean
  local lDate
  lDate = .null.
  && IRODG 20210313 ISSUE # 14
  do case
  case 'T' $ tcDate && JavaScript or ISO 8601 format.
      do case
      case '+' $ tcDate
          tcDate = getwordnum(tcDate, 1, '+')
      case at('-', tcDate, 3) > 0
          tcDate = substr(tcDate, 1, at('-', tcDate, 3)-1)
      otherwise
      endcase
      try
          setDateAct = set('Date')
          set date ymd
          lDate = ctot('^'+tcDate)
      catch
          lDate = {//::}
      finally
          set date &setDateAct
      endtry
  case occurs(':', tcDate) >= 2 && VFP Date Time Format. 'YYYY-mm-dd HH:mm:ss' and also 'dd-mm-yyyy hh:mm:ss'

      try
          setDateAct = set('Date')
      * set date ymd

          && Also verify if the Date or DateTime is DMY Format
          if !tlUseDMY
              set date ymd
          else
              set date dmy
          endif

          lDate = ctot(tcDate)
      catch
          lDate = {//::}
      finally
          set date &setDateAct
      endtry
  otherwise
      try
          setDateAct = set('Date')
          if !tlUseDMY
              set date ymd
          else
              set date dmy
          endif
          lDate = ctod(tcDate)
      catch
          lDate = {//}
      finally
          set date &setDateAct
      endtry
  endcase
  return lDate
  && IRODG 20210313 ISSUE # 14
endfunc

I tested again and worked just fine

And many thanks for adding me as an active colaborator 😁😁😁 Let's improve this tool because it is a really uselfull and well organized tooll

Irwin1985 commented 1 year ago

I've sent you an invitation as collaborator. Every change you make remember to change the mayor version or revision in the JSONClass.prg file. Try creating your first pull request with these DATE format changes.

DanielCarlos231 commented 1 year ago

I already did the changes I just did not pull them yet, because I wanna confirm something before I do the pulls you said to change the mayor version in the JsonClass.prg, the version there is 9.12 so it should go to 10.12... that got me confused.. did I understand correctly... because I thought it should go from 9.12 to 9.13

because here in Brazil we call major version the first number on the version in this case is 9...

DanielCarlos231 commented 1 year ago

I changed the version from 9.12 to 9.13 and than I did the pull, if it is not the correct version number you tell me and I'll fix it

image

Irwin1985 commented 1 year ago

If you make a big change (new parsing method, new API method, etc) then you should change the mayor version (in this case from 9 to 10.0) but if you make small changes (fixing bugs, extends the number method, new date format, etc) that should change the revision version or menor version (in this case from 9.10 to 9.11).

DanielCarlos231 commented 1 year ago

Ok got it 😁