institutional-trader/backend/scripts/checkParsingFailures.js

108 lines
3.9 KiB
JavaScript

/**
* Check for timestamp parsing failures in OptionsFlow_monthly
* This identifies entries where the time format can't be parsed
*/
import { rawQuery } from '../src/db.js';
import dotenv from 'dotenv';
dotenv.config();
async function checkParsingFailures() {
console.log('🔍 Checking for timestamp parsing failures...\n');
try {
// Test the actual parsing logic from optionflowrockerscorer.sql
const parsingTest = await rawQuery(`
SELECT
"CreatedDate",
"CreatedTime",
COUNT(*) as count,
-- Try to parse the timestamp using the same logic as the query
CASE
WHEN "CreatedDate"::text ~ '^\\d{4}-\\d{2}-\\d{2}$' AND "CreatedTime"::text ~* '(AM|PM)'
THEN CASE
WHEN "CreatedTime"::text ~ ':\\d{2}:\\d{2}\\s*(AM|PM)'
THEN to_timestamp("CreatedDate"::text || ' ' || REGEXP_REPLACE(btrim("CreatedTime"::text), '^0([1-9]):', '\\1:'), 'YYYY-MM-DD HH12:MI:SS AM')
WHEN "CreatedTime"::text ~ ':\\d{2}\\s*(AM|PM)'
THEN to_timestamp("CreatedDate"::text || ' ' || REGEXP_REPLACE(btrim("CreatedTime"::text), '^0([1-9]):', '\\1:'), 'YYYY-MM-DD HH12:MI AM')
ELSE NULL
END
ELSE NULL
END as parsed_ts
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND "CreatedTime"::text ~* '(AM|PM)'
GROUP BY "CreatedDate", "CreatedTime"
HAVING
CASE
WHEN "CreatedDate"::text ~ '^\\d{4}-\\d{2}-\\d{2}$' AND "CreatedTime"::text ~* '(AM|PM)'
THEN CASE
WHEN "CreatedTime"::text ~ ':\\d{2}:\\d{2}\\s*(AM|PM)'
THEN to_timestamp("CreatedDate"::text || ' ' || REGEXP_REPLACE(btrim("CreatedTime"::text), '^0([1-9]):', '\\1:'), 'YYYY-MM-DD HH12:MI:SS AM')
WHEN "CreatedTime"::text ~ ':\\d{2}\\s*(AM|PM)'
THEN to_timestamp("CreatedDate"::text || ' ' || REGEXP_REPLACE(btrim("CreatedTime"::text), '^0([1-9]):', '\\1:'), 'YYYY-MM-DD HH12:MI AM')
ELSE NULL
END
ELSE NULL
END IS NULL
ORDER BY count DESC
LIMIT 20;
`);
console.log('📊 Entries that fail to parse (NULL timestamps):');
if (parsingTest.length > 0) {
console.log(` Found ${parsingTest.length} time patterns that fail to parse`);
parsingTest.forEach(row => {
console.log(` - Date: ${row.CreatedDate}, Time: "${row.CreatedTime}" (${row.count} occurrences)`);
});
} else {
console.log(' ✅ All time entries parse successfully');
}
console.log('');
// Check for times that don't match expected patterns
const unusualFormats = await rawQuery(`
SELECT
"CreatedDate",
"CreatedTime",
COUNT(*) as count
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND "CreatedTime"::text ~* '(AM|PM)'
-- Times that have AM/PM but don't match standard patterns
AND "CreatedTime"::text !~ '^\\d{1,2}:\\d{2}:\\d{2}\\s*(AM|PM)$'
AND "CreatedTime"::text !~ '^\\d{1,2}:\\d{2}\\s*(AM|PM)$'
GROUP BY "CreatedDate", "CreatedTime"
ORDER BY count DESC
LIMIT 20;
`);
console.log('📊 Unusual time formats (AM/PM but non-standard):');
if (unusualFormats.length > 0) {
console.log(` Found ${unusualFormats.length} unusual time formats`);
unusualFormats.forEach(row => {
console.log(` - "${row.CreatedTime}" on ${row.CreatedDate}: ${row.count} occurrences`);
});
} else {
console.log(' ✅ All times match expected formats');
}
console.log('');
} catch (error) {
console.error('❌ Error checking parsing failures:', error.message);
console.error(error);
}
}
checkParsingFailures()
.then(() => {
console.log('\n✅ Diagnostic complete');
process.exit(0);
})
.catch((error) => {
console.error('\n❌ Diagnostic failed:', error);
process.exit(1);
});