fix-timestamp-format.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env tsx
  2. /**
  3. * 修复 works 和 work_day_statistics 表的 created_at 和 updated_at 字段格式
  4. * 将 timestamp 类型改为 datetime 类型,并修复历史数据
  5. *
  6. * 运行: cd server && pnpm exec tsx src/scripts/fix-timestamp-format.ts
  7. */
  8. import { initDatabase } from '../models/index.js';
  9. import { AppDataSource } from '../models/index.js';
  10. import { logger } from '../utils/logger.js';
  11. async function fixTimestampFormat() {
  12. try {
  13. await initDatabase();
  14. logger.info('数据库连接已初始化');
  15. const queryRunner = AppDataSource.createQueryRunner();
  16. await queryRunner.connect();
  17. try {
  18. logger.info('\n========================================');
  19. logger.info('开始修复时间字段格式...');
  20. logger.info('========================================\n');
  21. // 1. 修改 works 表的字段类型
  22. logger.info('1. 修改 works 表的 created_at 和 updated_at 字段类型...');
  23. await queryRunner.query(`
  24. ALTER TABLE works
  25. MODIFY COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  26. MODIFY COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  27. `);
  28. logger.info(' ✓ works 表字段类型修改完成');
  29. // 2. 修改 work_day_statistics 表的字段类型
  30. logger.info('2. 修改 work_day_statistics 表的 created_at 和 updated_at 字段类型...');
  31. await queryRunner.query(`
  32. ALTER TABLE work_day_statistics
  33. MODIFY COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  34. MODIFY COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  35. `);
  36. logger.info(' ✓ work_day_statistics 表字段类型修改完成');
  37. // 3. 修复历史数据 - 将时间转换为正确的格式
  38. logger.info('\n3. 修复 works 表的历史数据...');
  39. const worksResult = await queryRunner.query(`
  40. UPDATE works
  41. SET created_at = CONVERT_TZ(created_at, @@session.time_zone, '+08:00'),
  42. updated_at = CONVERT_TZ(updated_at, @@session.time_zone, '+08:00')
  43. WHERE created_at IS NOT NULL OR updated_at IS NOT NULL
  44. `);
  45. logger.info(` ✓ works 表已更新 ${worksResult.affectedRows || 0} 条记录`);
  46. logger.info('\n4. 修复 work_day_statistics 表的历史数据...');
  47. const statsResult = await queryRunner.query(`
  48. UPDATE work_day_statistics
  49. SET created_at = CONVERT_TZ(created_at, @@session.time_zone, '+08:00'),
  50. updated_at = CONVERT_TZ(updated_at, @@session.time_zone, '+08:00')
  51. WHERE created_at IS NOT NULL OR updated_at IS NOT NULL
  52. `);
  53. logger.info(` ✓ work_day_statistics 表已更新 ${statsResult.affectedRows || 0} 条记录`);
  54. // 4. 验证修复结果
  55. logger.info('\n5. 验证修复结果...');
  56. const sampleWorks = await queryRunner.query(`
  57. SELECT id, created_at, updated_at
  58. FROM works
  59. ORDER BY id DESC
  60. LIMIT 5
  61. `);
  62. logger.info(' works 表示例数据:');
  63. sampleWorks.forEach((row: any) => {
  64. logger.info(` ID ${row.id}: created_at=${row.created_at}, updated_at=${row.updated_at}`);
  65. });
  66. const sampleStats = await queryRunner.query(`
  67. SELECT id, created_at, updated_at
  68. FROM work_day_statistics
  69. ORDER BY id DESC
  70. LIMIT 5
  71. `);
  72. logger.info(' work_day_statistics 表示例数据:');
  73. sampleStats.forEach((row: any) => {
  74. logger.info(` ID ${row.id}: created_at=${row.created_at}, updated_at=${row.updated_at}`);
  75. });
  76. logger.info('\n========================================');
  77. logger.info('时间字段格式修复完成!');
  78. logger.info('========================================\n');
  79. } catch (error: any) {
  80. logger.error('修复过程中出错:', error);
  81. throw error;
  82. } finally {
  83. await queryRunner.release();
  84. }
  85. } catch (error: any) {
  86. logger.error('修复失败:', error);
  87. if (error instanceof Error) {
  88. logger.error('错误堆栈:', error.stack);
  89. }
  90. process.exit(1);
  91. } finally {
  92. await AppDataSource.destroy();
  93. process.exit(0);
  94. }
  95. }
  96. fixTimestampFormat().catch(console.error);