/** * 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); });