Is_Date() function for strings in mutiple possible formats

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Is_Date() function for strings in mutiple possible formats

Post by HGAutomator »

Is there an IS_Date() function, other than the standard one which determines if a variable is a date object?

I'm looking for something that can intelligently determine that a string could be a date, by analyzing whether it fits an mm/dd/yyyy or yyymmdd or other potential date formats.

In a sense, I'm really trying to determine if a string can NOT be a date.
User avatar
Claudio Ricardo
Posts: 367
Joined: Tue Oct 27, 2020 3:38 am
DBs Used: DBF, MySQL, MariaDB
Location: Bs. As. - Argentina

Re: Is_Date() function for strings in mutiple possible formats

Post by Claudio Ricardo »

Hi... Maybe:
Function Is_Date (xParam)
Return Iif ( ValType ( xParam ) == "D", .T., .F.)
Corrige al sabio y lo harás más sabio, Corrige al necio y lo harás tu enemigo.
WhatsApp / Telegram: +54 911-63016162
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: Is_Date() function for strings in mutiple possible formats

Post by HGAutomator »

Hi,

Thanks Claudio, but we're not looking at date variables. We're looking at strings that might be convertible to a date variable. Or rather, I'm looking at strings that can't possibly be converted to a date variable.

I need to determine whether a variable might contain a string date, or whether is obviously cannot. So the string "01012010" might refer to a date in the forms mmddyyyy or ddmmyyyy ; but the string "helloworld" or "31201313" cannot be dates.

I'm pretty sure I've seen something like this before, althought it might not have been Harbour.

Claudio Ricardo wrote: Thu Jul 08, 2021 7:24 pm Hi... Maybe:
Function Is_Date (xParam)
Return Iif ( ValType ( xParam ) == "D", .T., .F.)
wistong
Posts: 2
Joined: Fri Apr 01, 2016 3:13 pm

Re: Is_Date() function for strings in mutiple possible formats

Post by wistong »

Hola,
Prueba con :

dVar := "25-15-2021"

IF EMPTY( CTOD(dVar))
// Fecha Inválido
ELSE
// Fecha válida
ENDF


Ayuda :


CTOD()
Convert a date string to a date value
------------------------------------------------------------------------------
Syntax

CTOD(<cDate>) --> dDate

Arguments

<cDate> is a character string consisting of numbers representing the
month, day, and year separated by any character other than a number.
The month, day, and year digits must be specified in accordance with the
SET DATE format. If the century digits are not specified, the century
is determined by the rules of SET EPOCH.

Returns

CTOD() returns a date value. If <cDate> is not a valid date, CTOD()
returns an empty date.
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: Is_Date() function for strings in mutiple possible formats

Post by HGAutomator »

Thanks I'm familar with the date functions, but they all assume that the date string is in a specific format. I'm looking for a function that covers all possible formats. Also, it doesn't need to convert the string to a date ; it just needs to determine that it's IMPOSSIBLE to convert the string to a date.

So it would have to cover all possible date formats, regardless of the state of SET DATE or EPOCH.

Anyway, I'm searching through some of my old code, non-clipper/harbour. I'm nearly certain that this was done, somewhere.

If not, I'll build it from scratch.


Regards,




wistong wrote: Thu Jul 08, 2021 8:01 pm Hola,
Prueba con :

dVar := "25-15-2021"

IF EMPTY( CTOD(dVar))
// Fecha Inválido
ELSE
// Fecha válida
ENDF


Ayuda :


CTOD()
Convert a date string to a date value
------------------------------------------------------------------------------
Syntax

CTOD(<cDate>) --> dDate

Arguments

<cDate> is a character string consisting of numbers representing the
month, day, and year separated by any character other than a number.
The month, day, and year digits must be specified in accordance with the
SET DATE format. If the century digits are not specified, the century
is determined by the rules of SET EPOCH.

Returns

CTOD() returns a date value. If <cDate> is not a valid date, CTOD()
returns an empty date.
User avatar
danielmaximiliano
Posts: 2763
Joined: Fri Apr 09, 2010 4:53 pm
DBs Used: DBF
Location: Argentina
Contact:

Re: Is_Date() function for strings in mutiple possible formats

Post by danielmaximiliano »

se deberia usar expresiones regulares para saber si una fecha es correcta en diferenes formatos.
ej
1-4-94
01/04/94
01-04-1994
etc...
ZfcKj.png
ZfcKj.png (242.91 KiB) Viewed 1870 times
http://www.hmgforum.com/viewtopic.php?t=3382
*´¨)
¸.·´¸.·*´¨) ¸.·*¨)
(¸.·´. (¸.·` *
.·`. Harbour/HMG : It's magic !
(¸.·``··*

Saludos / Regards
DaNiElMaXiMiLiAnO

Whatsapp. := +54901169026142
Telegram Name := DaNiElMaXiMiLiAnO
Telegram invitation https://t.me/HMGWorkspace
User avatar
Claudio Ricardo
Posts: 367
Joined: Tue Oct 27, 2020 3:38 am
DBs Used: DBF, MySQL, MariaDB
Location: Bs. As. - Argentina

Re: Is_Date() function for strings in mutiple possible formats

Post by Claudio Ricardo »

Hola...
Se complica aún más, ya que necesita que sea independiente del Set Date... Nosotros usamos French o German "ddmmyyyy"
pero si lo ingresan como USA "mmddyyyy" o Japan "yyyymmdd" y sin Set Century On es "yy" (año en dos digitos)
Por ejemplo 101112 puede ser valido como 10 de noviembre de 2012 o 11 de octubre de 2012 o 12 de noviembre de 2010 respectivamente :(
Corrige al sabio y lo harás más sabio, Corrige al necio y lo harás tu enemigo.
WhatsApp / Telegram: +54 911-63016162
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: Is_Date() function for strings in mutiple possible formats

Post by HGAutomator »

Thanks Claudio,

For the file that we're analyzing, we don't have to worry about formats like

November 12, 2010

It'll be just digits ; or digits & slashes ; or digits & dashes.
Claudio Ricardo wrote: Fri Jul 09, 2021 7:04 am Hola...
Se complica aún más, ya que necesita que sea independiente del Set Date... Nosotros usamos French o German "ddmmyyyy"
pero si lo ingresan como USA "mmddyyyy" o Japan "yyyymmdd" y sin Set Century On es "yy" (año en dos digitos)
Por ejemplo 101112 puede ser valido como 10 de noviembre de 2012 o 11 de octubre de 2012 o 12 de noviembre de 2010 respectivamente :(
edk
Posts: 999
Joined: Thu Oct 16, 2014 11:35 am
Location: Poland

Re: Is_Date() function for strings in mutiple possible formats

Post by edk »

I used to need something similar that you ask. Maybe it will be helpful.

Code: Select all

#include <hmg.ch>

PROCEDURE Main()

	msgdebug (IsStringValidDate( "" ) )		//.F.

	msgdebug (IsStringValidDate( "30-02-1990" ))	//.F.

	msgdebug (IsStringValidDate( "01/02/2011" ), CheckStringValidDate( "01/02/2011" ))	//.T.

	msgdebug (IsStringValidDate( "2001\02\20" ))	//.T.

	msgdebug (IsStringValidDate( "12.20.2011" ))	//.T.

	msgdebug (IsStringValidDate( "12-20-11" ))	//.T.

	msgdebug (IsStringValidDate( "12.40.2011" ))	//.F.

	msgdebug (IsStringValidDate( "12.2011.20" ))	//.T.

	msgdebug (IsStringValidDate( "12402011" ), CheckStringValidDate( "12402011" ) )	//.T.  => 1240.20.11, 12.11.4020, 11.12.4020

	msgdebug (IsStringValidDate( "12402011",  hb_CtoD( "01/01/1990" , "dd/mm/yyyy" ) /* FromDate */ ,  hb_CtoD( "31/12/2050" , "dd/mm/yyyy" ) /* ToDate */ ))	//.F.

	msgdebug (IsStringValidDate( "310210" ), CheckStringValidDate( "310210" ) )	//.T.  => 31.10.1902, 1931.02.10, 1931.10.02

	msgdebug (IsStringValidDate( "310210",  hb_CtoD( "01/01/1990" , "dd/mm/yyyy" )  /* FromDate */ ,  hb_CtoD( "31/12/2050" , "dd/mm/yyyy" ) /* ToDate */ ))	//.F.

	msgdebug (IsStringValidDate( "12@40@2011" ))	//.F.

	msgdebug (IsStringValidDate( "12x40x2011" ))	//.F.

	msgdebug (IsStringValidDate( 1111 ))		//.F.

	msgdebug (IsStringValidDate( .F. ))		//.F.

	msgdebug (IsStringValidDate( ))			//.F.
RETURN


*************************************************************************
Function IsStringValidDate( cDate, dRangeFrom, dRangeTo )
Local lValidDate := Len ( CheckStringValidDate( cDate, dRangeFrom, dRangeTo ) ) > 0
RETURN lValidDate
*************************************************************************
Function CheckStringValidDate( cDate, dRangeFrom, dRangeTo  )

Local cSep:=".-/\ ", cDateCheck
Local i, j, nInsPos
Local isSep := .F.
Local aDateFormats:={ "dd/mm/yyyy", "dd/mm/yy",;
		      "mm/dd/yyyy", "mm/dd/yy", ;
		      "yyyy/mm/dd", "yy/mm/dd", ;
		      "yyyy/dd/mm", "yy/dd/mm", ;
		      "mm/yyyy/dd", "mm/yy/dd", ;
		      "dd/yyyy/mm", "dd/yy/mm" }, ;
      aTokens, aDates :={}
Local dDate


Default cDate := ""
Default dRangeFrom := CToD( "" ), dRangeTo := hb_CtoD( "31/12/9999" , "dd/mm/yyyy" )

IF !hb_isChar ( cDate )
	Return aDates
ENDIF

FOR i:=1 TO Len ( cDate )
	IF Substr( cDate, i, 1 ) $ cSep
		isSep := .T.
	ELSEIF !IsDigit( Substr( cDate, i, 1 ) )
		Return aDates
	ENDIF
NEXT i
	

FOR i:=1 TO Len ( aDateFormats )
	IF !isSep
		aTokens := hb_Atokens ( aDateFormats [i], "/" )
		cDateCheck := cDate
		nInsPos := 0
		FOR j := 1 TO Len ( aTokens ) - 1
			nInsPos += Len( aTokens [j]) + 1
			cDateCheck := Stuff(cDateCheck, nInsPos, 0, "/")
		NEXT j
	ELSE
		cDateCheck := cDate
	ENDIF
	dDate := hb_CtoD( cDateCheck , aDateFormats [i]) 
	IF !EMPTY( dDate ) .AND. dDate >= dRangeFrom .AND. dDate <= dRangeTo
		IF ASCAN ( aDates, dDate ) = 0
			AADD ( aDates, dDate )
		ENDIF
	ENDIF
NEXT i
RETURN aDates
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: Is_Date() function for strings in mutiple possible formats

Post by HGAutomator »

Perfect, edk. Thanks.

edk wrote: Fri Jul 09, 2021 10:37 am I used to need something similar that you ask. Maybe it will be helpful.

Code: Select all

#include <hmg.ch>

PROCEDURE Main()

	msgdebug (IsStringValidDate( "" ) )		//.F.

	msgdebug (IsStringValidDate( "30-02-1990" ))	//.F.

	msgdebug (IsStringValidDate( "01/02/2011" ), CheckStringValidDate( "01/02/2011" ))	//.T.

	msgdebug (IsStringValidDate( "2001\02\20" ))	//.T.

	msgdebug (IsStringValidDate( "12.20.2011" ))	//.T.

	msgdebug (IsStringValidDate( "12-20-11" ))	//.T.

	msgdebug (IsStringValidDate( "12.40.2011" ))	//.F.

	msgdebug (IsStringValidDate( "12.2011.20" ))	//.T.

	msgdebug (IsStringValidDate( "12402011" ), CheckStringValidDate( "12402011" ) )	//.T.  => 1240.20.11, 12.11.4020, 11.12.4020

	msgdebug (IsStringValidDate( "12402011",  hb_CtoD( "01/01/1990" , "dd/mm/yyyy" ) /* FromDate */ ,  hb_CtoD( "31/12/2050" , "dd/mm/yyyy" ) /* ToDate */ ))	//.F.

	msgdebug (IsStringValidDate( "310210" ), CheckStringValidDate( "310210" ) )	//.T.  => 31.10.1902, 1931.02.10, 1931.10.02

	msgdebug (IsStringValidDate( "310210",  hb_CtoD( "01/01/1990" , "dd/mm/yyyy" )  /* FromDate */ ,  hb_CtoD( "31/12/2050" , "dd/mm/yyyy" ) /* ToDate */ ))	//.F.

	msgdebug (IsStringValidDate( "12@40@2011" ))	//.F.

	msgdebug (IsStringValidDate( "12x40x2011" ))	//.F.

	msgdebug (IsStringValidDate( 1111 ))		//.F.

	msgdebug (IsStringValidDate( .F. ))		//.F.

	msgdebug (IsStringValidDate( ))			//.F.
RETURN


*************************************************************************
Function IsStringValidDate( cDate, dRangeFrom, dRangeTo )
Local lValidDate := Len ( CheckStringValidDate( cDate, dRangeFrom, dRangeTo ) ) > 0
RETURN lValidDate
*************************************************************************
Function CheckStringValidDate( cDate, dRangeFrom, dRangeTo  )

Local cSep:=".-/\ ", cDateCheck
Local i, j, nInsPos
Local isSep := .F.
Local aDateFormats:={ "dd/mm/yyyy", "dd/mm/yy",;
		      "mm/dd/yyyy", "mm/dd/yy", ;
		      "yyyy/mm/dd", "yy/mm/dd", ;
		      "yyyy/dd/mm", "yy/dd/mm", ;
		      "mm/yyyy/dd", "mm/yy/dd", ;
		      "dd/yyyy/mm", "dd/yy/mm" }, ;
      aTokens, aDates :={}
Local dDate


Default cDate := ""
Default dRangeFrom := CToD( "" ), dRangeTo := hb_CtoD( "31/12/9999" , "dd/mm/yyyy" )

IF !hb_isChar ( cDate )
	Return aDates
ENDIF

FOR i:=1 TO Len ( cDate )
	IF Substr( cDate, i, 1 ) $ cSep
		isSep := .T.
	ELSEIF !IsDigit( Substr( cDate, i, 1 ) )
		Return aDates
	ENDIF
NEXT i
	

FOR i:=1 TO Len ( aDateFormats )
	IF !isSep
		aTokens := hb_Atokens ( aDateFormats [i], "/" )
		cDateCheck := cDate
		nInsPos := 0
		FOR j := 1 TO Len ( aTokens ) - 1
			nInsPos += Len( aTokens [j]) + 1
			cDateCheck := Stuff(cDateCheck, nInsPos, 0, "/")
		NEXT j
	ELSE
		cDateCheck := cDate
	ENDIF
	dDate := hb_CtoD( cDateCheck , aDateFormats [i]) 
	IF !EMPTY( dDate ) .AND. dDate >= dRangeFrom .AND. dDate <= dRangeTo
		IF ASCAN ( aDates, dDate ) = 0
			AADD ( aDates, dDate )
		ENDIF
	ENDIF
NEXT i
RETURN aDates
Post Reply