Solved

Borland Database Engine date decoding errors

Posted on 1997-05-23
10
598 Views
Last Modified: 2012-06-21
Hi, I'm learning-on-the-go as I develop a database application for a small business.  I'm running into a lot of trouble reading numerical and date data from a dBase III file using the Borland Database Engine and IDAPI.

The function was returning wierd values, so as an error-check I encoded then immediately decoded a date.  What I get back is not what I put in.

Help, please!

DbiDateEncode (2, 29, 80, &dte);
DbiDateDecode (dte, (pUINT16)&mm, (pUINT16)&dd, (pINT16)&yy);
sprintf (str, "%i/%i/%i", mm, dd, yy);
MessageBox (hDlg, str, "", MB_OK);

Theoretically, the messagebox should display "2/29/80" but it actually displays something like "901286/13/3248237"

Any ideas?
0
Comment
Question by:Klaxxon
  • 5
  • 3
  • 2
10 Comments
 
LVL 4

Expert Comment

by:AVaulin
ID: 1163662
You use DbiDateEncode and DbiDateDecode not correctly. 1st parameter in DbiDateEncode and 2nd, 3rd and 4th parameters in DbiDateDecode are references. You must write:
DbiDateEncode( 2, 29, 80, dte );
DbiDateDecode( dte, mm, dd, yy );
I hope this will help. Good luck.
0
 

Author Comment

by:Klaxxon
ID: 1163663
Thanks for your answer, but it does not work.

My variables are declared as follows (as the online help file says they should be):

DBIDATE dte;
pUINT16 mm, dd;
pINT16 yy;

My code looks as you suggested:

DbiDateEncode (2, 29, 80, dte);
DbiDateDecode (dte, mm, dd, yy);
sprintf (str, "%i/%i/%i", mm, dd, yy);
MessageBox (hDlg, str, "", MB_OK);            

But will not compile due to the following error:

Error:  superaje.c(583,34):Type mismatch in parameter 'pdateD' in call to 'DbiDateEncode'

I can get the code to compile as follows:

DbiDateEncode (2, 29, 80, &dte);
DbiDateDecode (dte, mm, dd, yy);
sprintf (str, "%i/%i/%i", mm, dd, yy);
MessageBox (hDlg, str, "", MB_OK);            

(I added a '&' to dte in DbiDateEncode), but it crashes with a "Thread Stopped" message saying there was an "access violation".

Obviously, my understanding of pointers is rudimentary, so if you could help further, it would be appreciated.
0
 
LVL 4

Expert Comment

by:AVaulin
ID: 1163664
Let's try this way:

long dte;
Word mm, dd;
short yy;

DbiDateEncode (2, 29, 80, dte);
sprintf (str, "%li", dte);
MessageBox (hDlg, str, "", MB_OK);
DbiDateDecode( dte, mm, dd, yy );
sprintf (str, "%hi/%hi/%hi", mm, dd, yy); // see h specifier
MessageBox (hDlg, str, "", MB_OK);

What both MessageBox says?
0
 

Author Comment

by:Klaxxon
ID: 1163665
Nope ... doesn't work.
I get a bunch of "type mismatch" messages because the types need to be DBIDATE, pUINT16, and pINT16.

I'm working in Borland C++ 32-bit with Borland Database Engine 32-bit.
0
 

Accepted Solution

by:
rlayton earned 100 total points
ID: 1163666
I believe DbiDateEncode requires 4 digits to calculate the correct date.  Try it, you'll like it!
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:Klaxxon
ID: 1163667
Thanks for the advise, unfortunately it didn't help.  For furthur clarification, here is the exact code I'm using, plus the exact results I get:

The variables are declared as follows:
DBIDATE dte;
pUINT16 mm, dd;
pINT16 yy;

This is the code:
/*  "Chk()" is simply an error-message printing function.  It's source can be found under "chk" in the bde32.hlp file  */

Chk (DbiDateEncode (4, 28, 96, &dte));
Chk (DbiDateDecode (dte, (pUINT16)&mm, (pUINT16)&dd, (pINT16)&yy));
sprintf (str, "%i/%i/%i", mm, dd, yy);
MessageBox (hDlg, str, "", MB_OK);

Here's the results with different dates:

when I encode:  5, 28, 1997
I get:  2064515077/28/133069
(at least the day works!)

encode:  5, 28, 97
get:  2064515077/28/131169

encode:  4, 28, 97
get:  2064515076/28/131169

encode:  4, 28, 96
get:  2064515076/28/131168

These results imply that I get simply subtract a particular value from each answer to get the right one.  This is the first time I actually did a trial-and-error check of the return values, and now it looks like they're always off by a consistant ammount.

I'd still like to have the function work properly, though.... I really bothers me to have to hack an answer out.

BTW, I ran the DbiGetDateFormat() function, and it returned the following:
DateFormat = 0
4 digit year = 0
Year biased = 1
date separator = '/'

The explanations of those are in the help file, but those values are as they should be.

As some additional background, I'm writing a program that reads in a dBase III .DBF file.  I was getting weird values when reading dates, so *that's* why I encoded then decoded a date... It's purpose is simply an error check.

Thanks for your help, I hope I've clarified a few things, and I hope you can assist me further...  My employer is getting anxious to see some results and this problem has been a major roadblock.
       - Klaxxon
0
 

Expert Comment

by:rlayton
ID: 1163668
Here is the exact code I use to encode/decode this stuff:

int Month, int Day, int Year;
DBIDATE Td;
 
DbiDateEncode(Month, Day, Year, &Td);
DbiDateDecode(Td, &Month, &Day, &Year);

This stuff is actually quite straight forward, and I haven't had any problems with it once I got it all setup and working correctly.  

The only other problem I can see is if the memory for the table buffer isn't allocated correctly.  Also, view the contents of the Td  ( the DBIDATE / double) variable after encoding each of the different trial dates, and see what relationship they have.  

I've never used the BDE with dBaseIII, but I've plenty of success using it with Paradox, MS SQL Server, and Sybase, which should basically be the same using it with any other DataBase

Anyway, Good luck!


PS. I have a DataBase/Table wrapper class I've written which encapsulates all this stuff, automating file opening, record access, etc...,  which really makes it much easier to manage (at least for me.)  If you're interested let me know,  I'd consider letting somebody else try it out!  However it may take you longer to get it set up than you have to waste.


0
 

Author Comment

by:Klaxxon
ID: 1163669
aaaallllllrrrriiiiiigggggghhhhhhtttttttt!!!!!

(you'll have to excuse me, but this problem has been really bothering me... and now it's FIXED!!!)  :o)

For some unknown reason, if the month, day, and year variables have not been assigned a value (it appears any value will do) before DbiDateDecode (dte, &mm, &dd, &yy); is called, then I get screwy answers.  All I did was assign mm = dd = yy = 1; at the top of the function, and now DbiDateDecode returns everything correctly!!  Wahoo!

I figured that out because in your code you fed DbiDateEncode preassigned values while I was trying to pass numbers directly to the function.  This led me to do a little playing around, and I figured it out.

Thank you *VERY* much.

.....Now, on with my program!

PS:  You *may* see a question posted here soon about reading regular numerical data (as opposed to strings) from a database.  But I'll see what I can do first.  Thanks a bunch.
0
 

Author Comment

by:Klaxxon
ID: 1163670
Yup.... I'm having problems with reading numerical data.  YaSee, this is the first time I've ever used BDE so I'm learning as I go.

Say a field contains an integer.  Do I just do the following?

int num;
DbiGetField (VarCur, FieldNum, RecBuff, (pBYTE)num, ...);

or do I use:
..., (pBYTE)&num, ...

or do I declare num as a string or perhaps a double?

If you could send me some sample source either as a comment to this question or to rogersa@superaje.com ,  I'd really appreciate it.

If you like, I can submit it as a 25 or 50 point question and then grade you.

Thanks in advance.
0
 

Expert Comment

by:rlayton
ID: 1163671
I'll give this one to you, just treat me well when the opportunity arises.

If the value you are retrieving is a double, then pass in a double, likewise with int, char*,etc...

Here is a snippet from my table class...

char * Table::GetField (UINT16 FieldNum, char *Src)
{
      BOOL Blank;

      strcpy(Action, "GetField");

      Status = DbiGetField (Cursor, FieldNum, DBRec, (pBYTE)Src, &Blank);

//Not always blank in SQL Server
      if(Blank)
      {
            switch(NumberType)
            {
                  case NINT:
                        memset(Src, 0, sizeof(int));
                        break;

                  case NDOUBLE:
                        memset(Src, 0, sizeof(double));
                        break;

                  case NLONG:
                        memset(Src, 0, sizeof(long));
                        break;

                  default:
                        strcpy(Src, "");

            }
      }


      if(Status)
            ErrorHandler();

      return Src;

}


double Table::GetField(UINT16 FieldNum, double &Number)
{
      NumberType = NDOUBLE;

      GetField(FieldNum, (char *)&Number);

      return Number;
}


int Table::GetField(UINT16 FieldNum, int &Number)
{
      NumberType = NINT;

      GetField(FieldNum, (char *)&Number);

      return Number;
}


long Table::GetField(UINT16 FieldNum, long &Number)
{
      NumberType = NLONG;

      GetField(FieldNum, (char *)&Number);

      return Number;
}


As you can see, I simply pass in the variable of the type I want to retrieve, which forces the correct function to be called, and the variable is also returned for ease of use!  Each function calls the top (top as in top of this listing) function, so you could look at that one for reference.  The Cursor and Record are both part of the class, so you'll need to pass those in as well.

Quick examples for use:

double Double;
int Integer;
char Str[MAX_SIZE];

wsprintf(Temp, "%d \t %lf", GetField(FieldNum, Integer), GetField(FieldNum, Double));
MessageBox(0, GetField(FieldNum, Str), Title, MB_OK);

etc...


Good Luck!
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now