#include "sflconv.h"
long
conv_str_date (
const char *string,
int flags,
int format,
int order)
Synopsis
Converts a string to a date. The supposed format of the date is
defined by the format argument, which can be one of:
DATE YMD COMPACT
| Year month day. |
DATE
YMD DELIM | Year month day. |
DATE YMD SPACE | Year month
day. |
DATE YMD COMMA | Year month day. |
DATE YM
COMPACT | Year and month only; day is zero.
|
DATE YM DELIM | Year and month only; day is zero. |
DATE YM SPACE | Year and
month only; day is zero. |
DATE MD
COMPACT | Month and day only; year is zero.
|
DATE MD DELIM | Month and day only; year is zero. |
DATE MD SPACE | Month and
day only; year is zero. |
The date order must be one of:
DATE ORDER
YMD | Year month day. |
DATE ORDER DMY | Day month
year. |
DATE ORDER MDY | Month day year. |
You can override the
order using these flags: FLAG D ORDER YMD | Year
month day. |
FLAG D ORDER DMY | Day month year. |
FLAG D
ORDER MDY | Month day year. |
Returns the date as a long integer, YYYYMMDD. The conversion is
pretty relaxed and allows strings like: 010195, 1-1-95, 1-Jan-
95, 1jan95, 01jan95, 1 1 95, etc. The input string must be
null-terminated. Returns -1 in case of an invalid date or
format. If the short formats (DATE_DM_..., DATE_YM_...) are
used, the missing field is always set to 0 and cannot be
supplied in the string. If the date was empty, i.e. contains no
usable digits, returns 0.
Source Code - (sflcvsd.c)
{
static
char *month_name [] =
{
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec"
};
static byte
month_days [] =
{
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
},
order_ptr [][3] = /* Year, Month, Day pointers */
{ /* for various orders & formats */
/* YY MM DD YYYY MM DD YY MM YYYY MM MM DD */
{ 0, 2, 4 }, { 0, 4, 6 }, { 0, 2, 99 }, { 0, 4, 99 }, { 99, 0, 2 },
{ 4, 2, 0 }, { 4, 2, 0 }, { 2, 0, 99 }, { 2, 0, 99 }, { 99, 2, 0 },
{ 4, 0, 2 }, { 4, 0, 2 }, { 2, 0, 99 }, { 2, 0, 99 }, { 99, 0, 2 },
};
char
date_digits [9], /* 8 digits of date */
month_letters [4] = "???", /* 3 characters of month */
ch; /* Next character in date */
long
feedback; /* Returned date; -1 = error */
int
digits, /* Number of digits in string */
delimiters, /* Number of delimiters in date */
digitseq, /* Number of digits in sequence */
count, /* Number of month letters */
year, /* Date year value */
month, /* Date month value */
day, /* Date day value */
order_index, /* Index into order table */
y_ptr, /* Where is year in date? */
m_ptr, /* Where is month in date? */
d_ptr, /* Where is day in date? */
date_order = order; /* Actual date order */
Bool
had_month; /* Did we already get a month? */
ASSERT (format >= DATE_FORMAT_FIRST && format <= DATE_FORMAT_LAST);
ASSERT (order >= DATE_ORDER_FIRST && order <= DATE_ORDER_LAST);
conv_reason = 0; /* No conversion errors so far */
if (flags & FLAG_D_ORDER_YMD)
date_order = DATE_ORDER_YMD;
else
if (flags & FLAG_D_ORDER_DMY)
date_order = DATE_ORDER_DMY;
else
if (flags & FLAG_D_ORDER_MDY)
date_order = DATE_ORDER_MDY;
/* Collect date digits */
digits = 0; /* Nothing collected so far */
digitseq = 0; /* No digits in sequence */
feedback = 0; /* No errors so far */
delimiters = 0; /* We allow up to 2 delimiters */
had_month = FALSE; /* True after 3-letter month seen */
do
{
ch = *string++;
if (isdigit (ch))
{
if (digits < 8)
{
digitseq++;
date_digits [digits++] = ch;
}
else
{
conv_reason = CONV_ERR_DATE_SIZE;
feedback = -1; /* Too many digits */
}
}
else
{
/* Fill-up to even number of digits */
if (digits > (digits / 2) * 2)
{
date_digits [digits] = date_digits [digits - 1];
date_digits [digits - 1] = '0';
digits++;
}
/* 3 or 5 in a row is not allowed */
if (digitseq == 3 || digitseq == 5)
{
conv_reason = CONV_ERR_REJECT_3_5;
feedback = -1;
}
digitseq = 0;
/* If a letter, try to match against a month */
if (isalpha (ch))
{
if (had_month)
{
conv_reason = CONV_ERR_MULTIPLE_MONTH;
feedback = -1;
}
else
{
for (count = 0; isalpha (ch); )
{
if (count < 3)
month_letters [count++] = (char) tolower (ch);
ch = *string++;
}
string--; /* Move back to char after month */
if (count < 3)
{
conv_reason = CONV_ERR_BAD_MONTH;
feedback = -1; /* Too few letters */
}
month_letters [3] = 0;
for (count = 0; count < 12; count++)
if (streq (month_letters, month_name [count]))
{
count++;
date_digits [digits++] = (char) (count / 10 + '0');
date_digits [digits++] = (char) (count % 10 + '0');
had_month = TRUE;
break;
}
if (!had_month)
{
conv_reason = CONV_ERR_BAD_MONTH;
feedback = -1; /* Month not found */
}
}
}
else
if (ispunct (ch)) /* Skip any delimiter */
if ((++delimiters > 2)
|| (format > DATE_YMD_LAST && delimiters > 1))
{
conv_reason = CONV_ERR_MULTIPLE_DELIM;
feedback = -1; /* Multiple delimiters */
}
}
}
until (ch == 0);
/* Return zero date if empty */
if (digits == 0)
return (feedback);
/* Calculate offset in date_digits for various date order & formats */
order_index = (date_order - 1) * 5; /* Each row has 5 items */
if (format <= DATE_YMD_LAST)
{
if (digits == 6)
; /* nothing */
else
if (digits == 8)
order_index += 1;
}
else
if (format <= DATE_YM_LAST)
{
date_digits [digits++] = '0';
date_digits [digits++] = '0';
if (digits == 6)
order_index += 2;
else
if (digits == 8)
order_index += 3;
else
{
conv_reason = CONV_ERR_DATE_SIZE;
return (-1); /* Error - bad date size */
}
}
else
if (format <= DATE_MD_LAST)
{
date_digits [digits++] = '0';
date_digits [digits++] = '0';
if (digits == 6)
order_index += 4;
else
{
conv_reason = CONV_ERR_DATE_SIZE;
return (-1); /* Error - bad date size */
}
}
/* Decode order to pick-up offset of day/month/year in date_digits */
y_ptr = order_ptr [order_index][0];
m_ptr = order_ptr [order_index][1];
d_ptr = order_ptr [order_index][2];
# define DIGIT(x) (date_digits [(x)] - '0')
if (y_ptr != 99)
{
year = DIGIT (y_ptr) * 10 + DIGIT (y_ptr + 1);
if (digits == 8)
year = DIGIT (y_ptr + 2) * 10 + DIGIT (y_ptr + 3) + year * 100;
if (year < 50)
year += 2000;
else
if (year < 100)
year += 1900;
}
else
year = 0;
if (m_ptr != 99)
{
month = DIGIT (m_ptr) * 10 + DIGIT (m_ptr + 1);
if (month == 0 || month > 12)
{
conv_reason = CONV_ERR_OUT_OF_RANGE;
feedback = -1;
}
}
else
month = 0;
if (d_ptr != 99)
{
day = DIGIT (d_ptr) * 10 + DIGIT (d_ptr + 1);
if ((day == 0 || day > (int) month_days [month - 1])
|| (month == 2 && day == 29 && !leap year (year)))
{
conv_reason = CONV_ERR_OUT_OF_RANGE;
feedback = -1;
}
}
else
day = 0;
if (feedback == 0)
feedback = year * 10000L + month * 100 + day;
return (feedback);
}
| << | <
| > | >>
|
Copyright © 1996-2000 iMatix Corporation |