8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 15:23:03 +01:00

Change some aspects of the string-to-date conversion with format to make it more similar to the SQL standard #2388 (#7881)

* Use current TimeStamp for data in stringToDate conversion if it's not specify

Also fix RM pattern and change (A/P)M to (A/P).M.

* Add more tests

* Add TimeStamp validation

Also move duplicated code to functions.

* Add more unit tests for "YY" and "YYY" patterns

* Use Callback for getting current date

It's better because we can mock Callback for unit tests.

* Fix exception and README description

* Add ability to print blr_cast_format

* Put a comment about new BLR in the right place

* Add information about behavior of string to datetime conversion

* Rework old patterns and add new ones

Add A.M, P.M., RR and RRRR patterns.
Rework YY, YYY, HH and HH12 patterns due to new patterns.
Add restriction from SQL standard to format.
Fix incorrect error message for mismatched pattern.
Fix bug with 0 hours in HH12.

* Add more unit tests

* Update doc for cast format

* Allow specification of log_level for BOOST_TESTS in make

* Change enum class to enum in namespace

* Switch from plain enum to constexpr values

---------

Co-authored-by: Artyom Ivanov <artyom.ivanov@red-soft.ru>
This commit is contained in:
TreeHunter 2024-03-04 14:43:14 +03:00 committed by GitHub
parent b40c1e0349
commit a429459b76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 946 additions and 355 deletions

View File

@ -790,18 +790,20 @@ install install-embedded silent_install package packages dist:
.PHONY: tests tests_process run_tests run_tests_process
log_level ?= all
tests:
$(MAKE) TARGET?=$(DefaultTarget) tests_process
tests_process: $(COMMON_TEST) $(ENGINE_TEST) $(ISQL_TEST)
run_tests:
$(MAKE) TARGET?=$(DefaultTarget) run_tests_process
$(MAKE) TARGET?=$(DefaultTarget) LOG_LEVEL?=$(log_level) run_tests_process
run_tests_process: tests_process
$(COMMON_TEST) --log_level=all
$(ENGINE_TEST) --log_level=all
$(ISQL_TEST) --log_level=all
$(COMMON_TEST) --log_level=$(LOG_LEVEL)
$(ENGINE_TEST) --log_level=$(LOG_LEVEL)
$(ISQL_TEST) --log_level=$(LOG_LEVEL)
#___________________________________________________________________________

View File

@ -1,6 +1,6 @@
## 1. DATETIME TO STRING
The following flags are currently implemented for datetime to string conversion:
The following patterns are currently implemented for datetime to string conversion:
| Format Pattern | Description |
| -------------- | ----------- |
| YEAR | Year (1 - 9999) |
@ -21,12 +21,13 @@ The following flags are currently implemented for datetime to string conversion:
| DDD | Day of the Year (001 - 366) |
| DY | Short name of the Day (Mon) |
| J | Julian Day (number of days since January 1, 4712 BC) |
| HH / HH12 | Hour of the Day (01 - 12) with period (AM, PM) |
| HH / HH12 | Hour of the Day (01 - 12) without Period (for Period use A.M or P.M.) |
| HH24 | Hour of the Day (00 - 23) |
| MI | Minutes (00 - 59) |
| SS | Seconds (00 - 59) |
| SSSSS | Seconds after midnight (0 - 86399) |
| FF1 - FF9 | Fractional seconds with the specified accuracy |
| A.M. / P.M. | Period for 12 hours time (it doesn't matter which one is used, period will be inserted based on time) |
| TZH | Time zone in Hours (-14 - 14) |
| TZM | Time zone in Minutes (00 - 59) |
| TZR | Time zone Name |
@ -61,7 +62,7 @@ SELECT CAST(CURRENT_TIMESTAMP AS VARCHAR(45) FORMAT 'DD.MM.YEAR HH24:MI:SS "is"
## 2. STRING TO DATETIME
The following flags are currently implemented for string to datetime conversion:
The following patterns are currently implemented for string to datetime conversion:
| Format Pattern | Description |
| ------------- | ------------- |
| YEAR | Year |
@ -69,24 +70,39 @@ The following flags are currently implemented for string to datetime conversion:
| YYY | Last 3 digits of Year |
| YY | Last 2 digits of Year |
| Y | Last 1 digits of Year |
| RR / RRRR | Round Year (further information below) |
| MM | Month (1 - 12) |
| MON | Short Month name (Apr) |
| MONTH | Full Month name (APRIL) |
| RM | Roman representation of the Month (I - XII) |
| DD | Day of the Month (1 - 31) |
| J | Julian Day (number of days since January 1, 4712 BC) |
| HH / HH12 | Hour of the Day (1 - 12) with period (AM, PM) |
| HH / HH12 | Hour of the Day (1 - 12) without Period (to specify Period use A.M or P.M.) |
| HH24 | Hour of the Day (0 - 23) |
| MI | Minutes (0 - 59) |
| SS | Seconds (0 - 59) |
| SSSSS | Seconds after midnight (0 - 86399) |
| FF1 - FF4 | Fractional seconds with the specified accuracy |
| A.M. / P.M. | Period for 12 hours time (it doesn't matter which one is used, period will be taken from input string) |
| TZH | Time zone in Hours (-14 - 14) |
| TZM | Time zone in Minutes (0 - 59) |
| TZR | Time zone Name |
Dividers are the same as for datetime to string conversion and can also be omitted.
Year, month and day will be taken from current date if these components are not used in pattern (this applies only to data types that contain a date component).
Behavior of `RR`:
- If the specified two-digit year is 00 to 49, then
- If the last two digits of the current year are 00 to 49, then the returned year has the same first two digits as the current year.
- If the last two digits of the current year are 50 to 99, then the first 2 digits of the returned year are 1 greater than the first 2 digits of the current year.
- If the specified two-digit year is 50 to 99, then
- If the last two digits of the current year are 00 to 49, then the first 2 digits of the returned year are 1 less than the first 2 digits of the current year.
- If the last two digits of the current year are 50 to 99, then the returned year has the same first two digits as the current year.
Behavior of `RRRR`: Accepts either 4-digit or 2-digit input. If 2-digit, provides the same return as `RR`. If you do not want this functionality, then enter the 4-digit year.
Example:
```
SELECT CAST('2000.12.08 12:35:30.5000' AS TIMESTAMP FORMAT 'YEAR.MM.DD HH24:MI:SS.FF4') FROM RDB$DATABASE;

View File

@ -971,6 +971,7 @@ const int HIGH_WORD = 0;
#endif
#endif
inline const TEXT FB_SHORT_MONTHS[][4] =
{
"Jan", "Feb", "Mar",

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird
bool, Firebird::Callbacks*);
const UCHAR* CVT_get_bytes(const dsc*, unsigned&);
Firebird::string CVT_datetime_to_format_string(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb);
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb,
const Firebird::EXPECT_DATETIME expectedType);
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format,
const Firebird::EXPECT_DATETIME expectedType, Firebird::Callbacks* cb);
#endif //COMMON_CVT_H

View File

@ -6,29 +6,42 @@ using namespace Firebird;
using namespace Jrd;
using namespace CvtTestUtils;
BOOST_AUTO_TEST_SUITE(CVTSuite)
BOOST_AUTO_TEST_SUITE(CVTDatetimeFormat)
// Currently we cannot print our error messages because we need master interface for that
static void errFunc(const Firebird::Arg::StatusVector& v)
{
v.raise();
}
CVTCallback cb(errFunc);
MockCallback cb(errFunc, std::bind(mockGetLocalDate, 2023));
BOOST_AUTO_TEST_SUITE(CVTDatetimeToFormatString)
template<typename T>
static void testCVTDatetimeToFormatString(T date, const string& format, const string& expected, Callbacks& cb)
{
dsc desc;
desc.dsc_dtype = getDSCTypeFromDateType<T>();
desc.dsc_length = sizeof(T);
desc.dsc_address = (UCHAR*) &date;
desc.dsc_scale = 0;
try
{
dsc desc;
desc.dsc_dtype = getDSCTypeFromDateType<T>();
desc.dsc_length = sizeof(T);
desc.dsc_address = (UCHAR*) &date;
desc.dsc_scale = 0;
string result = CVT_datetime_to_format_string(&desc, format, &cb);
BOOST_TEST(result == expected, "\nRESULT: " << result.c_str() << "\nEXPECTED: " << expected.c_str());
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
string result = CVT_datetime_to_format_string(&desc, format, &cb);
BOOST_TEST(result == expected, "\nRESULT: " << result.c_str() << "\nEXPECTED: " << expected.c_str());
}
catch(const Exception& ex)
{
BOOST_TEST_INFO("Exception was caught!");
BOOST_TEST(false);
}
}
BOOST_AUTO_TEST_SUITE(FunctionalTest)
@ -44,9 +57,56 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_DATE)
testCVTDatetimeToFormatString(createDate(9999, 1, 1), "YEAR.YYYY.YYY.YY.Y", "9999.9999.999.99.9", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "Q", "1", cb);
testCVTDatetimeToFormatString(createDate(1, 2, 1), "Q", "1", cb);
testCVTDatetimeToFormatString(createDate(1, 3, 1), "Q", "1", cb);
testCVTDatetimeToFormatString(createDate(1, 4, 1), "Q", "2", cb);
testCVTDatetimeToFormatString(createDate(1, 5, 1), "Q", "2", cb);
testCVTDatetimeToFormatString(createDate(1, 6, 1), "Q", "2", cb);
testCVTDatetimeToFormatString(createDate(1, 7, 1), "Q", "3", cb);
testCVTDatetimeToFormatString(createDate(1, 8, 1), "Q", "3", cb);
testCVTDatetimeToFormatString(createDate(1, 9, 1), "Q", "3", cb);
testCVTDatetimeToFormatString(createDate(1, 10, 1), "Q", "4", cb);
testCVTDatetimeToFormatString(createDate(1, 11, 1), "Q", "4", cb);
testCVTDatetimeToFormatString(createDate(1, 12, 1), "Q", "4", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "MON", "Jan", cb);
testCVTDatetimeToFormatString(createDate(1, 2, 1), "MON", "Feb", cb);
testCVTDatetimeToFormatString(createDate(1, 3, 1), "MON", "Mar", cb);
testCVTDatetimeToFormatString(createDate(1, 4, 1), "MON", "Apr", cb);
testCVTDatetimeToFormatString(createDate(1, 5, 1), "MON", "May", cb);
testCVTDatetimeToFormatString(createDate(1, 6, 1), "MON", "Jun", cb);
testCVTDatetimeToFormatString(createDate(1, 7, 1), "MON", "Jul", cb);
testCVTDatetimeToFormatString(createDate(1, 8, 1), "MON", "Aug", cb);
testCVTDatetimeToFormatString(createDate(1, 9, 1), "MON", "Sep", cb);
testCVTDatetimeToFormatString(createDate(1, 10, 1), "MON", "Oct", cb);
testCVTDatetimeToFormatString(createDate(1, 11, 1), "MON", "Nov", cb);
testCVTDatetimeToFormatString(createDate(1, 12, 1), "MON", "Dec", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "MONTH", "JANUARY", cb);
testCVTDatetimeToFormatString(createDate(1, 2, 1), "MONTH", "FEBRUARY", cb);
testCVTDatetimeToFormatString(createDate(1, 3, 1), "MONTH", "MARCH", cb);
testCVTDatetimeToFormatString(createDate(1, 4, 1), "MONTH", "APRIL", cb);
testCVTDatetimeToFormatString(createDate(1, 5, 1), "MONTH", "MAY", cb);
testCVTDatetimeToFormatString(createDate(1, 6, 1), "MONTH", "JUNE", cb);
testCVTDatetimeToFormatString(createDate(1, 7, 1), "MONTH", "JULY", cb);
testCVTDatetimeToFormatString(createDate(1, 8, 1), "MONTH", "AUGUST", cb);
testCVTDatetimeToFormatString(createDate(1, 9, 1), "MONTH", "SEPTEMBER", cb);
testCVTDatetimeToFormatString(createDate(1, 10, 1), "MONTH", "OCTOBER", cb);
testCVTDatetimeToFormatString(createDate(1, 11, 1), "MONTH", "NOVEMBER", cb);
testCVTDatetimeToFormatString(createDate(1, 12, 1), "MONTH", "DECEMBER", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "RM", "I", cb);
testCVTDatetimeToFormatString(createDate(1, 2, 1), "RM", "II", cb);
testCVTDatetimeToFormatString(createDate(1, 3, 1), "RM", "III", cb);
testCVTDatetimeToFormatString(createDate(1, 4, 1), "RM", "IV", cb);
testCVTDatetimeToFormatString(createDate(1, 5, 1), "RM", "V", cb);
testCVTDatetimeToFormatString(createDate(1, 6, 1), "RM", "VI", cb);
testCVTDatetimeToFormatString(createDate(1, 7, 1), "RM", "VII", cb);
testCVTDatetimeToFormatString(createDate(1, 8, 1), "RM", "VIII", cb);
testCVTDatetimeToFormatString(createDate(1, 9, 1), "RM", "IX", cb);
testCVTDatetimeToFormatString(createDate(1, 10, 1), "RM", "X", cb);
testCVTDatetimeToFormatString(createDate(1, 11, 1), "RM", "XI", cb);
testCVTDatetimeToFormatString(createDate(1, 12, 1), "RM", "XII", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "MM:RM-MON/MONTH", "01:I-Jan/JANUARY", cb);
testCVTDatetimeToFormatString(createDate(1, 6, 1), "MM-RM.MON;MONTH", "06-VI.Jun;JUNE", cb);
@ -56,6 +116,22 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_DATE)
testCVTDatetimeToFormatString(createDate(1, 6, 15), "WW-W", "24-3", cb);
testCVTDatetimeToFormatString(createDate(1, 12, 30), "WW.W", "52.5", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "DAY", "MONDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 2), "DAY", "TUESDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 3), "DAY", "WEDNESDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 4), "DAY", "THURSDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 5), "DAY", "FRIDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 6), "DAY", "SATURDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 7), "DAY", "SUNDAY", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 1), "DY", "Mon", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 2), "DY", "Tue", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 3), "DY", "Wed", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 4), "DY", "Thu", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 5), "DY", "Fri", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 6), "DY", "Sat", cb);
testCVTDatetimeToFormatString(createDate(1, 1, 7), "DY", "Sun", cb);
testCVTDatetimeToFormatString(createDate(2023, 6, 4), "D;DAY-DY", "1;SUNDAY-Sun", cb);
testCVTDatetimeToFormatString(createDate(2023, 6, 7), "D.DAY,DY", "4.WEDNESDAY,Wed", cb);
testCVTDatetimeToFormatString(createDate(2023, 6, 10), "D DAY DY", "7 SATURDAY Sat", cb);
@ -72,9 +148,47 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_DATE)
BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIME)
{
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH-HH12.HH24,MI/SS SSSSS", "12 AM-12 AM.00,00/00 0", cb);
testCVTDatetimeToFormatString(createTime(12, 35, 15), "HH.HH12:HH24;MI-SS/SSSSS", "12 PM.12 PM:12;35-15/45315", cb);
testCVTDatetimeToFormatString(createTime(23, 59, 59), " HH - HH12 . HH24 , MI / SS SSSSS ", " 11 PM - 11 PM . 23 , 59 / 59 86399 ", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH24", "00", cb);
testCVTDatetimeToFormatString(createTime(12, 0, 0), "HH24", "12", cb);
testCVTDatetimeToFormatString(createTime(23, 0, 0), "HH24", "23", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH A.M.", "12 A.M.", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH P.M.", "12 A.M.", cb);
testCVTDatetimeToFormatString(createTime(11, 0, 0), "HH A.M.", "11 A.M.", cb);
testCVTDatetimeToFormatString(createTime(11, 0, 0), "HH P.M.", "11 A.M.", cb);
testCVTDatetimeToFormatString(createTime(12, 0, 0), "HH A.M.", "12 P.M.", cb);
testCVTDatetimeToFormatString(createTime(12, 0, 0), "HH P.M.", "12 P.M.", cb);
testCVTDatetimeToFormatString(createTime(13, 0, 0), "HH A.M.", "01 P.M.", cb);
testCVTDatetimeToFormatString(createTime(13, 0, 0), "HH P.M.", "01 P.M.", cb);
testCVTDatetimeToFormatString(createTime(23, 0, 0), "HH A.M.", "11 P.M.", cb);
testCVTDatetimeToFormatString(createTime(23, 0, 0), "HH P.M.", "11 P.M.", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH12 A.M.", "12 A.M.", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH12 P.M.", "12 A.M.", cb);
testCVTDatetimeToFormatString(createTime(11, 0, 0), "HH12 A.M.", "11 A.M.", cb);
testCVTDatetimeToFormatString(createTime(11, 0, 0), "HH12 P.M.", "11 A.M.", cb);
testCVTDatetimeToFormatString(createTime(12, 0, 0), "HH12 A.M.", "12 P.M.", cb);
testCVTDatetimeToFormatString(createTime(12, 0, 0), "HH12 P.M.", "12 P.M.", cb);
testCVTDatetimeToFormatString(createTime(13, 0, 0), "HH12 A.M.", "01 P.M.", cb);
testCVTDatetimeToFormatString(createTime(13, 0, 0), "HH12 P.M.", "01 P.M.", cb);
testCVTDatetimeToFormatString(createTime(23, 0, 0), "HH12 A.M.", "11 P.M.", cb);
testCVTDatetimeToFormatString(createTime(23, 0, 0), "HH12 P.M.", "11 P.M.", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "MI", "00", cb);
testCVTDatetimeToFormatString(createTime(0, 30, 0), "MI", "30", cb);
testCVTDatetimeToFormatString(createTime(0, 59, 0), "MI", "59", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "SS", "00", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 30), "SS", "30", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 59), "SS", "59", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "SSSSS", "0", cb);
testCVTDatetimeToFormatString(createTime(12, 30, 15), "SSSSS", "45015", cb);
testCVTDatetimeToFormatString(createTime(23, 59, 59), "SSSSS", "86399", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0), "HH-HH12 A.M..HH24,MI/SS SSSSS", "12-12 A.M..00,00/00 0", cb);
testCVTDatetimeToFormatString(createTime(12, 35, 15), "HH.HH12 P.M.:HH24;MI-SS/SSSSS", "12.12 P.M.:12;35-15/45315", cb);
testCVTDatetimeToFormatString(createTime(23, 59, 59), " HH P.M. - HH12 . HH24 , MI / SS SSSSS ", " 11 P.M. - 11 . 23 , 59 / 59 86399 ", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0, 1), "FF1.FF2/FF3;FF4:FF5-FF6,FF7-FF8 FF9", "1.10/100;1000:10000-100000,1000000-10000000 100000000", cb);
testCVTDatetimeToFormatString(createTime(0, 0, 0, 1000), "FF1.FF2/FF3;FF4:FF5-FF6,FF7-FF8 FF9", "1.10/100;1000:10000-100000,1000000-10000000 100000000", cb);
@ -88,12 +202,12 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIMESTAMP)
testCVTDatetimeToFormatString(timestamp, "YEAR.YYYY.YYY.YY.Y/J", "1982.1982.982.82.2/2445081", cb);
testCVTDatetimeToFormatString(timestamp, "Q-MM-RM-MON-MONTH", "2-04-IV-Apr-APRIL", cb);
testCVTDatetimeToFormatString(timestamp, "WW,W-D;DAY:DD DDD.DY", "16,3-4;WEDNESDAY:21 111.Wed", cb);
testCVTDatetimeToFormatString(timestamp, "HH-HH12-HH24-MI-SS-SSSSS.FF2", "01 AM-01 AM-01-34-15-5655.25", cb);
testCVTDatetimeToFormatString(timestamp, "HH-HH12 P.M.-HH24-MI-SS-SSSSS.FF2", "01-01 A.M.-01-34-15-5655.25", cb);
}
BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIME_TZ)
{
testCVTDatetimeToFormatString(createTimeTZ(15, 35, 59, 0, 900), "HH-HH12-HH24-MI-SS-SSSSS.FF1/TZH/TZM", "03 PM-03 PM-15-35-59-56159.9/+00/00", cb);
testCVTDatetimeToFormatString(createTimeTZ(15, 35, 59, 0, 900), "HH A.M.-HH12-HH24-MI-SS-SSSSS.FF1/TZH/TZM", "03 P.M.-03-15-35-59-56159.9/+00/00", cb);
testCVTDatetimeToFormatString(createTimeTZ(15, 35, 59, 160), "HH24:MI-TZH:TZM", "15:35-+02:40", cb);
testCVTDatetimeToFormatString(createTimeTZ(15, 35, 59, -160), "HH24:MI TZH:TZM", "15:35 -02:40", cb);
@ -109,7 +223,7 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_TIMESTAMP_TZ)
testCVTDatetimeToFormatString(timestampTZ, "YEAR.YYYY.YYY.YY.Y/J", "1982.1982.982.82.2/2445081", cb);
testCVTDatetimeToFormatString(timestampTZ, "Q-MM-RM-MON-MONTH", "2-04-IV-Apr-APRIL", cb);
testCVTDatetimeToFormatString(timestampTZ, "WW,W-D;DAY:DD DDD.DY", "16,3-4;WEDNESDAY:21 111.Wed", cb);
testCVTDatetimeToFormatString(timestampTZ, "HH-HH12-HH24-MI-SS-SSSSS.FF2/TZH/TZM", "01 AM-01 AM-01-34-15-5655.50/+00/00", cb);
testCVTDatetimeToFormatString(timestampTZ, "HH A.M.-HH12-HH24-MI-SS-SSSSS.FF2/TZH/TZM", "01 A.M.-01-01-34-15-5655.50/+00/00", cb);
testCVTDatetimeToFormatString(createTimeStampTZ(1982, 4, 21, 1, 34, 15, 70), "HH24:MI-TZH:TZM", "01:34-+01:10", cb);
testCVTDatetimeToFormatString(createTimeStampTZ(1982, 4, 21, 1, 34, 15, -70), "HH24:MI TZH:TZM", "01:34 -01:10", cb);
@ -126,7 +240,7 @@ BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_SOLID_PATTERNS)
testCVTDatetimeToFormatString(timestampTZ, "YEARYYYYYYYYYYJ", "198219821982822445081", cb);
testCVTDatetimeToFormatString(timestampTZ, "QMMRMMONMONTH", "204IVAprAPRIL", cb);
testCVTDatetimeToFormatString(timestampTZ, "WWWD/DAYDDDDDDY", "1634/WEDNESDAY1111112", cb);
testCVTDatetimeToFormatString(timestampTZ, "HHHH12HH24MISSSSSSSFF2TZHTZM", "01 AM01 AM013456551550+0000", cb);
testCVTDatetimeToFormatString(timestampTZ, "HHHH12A.M.HH24MISSSSSSSFF2TZHTZM", "0101A.M.013456551550+0000", cb);
}
BOOST_AUTO_TEST_CASE(CVTDatetimeToFormatStringTest_RAW_TEXT)
@ -149,37 +263,48 @@ BOOST_AUTO_TEST_SUITE(CVTStringToFormatDateTime)
static void testCVTStringToFormatDateTime(const string& date, const string& format,
const ISC_TIMESTAMP_TZ& expected, Firebird::EXPECT_DATETIME expectedType, Callbacks& cb)
{
string varyingString = "xx";
varyingString += date;
*(USHORT*) varyingString.data() = varyingString.size() - sizeof(USHORT);
try
{
string varyingString = "xx";
varyingString += date;
*(USHORT*) varyingString.data() = varyingString.size() - sizeof(USHORT);
dsc desc;
desc.dsc_dtype = dtype_varying;
desc.dsc_length = varyingString.size() + sizeof(USHORT);
desc.dsc_address = (UCHAR*) varyingString.data();
desc.dsc_scale = 0;
dsc desc;
desc.dsc_dtype = dtype_varying;
desc.dsc_length = varyingString.size() + sizeof(USHORT);
desc.dsc_address = (UCHAR*) varyingString.data();
desc.dsc_scale = 0;
const ISC_TIMESTAMP_TZ result = CVT_string_to_format_datetime(&desc, format, &cb, expectedType);
BOOST_TEST_INFO("INPUT: " << "\"" << date.c_str() << "\"");
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
struct tm resultTimes;
memset(&resultTimes, 0, sizeof(resultTimes));
int resultFractions;
NoThrowTimeStamp::decode_timestamp(result.utc_timestamp, &resultTimes, &resultFractions);
SSHORT resultOffset;
TimeZoneUtil::extractOffset(result, &resultOffset);
const ISC_TIMESTAMP_TZ result = CVT_string_to_format_datetime(&desc, format, expectedType, &cb);
struct tm expectedTimes;
memset(&expectedTimes, 0, sizeof(expectedTimes));
int expectedFractions;
NoThrowTimeStamp::decode_timestamp(expected.utc_timestamp, &expectedTimes, &expectedFractions);
SSHORT expectedOffset;
TimeZoneUtil::extractOffset(expected, &expectedOffset);
struct tm resultTimes;
memset(&resultTimes, 0, sizeof(resultTimes));
int resultFractions;
NoThrowTimeStamp::decode_timestamp(result.utc_timestamp, &resultTimes, &resultFractions);
SSHORT resultOffset;
TimeZoneUtil::extractOffset(result, &resultOffset);
bool isEqual = !((bool) memcmp(&resultTimes, &expectedTimes, sizeof(struct tm)))
&& resultFractions == expectedFractions && resultOffset == expectedOffset;
struct tm expectedTimes;
memset(&expectedTimes, 0, sizeof(expectedTimes));
int expectedFractions;
NoThrowTimeStamp::decode_timestamp(expected.utc_timestamp, &expectedTimes, &expectedFractions);
SSHORT expectedOffset;
TimeZoneUtil::extractOffset(expected, &expectedOffset);
BOOST_TEST(isEqual, "\nRESULT: " << DECOMPOSE_TM_STRUCT(resultTimes, resultFractions, resultOffset)
<< "\nEXPECTED: " << DECOMPOSE_TM_STRUCT(expectedTimes, expectedFractions, expectedOffset));
bool isEqual = !((bool) memcmp(&resultTimes, &expectedTimes, sizeof(struct tm)))
&& resultFractions == expectedFractions && resultOffset == expectedOffset;
BOOST_TEST(isEqual, "\nRESULT: " << DECOMPOSE_TM_STRUCT(resultTimes, resultFractions, resultOffset)
<< "\nEXPECTED: " << DECOMPOSE_TM_STRUCT(expectedTimes, expectedFractions, expectedOffset));
}
catch(const Exception& ex)
{
BOOST_TEST_INFO("Exception was caught!");
BOOST_TEST(false);
}
}
static void testCVTStringToFormatDateTimeExpectDate(const string& date, const string& format,
@ -200,48 +325,141 @@ static void testCVTStringToFormatDateTimeExpectTimeTZ(const string& date, const
testCVTStringToFormatDateTime(date, format, expected, expect_sql_time_tz, cb);
};
static void testExceptionCvtStringToFormatDateTime(const string& date, const string& format, Callbacks& cb)
{
string varyingString = "xx";
varyingString += date;
*(USHORT*) varyingString.data() = varyingString.size() - sizeof(USHORT);
dsc desc;
desc.dsc_dtype = dtype_varying;
desc.dsc_length = varyingString.size() + sizeof(USHORT);
desc.dsc_address = (UCHAR*) varyingString.data();
desc.dsc_scale = 0;
BOOST_TEST_INFO("INPUT: " << "\"" << date.c_str() << "\"");
BOOST_TEST_INFO("FORMAT: " << "\"" << format.c_str() << "\"");
BOOST_CHECK_THROW(CVT_string_to_format_datetime(&desc, format, expect_timestamp_tz, &cb), status_exception);
}
BOOST_AUTO_TEST_SUITE(FunctionalTest)
BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_DATE)
{
testCVTStringToFormatDateTimeExpectDate("1", "YEAR", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1234", "YEAR", createTimeStampTZ(1234, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9999", "YEAR", createTimeStampTZ(9999, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YEAR", createTimeStampTZ(1, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("0001", "YEAR", createTimeStampTZ(1, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1234", "YEAR", createTimeStampTZ(1234, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9999", "YEAR", createTimeStampTZ(9999, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YYYY", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1234", "YYYY", createTimeStampTZ(1234, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9999", "YYYY", createTimeStampTZ(9999, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YYYY", createTimeStampTZ(1, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("0001", "YYYY", createTimeStampTZ(1, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1234", "YYYY", createTimeStampTZ(1234, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9999", "YYYY", createTimeStampTZ(9999, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YYY", createTimeStampTZ(2001, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("522", "YYY", createTimeStampTZ(2522, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("999", "YYY", createTimeStampTZ(1999, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YYY", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("001", "YYY", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("522", "YYY", createTimeStampTZ(2522, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("523", "YYY", createTimeStampTZ(2523, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("999", "YYY", createTimeStampTZ(2999, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YY", createTimeStampTZ(2001, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("72", "YY", createTimeStampTZ(2072, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("99", "YY", createTimeStampTZ(1999, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "YY", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("01", "YY", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("50", "YY", createTimeStampTZ(2050, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("99", "YY", createTimeStampTZ(2099, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "Y", createTimeStampTZ(2001, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9", "Y", createTimeStampTZ(2009, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "Y", createTimeStampTZ(2021, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9", "Y", createTimeStampTZ(2029, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "MM", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("6", "MM", createTimeStampTZ(1, 6, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("12", "MM", createTimeStampTZ(1, 12, 1, 0, 0, 0, 0), cb);
{
// RR pattern depends on last 2 digits of current year
MockCallback cb_2000(errFunc, std::bind(mockGetLocalDate, 2000));
MockCallback cb_2049(errFunc, std::bind(mockGetLocalDate, 2049));
MockCallback cb_2050(errFunc, std::bind(mockGetLocalDate, 2050));
MockCallback cb_2099(errFunc, std::bind(mockGetLocalDate, 2099));
testCVTStringToFormatDateTimeExpectDate("Jan", "MON", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Jun", "MON", createTimeStampTZ(1, 6, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Dec", "MON", createTimeStampTZ(1, 12, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "RR", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("1", "RR", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb_2049);
testCVTStringToFormatDateTimeExpectDate("1", "RR", createTimeStampTZ(2101, 0, 0, 0, 0, 0, 0), cb_2050);
testCVTStringToFormatDateTimeExpectDate("1", "RR", createTimeStampTZ(2101, 0, 0, 0, 0, 0, 0), cb_2099);
testCVTStringToFormatDateTimeExpectDate("January", "MONTH", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("June", "MONTH", createTimeStampTZ(1, 6, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("December", "MONTH", createTimeStampTZ(1, 12, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("01", "RR", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("01", "RR", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb_2049);
testCVTStringToFormatDateTimeExpectDate("01", "RR", createTimeStampTZ(2101, 0, 0, 0, 0, 0, 0), cb_2050);
testCVTStringToFormatDateTimeExpectDate("01", "RR", createTimeStampTZ(2101, 0, 0, 0, 0, 0, 0), cb_2099);
testCVTStringToFormatDateTimeExpectDate("I", "RM", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("IV", "RM", createTimeStampTZ(1, 4, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("XII", "RM", createTimeStampTZ(1, 12, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("49", "RR", createTimeStampTZ(2049, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("49", "RR", createTimeStampTZ(2049, 0, 0, 0, 0, 0, 0), cb_2049);
testCVTStringToFormatDateTimeExpectDate("49", "RR", createTimeStampTZ(2149, 0, 0, 0, 0, 0, 0), cb_2050);
testCVTStringToFormatDateTimeExpectDate("49", "RR", createTimeStampTZ(2149, 0, 0, 0, 0, 0, 0), cb_2099);
testCVTStringToFormatDateTimeExpectDate("1", "DD", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("15", "DD", createTimeStampTZ(1, 1, 15, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("31", "DD", createTimeStampTZ(1, 1, 31, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("50", "RR", createTimeStampTZ(1950, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("50", "RR", createTimeStampTZ(1950, 0, 0, 0, 0, 0, 0), cb_2049);
testCVTStringToFormatDateTimeExpectDate("50", "RR", createTimeStampTZ(2050, 0, 0, 0, 0, 0, 0), cb_2050);
testCVTStringToFormatDateTimeExpectDate("50", "RR", createTimeStampTZ(2050, 0, 0, 0, 0, 0, 0), cb_2099);
testCVTStringToFormatDateTimeExpectDate("99", "RR", createTimeStampTZ(1999, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("99", "RR", createTimeStampTZ(1999, 0, 0, 0, 0, 0, 0), cb_2049);
testCVTStringToFormatDateTimeExpectDate("99", "RR", createTimeStampTZ(2099, 0, 0, 0, 0, 0, 0), cb_2050);
testCVTStringToFormatDateTimeExpectDate("99", "RR", createTimeStampTZ(2099, 0, 0, 0, 0, 0, 0), cb_2099);
testCVTStringToFormatDateTimeExpectDate("1", "RRRR", createTimeStampTZ(2001, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("99", "RRRR", createTimeStampTZ(1999, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("0001", "RRRR", createTimeStampTZ(1, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("0099", "RRRR", createTimeStampTZ(99, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("1000", "RRRR", createTimeStampTZ(1000, 0, 0, 0, 0, 0, 0), cb_2000);
testCVTStringToFormatDateTimeExpectDate("9999", "RRRR", createTimeStampTZ(9999, 0, 0, 0, 0, 0, 0), cb_2000);
}
testCVTStringToFormatDateTimeExpectDate("1", "MM", createTimeStampTZ(0, 1, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("01", "MM", createTimeStampTZ(0, 1, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("6", "MM", createTimeStampTZ(0, 6, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("06", "MM", createTimeStampTZ(0, 6, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("12", "MM", createTimeStampTZ(0, 12, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Jan", "MON", createTimeStampTZ(0, 1, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Feb", "MON", createTimeStampTZ(0, 2, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Mar", "MON", createTimeStampTZ(0, 3, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Apr", "MON", createTimeStampTZ(0, 4, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("May", "MON", createTimeStampTZ(0, 5, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Jun", "MON", createTimeStampTZ(0, 6, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Jul", "MON", createTimeStampTZ(0, 7, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Aug", "MON", createTimeStampTZ(0, 8, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Sep", "MON", createTimeStampTZ(0, 9, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Oct", "MON", createTimeStampTZ(0, 10, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Nov", "MON", createTimeStampTZ(0, 11, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("Dec", "MON", createTimeStampTZ(0, 12, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("January", "MONTH", createTimeStampTZ(0, 1, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("February", "MONTH", createTimeStampTZ(0, 2, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("March", "MONTH", createTimeStampTZ(0, 3, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("April", "MONTH", createTimeStampTZ(0, 4, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("May", "MONTH", createTimeStampTZ(0, 5, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("June", "MONTH", createTimeStampTZ(0, 6, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("July", "MONTH", createTimeStampTZ(0, 7, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("August", "MONTH", createTimeStampTZ(0, 8, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("September", "MONTH", createTimeStampTZ(0, 9, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("October", "MONTH", createTimeStampTZ(0, 10, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("November", "MONTH", createTimeStampTZ(0, 11, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("December", "MONTH", createTimeStampTZ(0, 12, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("I", "RM", createTimeStampTZ(0, 1, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("II", "RM", createTimeStampTZ(0, 2, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("III", "RM", createTimeStampTZ(0, 3, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("IV", "RM", createTimeStampTZ(0, 4, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("V", "RM", createTimeStampTZ(0, 5, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("VI", "RM", createTimeStampTZ(0, 6, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("VII", "RM", createTimeStampTZ(0, 7, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("VIII", "RM", createTimeStampTZ(0, 8, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("IX", "RM", createTimeStampTZ(0, 9, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("X", "RM", createTimeStampTZ(0, 10, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("XI", "RM", createTimeStampTZ(0, 11, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("XII", "RM", createTimeStampTZ(0, 12, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1", "DD", createTimeStampTZ(0, 0, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("01", "DD", createTimeStampTZ(0, 0, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("15", "DD", createTimeStampTZ(0, 0, 15, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("31", "DD", createTimeStampTZ(0, 0, 31, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("2451887", "J", createTimeStampTZ(2000, 12, 8, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1721426", "J", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
@ -251,85 +469,150 @@ BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_DATE)
testCVTStringToFormatDateTimeExpectDate("1981-8/13", "YEAR.MM.DD", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("9999 12;31", "YEAR.MM.DD", createTimeStampTZ(9999, 12, 31, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1981-Aug/13", "YEAR.MON.DD", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1981-August/13", "YEAR.MONTH.DD", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("1981-VIII/13", "YEAR.RM.DD", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("25.Jan.25", "YY;MON;DD", createTimeStampTZ(2025, 1, 25, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectDate("./.1981./-8--/13--", " YEAR. -.MM.,,-.DD//", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
}
BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_TIME)
{
testCVTStringToFormatDateTimeExpectTime("12 AM", "HH", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 AM", "HH", createTimeStampTZ(1, 1, 1, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 AM", "HH", createTimeStampTZ(1, 1, 1, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 A.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 A.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 A.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 A.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 A.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 A.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 A.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 A.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 PM", "HH", createTimeStampTZ(1, 1, 1, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 PM", "HH", createTimeStampTZ(1, 1, 1, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 PM", "HH", createTimeStampTZ(1, 1, 1, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 P.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 P.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 P.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 P.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 P.M.", "HH A.M.", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 P.M.", "HH P.M.", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 AM", "HH12", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 AM", "HH12", createTimeStampTZ(1, 1, 1, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 AM", "HH12", createTimeStampTZ(1, 1, 1, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 A.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 A.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 A.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 A.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 A.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 A.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 A.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 A.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 PM", "HH12", createTimeStampTZ(1, 1, 1, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 PM", "HH12", createTimeStampTZ(1, 1, 1, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 PM", "HH12", createTimeStampTZ(1, 1, 1, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 P.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12 P.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 P.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("01 P.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 P.M.", "HH12 A.M.", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("11 P.M.", "HH12 P.M.", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "HH24", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12", "HH24", createTimeStampTZ(1, 1, 1, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("23", "HH24", createTimeStampTZ(1, 1, 1, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("A.M. 12", "A.M. HH", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("A.M. 1", "P.M. HH", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("A.M. 01", "P.M. HH", createTimeStampTZ(0, 0, 0, 1, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("A.M. 11", "A.M. HH", createTimeStampTZ(0, 0, 0, 11, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("P.M. 12", "A.M. HH", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("P.M. 1", "P.M. HH", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("P.M. 01", "P.M. HH", createTimeStampTZ(0, 0, 0, 13, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("P.M. 11", "A.M. HH", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "MI", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("30", "MI", createTimeStampTZ(1, 1, 1, 0, 30, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("59", "MI", createTimeStampTZ(1, 1, 1, 0, 59, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "HH24", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("00", "HH24", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("12", "HH24", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("23", "HH24", createTimeStampTZ(0, 0, 0, 23, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "SS", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("30", "SS", createTimeStampTZ(1, 1, 1, 0, 0, 30, 0), cb);
testCVTStringToFormatDateTimeExpectTime("59", "SS", createTimeStampTZ(1, 1, 1, 0, 0, 59, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "MI", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("00", "MI", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("30", "MI", createTimeStampTZ(0, 0, 0, 0, 30, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("59", "MI", createTimeStampTZ(0, 0, 0, 0, 59, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "SSSSS", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("45315", "SSSSS", createTimeStampTZ(1, 1, 1, 12, 35, 15, 0), cb);
testCVTStringToFormatDateTimeExpectTime("86399", "SSSSS", createTimeStampTZ(1, 1, 1, 23, 59, 59, 0), cb);
testCVTStringToFormatDateTimeExpectTime("0", "SS", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("00", "SS", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("30", "SS", createTimeStampTZ(0, 0, 0, 0, 0, 30, 0), cb);
testCVTStringToFormatDateTimeExpectTime("59", "SS", createTimeStampTZ(0, 0, 0, 0, 0, 59, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF1", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("5", "FF1", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("9", "FF1", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 9000), cb);
testCVTStringToFormatDateTimeExpectTime("0", "SSSSS", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("00000", "SSSSS", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTime("45315", "SSSSS", createTimeStampTZ(0, 0, 0, 12, 35, 15, 0), cb);
testCVTStringToFormatDateTimeExpectTime("86399", "SSSSS", createTimeStampTZ(0, 0, 0, 23, 59, 59, 0), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF2", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF2", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("50", "FF2", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("99", "FF2", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 9900), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF1", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("5", "FF1", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("9", "FF1", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 9000), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF3", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 10), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF3", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("100", "FF3", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("500", "FF3", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("999", "FF3", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 9990), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF2", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF2", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("50", "FF2", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("99", "FF2", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 9900), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 1), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 10), cb);
testCVTStringToFormatDateTimeExpectTime("100", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("1000", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("5000", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("9999", "FF4", createTimeStampTZ(1, 1, 1, 0, 0, 0, 0, 9999), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF3", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 10), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF3", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("100", "FF3", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("500", "FF3", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("999", "FF3", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 9990), cb);
testCVTStringToFormatDateTimeExpectTime("1 PM - 25 - 45 - 200", "HH.MI.SS.FF4", createTimeStampTZ(1, 1, 1, 13, 25, 45, 0, 200), cb);
testCVTStringToFormatDateTimeExpectTime("15:0:15:2", "HH24.MI.SS.FF1", createTimeStampTZ(1, 1, 1, 15, 0, 15, 0, 2000), cb);
testCVTStringToFormatDateTimeExpectTime("1", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 1), cb);
testCVTStringToFormatDateTimeExpectTime("10", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 10), cb);
testCVTStringToFormatDateTimeExpectTime("100", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 100), cb);
testCVTStringToFormatDateTimeExpectTime("1000", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 1000), cb);
testCVTStringToFormatDateTimeExpectTime("5000", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 5000), cb);
testCVTStringToFormatDateTimeExpectTime("9999", "FF4", createTimeStampTZ(0, 0, 0, 0, 0, 0, 0, 9999), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M. - 25 - 45 - 200", "HH P.M. MI.SS.FF4", createTimeStampTZ(0, 0, 0, 13, 25, 45, 0, 200), cb);
testCVTStringToFormatDateTimeExpectTime("15:0:15:2", "HH24.MI.SS.FF1", createTimeStampTZ(0, 0, 0, 15, 0, 15, 0, 2000), cb);
}
BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_TZ)
{
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 2:30", "HH24:MI TZH:TZM", createTimeStampTZ(1, 1, 1, 12, 0, 0, 150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +2:30", "HH24:MI TZH:TZM", createTimeStampTZ(1, 1, 1, 12, 0, 0, 150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 -2:30", "HH24:MI TZH:TZM", createTimeStampTZ(1, 1, 1, 12, 0, 0, -150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +0:30", "HH24:MI TZH:TZM", createTimeStampTZ(1, 1, 1, 12, 0, 0, 30, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +0:00", "HH24:MI TZH:TZM", createTimeStampTZ(1, 1, 1, 12, 0, 0, 0, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 2:30", "HH24:MI TZH:TZM", createTimeStampTZ(0, 0, 0, 12, 0, 0, 150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +2:30", "HH24:MI TZH:TZM", createTimeStampTZ(0, 0, 0, 12, 0, 0, 150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 -2:30", "HH24:MI TZH:TZM", createTimeStampTZ(0, 0, 0, 12, 0, 0, -150, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +0:30", "HH24:MI TZH:TZM", createTimeStampTZ(0, 0, 0, 12, 0, 0, 30, 0), cb);
testCVTStringToFormatDateTimeExpectTimeTZ("12:00 +0:00", "HH24:MI TZH:TZM", createTimeStampTZ(0, 0, 0, 12, 0, 0, 0, 0), cb);
}
BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_SOLID_PATTERNS)
{
testCVTStringToFormatDateTimeExpectTime("1 PM - 25 - 45 - 200", "HHMISSFF4", createTimeStampTZ(1, 1, 1, 13, 25, 45, 0, 200), cb);
testCVTStringToFormatDateTimeExpectTime("1 P.M. - 25 - 45 - 200", "HHA.M.MISSFF4", createTimeStampTZ(0, 0, 0, 13, 25, 45, 0, 200), cb);
testCVTStringToFormatDateTimeExpectDate("1981-8/13", "YEARMMDD", createTimeStampTZ(1981, 8, 13, 0, 0, 0, 0), cb);
}
BOOST_AUTO_TEST_CASE(CVTStringToFormatDateTime_EXCEPTION_CHECK)
{
testExceptionCvtStringToFormatDateTime("2000.12.11", "WRONG FORMAT", cb);
testExceptionCvtStringToFormatDateTime("2000.12.11", "YYYY.MM.DD SS", cb);
testExceptionCvtStringToFormatDateTime("2000.12", "YYYY.MM.DD", cb);
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.M.", cb);
testExceptionCvtStringToFormatDateTime("1 A.G.", "HH12 A.P.", cb);
testExceptionCvtStringToFormatDateTime("24 12 A.M.", "HH24 HH12 P.M.", cb);
testExceptionCvtStringToFormatDateTime("24 12", "HH24 HH12", cb);
testExceptionCvtStringToFormatDateTime("24 A.M.", "HH24 P.M.", cb);
testExceptionCvtStringToFormatDateTime("12", "HH12", cb);
testExceptionCvtStringToFormatDateTime("A.M.", "P.M.", cb);
testExceptionCvtStringToFormatDateTime("P.M.", "A.M.", cb);
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH12 A.M.", cb);
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH12 P.M.", cb);
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH A.M.", cb);
testExceptionCvtStringToFormatDateTime("1 1 A.M.", "SSSSS HH P.M.", cb);
testExceptionCvtStringToFormatDateTime("1 1", "SSSSS HH24", cb);
testExceptionCvtStringToFormatDateTime("1 1", "SSSSS MI", cb);
testExceptionCvtStringToFormatDateTime("1 1", "SSSSS SS", cb);
testExceptionCvtStringToFormatDateTime("30 1", "TZM SS", cb);
testExceptionCvtStringToFormatDateTime("30", "TZM", cb);
}
BOOST_AUTO_TEST_SUITE_END() // FunctionalTest
BOOST_AUTO_TEST_SUITE_END() // CVTStringToFormatDateTime

View File

@ -26,22 +26,38 @@ namespace CvtTestUtils {
template<typename T>
static constexpr int sign(T value)
{
return (T(0) < value) - (value < T(0));
return (value >= T(0)) ? 1 : -1;
}
static ISC_DATE mockGetLocalDate(int year = 2023)
{
struct tm time;
memset(&time, 0, sizeof(time));
time.tm_year = year - 1900;
time.tm_mon = 0;
time.tm_mday = 1;
return NoThrowTimeStamp::encode_date(&time);
}
// Pass 0 to year, month and day to use CurrentTimeStamp for them
static struct tm initTMStruct(int year, int month, int day)
{
struct tm currentTime;
NoThrowTimeStamp::decode_date(mockGetLocalDate(), &currentTime);
struct tm times;
memset(&times, 0, sizeof(struct tm));
times.tm_year = year - 1900;
times.tm_mon = month - 1;
times.tm_mday = day;
times.tm_year = year > 0 ? year - 1900 : currentTime.tm_year;
times.tm_mon = month > 0 ? month - 1 : currentTime.tm_mon;
times.tm_mday = day > 0 ? day : currentTime.tm_mday;
mktime(&times);
return times;
}
// Pass 0 to year, month and day to use CurrentTimeStamp for them
static ISC_DATE createDate(int year, int month, int day)
{
struct tm times = initTMStruct(year, month, day);
@ -53,6 +69,7 @@ static ISC_TIME createTime(int hours, int minutes, int seconds, int fractions =
return NoThrowTimeStamp::encode_time(hours, minutes, seconds, fractions);
}
// Pass 0 to year, month and day to use CurrentTimeStamp for them
static ISC_TIMESTAMP createTimeStamp(int year, int month, int day, int hours, int minutes, int seconds, int fractions = 0)
{
struct tm times = initTMStruct(year, month, day);
@ -63,6 +80,7 @@ static ISC_TIMESTAMP createTimeStamp(int year, int month, int day, int hours, in
return NoThrowTimeStamp::encode_timestamp(&times, fractions);
}
// Pass 0 to year, month and day to use CurrentTimeStamp for them
static ISC_TIMESTAMP_TZ createTimeStampTZ(int year, int month, int day, int hours, int minutes, int seconds,
int offsetInMinutes, int fractions = 0)
{
@ -84,10 +102,11 @@ static ISC_TIME_TZ createTimeTZ(int hours, int minutes, int seconds, int offsetI
}
class CVTCallback : public Firebird::Callbacks
class MockCallback : public Firebird::Callbacks
{
public:
explicit CVTCallback(ErrorFunction aErr) : Callbacks(aErr)
explicit MockCallback(ErrorFunction aErr, std::function<SLONG()> mockGetLocalDateFunc)
: Callbacks(aErr), m_mockGetLocalDateFunc(mockGetLocalDateFunc)
{}
public:
@ -97,10 +116,18 @@ public:
void validateData(Firebird::CharSet* toCharset, SLONG length, const UCHAR* q) override { }
ULONG validateLength(Firebird::CharSet* charSet, CHARSET_ID charSetId, ULONG length, const UCHAR* start,
const USHORT size) override { return 0; }
SLONG getLocalDate() override { return 0; }
SLONG getLocalDate() override
{
return m_mockGetLocalDateFunc();
}
ISC_TIMESTAMP getCurrentGmtTimeStamp() override { ISC_TIMESTAMP ts; return ts; }
USHORT getSessionTimeZone() override { return 1439; } // 1439 is ONE_DAY, so we have no offset
void isVersion4(bool& v4) override { }
private:
std::function<SLONG()> m_mockGetLocalDateFunc;
};

View File

@ -3815,38 +3815,38 @@ dsc* CastNode::perform(thread_db* tdbb, impure_value* impure, dsc* value,
{
case dtype_sql_time:
{
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, &EngineCallbacks::instance,
expect_sql_time);
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_time,
&EngineCallbacks::instance);
*(ISC_TIME*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp.timestamp_time;
break;
}
case dtype_sql_date:
{
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, &EngineCallbacks::instance,
expect_sql_date);
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_date,
&EngineCallbacks::instance);
*(ISC_DATE*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp.timestamp_date;
break;
}
case dtype_timestamp:
{
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, &EngineCallbacks::instance,
expect_timestamp);
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_timestamp,
&EngineCallbacks::instance);
*(ISC_TIMESTAMP*) impure->vlu_desc.dsc_address = timestampTZ.utc_timestamp;
break;
}
case dtype_sql_time_tz:
case dtype_ex_time_tz:
{
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, &EngineCallbacks::instance,
expect_sql_time_tz);
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_sql_time_tz,
&EngineCallbacks::instance);
*(ISC_TIME_TZ*) impure->vlu_desc.dsc_address = TimeZoneUtil::timeStampTzToTimeTz(timestampTZ);
break;
}
case dtype_timestamp_tz:
case dtype_ex_timestamp_tz:
{
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, &EngineCallbacks::instance,
expect_timestamp_tz);
ISC_TIMESTAMP_TZ timestampTZ = CVT_string_to_format_datetime(value, format, expect_timestamp_tz,
&EngineCallbacks::instance);
*(ISC_TIMESTAMP_TZ*) impure->vlu_desc.dsc_address = timestampTZ;
break;
}

View File

@ -978,6 +978,9 @@ FB_IMPL_MSG(JRD, 975, invalid_data_type_for_date_format, -901, "HY", "000", "It
FB_IMPL_MSG(JRD, 976, incompatible_date_format_with_current_date_type, -901, "HY", "000", "Cannot use \"@1\" format with current date type")
FB_IMPL_MSG(JRD, 977, value_for_pattern_is_out_of_range, -901, "HY", "000", "Value for @1 pattern is out of range [@2, @3]")
FB_IMPL_MSG(JRD, 978, month_name_mismatch, -901, "HY", "000", "@1 is not MONTH")
FB_IMPL_MSG(JRD, 979, incorrect_hours_period, -901, "HY", "000", "@1 is incorrect period for 12H, it should be AM or PM")
FB_IMPL_MSG(JRD, 979, incorrect_hours_period, -901, "HY", "000", "@1 is incorrect period for 12H, it should be A.M. or P.M.")
FB_IMPL_MSG(JRD, 980, data_for_format_is_exhausted, -901, "HY", "000", "All data has been read, but format pattern wants more. Unfilled patterns: \"@1\"")
FB_IMPL_MSG(JRD, 981, trailing_part_of_string, -901, "HY", "000", "There is a trailing part of input string that does not fit into FORMAT: \"@1\"")
FB_IMPL_MSG(JRD, 982, pattern_cant_be_used_without_other_pattern, -901, "HY", "000", "@1 can't be used without @2")
FB_IMPL_MSG(JRD, 983, pattern_cant_be_used_without_other_pattern_and_vice_versa, -901, "HY", "000", "@1 can't be used without @2 and vice versa")
FB_IMPL_MSG(JRD, 984, incompatible_format_patterns, -901, "HY", "000", "@1 incompatible with @2")

View File

@ -5724,6 +5724,9 @@ const
isc_incorrect_hours_period = 335545299;
isc_data_for_format_is_exhausted = 335545300;
isc_trailing_part_of_string = 335545301;
isc_pattern_cant_be_used_without_other_pattern = 335545302;
isc_pattern_cant_be_used_without_other_pattern_and_vice_versa = 335545303;
isc_incompatible_format_patterns = 335545304;
isc_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;
isc_gfix_incmp_sw = 335740932;

View File

@ -251,13 +251,15 @@ static const struct
// New BLR in FB5.0
{"dcl_local_table", dcl_local_table},
{"local_table_truncate", one_word},
{"local_table_id", local_table},
{"local_table_id", local_table}, // 220
{"outer_map", outer_map},
{NULL, NULL}, // blr_json_function
{"skip_locked", zero},
// New BLR in FB6.0
{"invoke_function", invoke_function},
{"invoke_procedure", invsel_procedure},
{"select_procedure", invsel_procedure},
{"blr_default_arg", zero},
{"cast_format", cast_format},
{0, 0}
};

View File

@ -419,7 +419,8 @@ static const UCHAR
outer_map[] = { op_outer_map, 0 },
in_list[] = { op_line, op_verb, op_indent, op_word, op_line, op_args, 0},
invoke_function[] = { op_invoke_function, 0 },
invsel_procedure[] = { op_invsel_procedure, 0 };
invsel_procedure[] = { op_invsel_procedure, 0 },
cast_format[] = { op_byte, op_literal, op_dtype, op_line, op_verb, 0 };
#include "../jrd/blp.h"