institutional-trader/backend/scripts/fixSingleDigitHours.js

160 lines
4.7 KiB
JavaScript

/**
* Fix Script: Pad Single-Digit Hours in CreatedTime
* This script fixes times like "2:31:47 PM" to "02:31:47 PM"
*
* Usage: node scripts/fixSingleDigitHours.js [--dry-run]
*/
import { rawQuery } from '../src/db.js';
import dotenv from 'dotenv';
dotenv.config();
async function fixSingleDigitHours(dryRun = false) {
console.log('🔍 Checking for single-digit hour times...\n');
try {
// First, find all entries with single-digit hours
const problematic = await rawQuery(`
SELECT
ctid,
"CreatedDate",
"CreatedTime",
"Symbol"
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND (
-- Single-digit hour with seconds: "2:31:47 PM"
"CreatedTime"::text ~ '^[1-9]:[0-9]{2}:[0-9]{2}\\s*(AM|PM)$'
-- Single-digit hour with minutes only: "2:30 PM"
OR "CreatedTime"::text ~ '^[1-9]:[0-9]{2}\\s*(AM|PM)$'
)
ORDER BY "CreatedDate" DESC, "CreatedTime" DESC
LIMIT 100;
`);
console.log(`📊 Found ${problematic.length} entries with single-digit hours`);
if (problematic.length === 0) {
console.log('✅ No entries with single-digit hours found!');
return;
}
// Show sample
console.log('\n📋 Sample of problematic entries:');
problematic.slice(0, 10).forEach(row => {
console.log(` - "${row.CreatedTime}" on ${row.CreatedDate} (${row.Symbol})`);
});
if (dryRun) {
console.log('\n🔍 DRY RUN MODE - No changes will be made');
console.log(` Would fix ${problematic.length} entries`);
return;
}
// Count total affected
const totalCount = await rawQuery(`
SELECT COUNT(*) as total
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND (
"CreatedTime"::text ~ '^[1-9]:[0-9]{2}:[0-9]{2}\\s*(AM|PM)$'
OR "CreatedTime"::text ~ '^[1-9]:[0-9]{2}\\s*(AM|PM)$'
);
`);
const total = totalCount[0]?.total || 0;
console.log(`\n🔧 Fixing ${total} entries...`);
// Fix entries with seconds: "2:31:47 PM" -> "02:31:47 PM"
const fixWithSeconds = await rawQuery(`
UPDATE "OptionsFlow_monthly"
SET "CreatedTime" = REGEXP_REPLACE(
btrim("CreatedTime"::text),
'^([1-9])(:[0-9]{2}:[0-9]{2}\\s*(AM|PM))',
'0\\1\\2',
'i'
)
WHERE "CreatedTime" IS NOT NULL
AND "CreatedTime"::text ~ '^[1-9]:[0-9]{2}:[0-9]{2}\\s*(AM|PM)$';
`);
console.log(` ✅ Fixed entries with seconds format`);
// Fix entries with minutes only: "2:30 PM" -> "02:30 PM"
const fixWithMinutes = await rawQuery(`
UPDATE "OptionsFlow_monthly"
SET "CreatedTime" = REGEXP_REPLACE(
btrim("CreatedTime"::text),
'^([1-9])(:[0-9]{2}\\s*(AM|PM))',
'0\\1\\2',
'i'
)
WHERE "CreatedTime" IS NOT NULL
AND "CreatedTime"::text ~ '^[1-9]:[0-9]{2}\\s*(AM|PM)$';
`);
console.log(` ✅ Fixed entries with minutes format`);
// Verify the fix
const remaining = await rawQuery(`
SELECT COUNT(*) as total
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND (
"CreatedTime"::text ~ '^[1-9]:[0-9]{2}:[0-9]{2}\\s*(AM|PM)$'
OR "CreatedTime"::text ~ '^[1-9]:[0-9]{2}\\s*(AM|PM)$'
);
`);
const remainingCount = remaining[0]?.total || 0;
if (remainingCount === 0) {
console.log(`\n✅ Successfully fixed all ${total} entries!`);
} else {
console.log(`\n⚠️ Warning: ${remainingCount} entries still have single-digit hours`);
console.log(' This might be due to whitespace or other formatting issues');
}
// Show sample of fixed entries
const fixedSample = await rawQuery(`
SELECT
"CreatedDate",
"CreatedTime",
COUNT(*) as count
FROM "OptionsFlow_monthly"
WHERE "CreatedTime" IS NOT NULL
AND "CreatedTime"::text ~ '^[0-9]{2}:[0-9]{2}:[0-9]{2}\\s*(AM|PM)$'
GROUP BY "CreatedDate", "CreatedTime"
ORDER BY "CreatedDate" DESC
LIMIT 5;
`);
console.log('\n📋 Sample of fixed entries (now properly formatted):');
fixedSample.forEach(row => {
console.log(` - "${row.CreatedTime}" on ${row.CreatedDate}: ${row.count} occurrences`);
});
} catch (error) {
console.error('❌ Error fixing single-digit hours:', error.message);
console.error(error);
throw error;
}
}
// Parse command line arguments
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run') || args.includes('-d');
// Run the fix
fixSingleDigitHours(dryRun)
.then(() => {
console.log('\n✅ Fix complete');
process.exit(0);
})
.catch((error) => {
console.error('\n❌ Fix failed:', error);
process.exit(1);
});