Просмотр исходного кода

Fix date format parsing for queue scheduling (#233)

Date input for scheduled prints was swapping month and day for European
users because:
1. EU format only accepted "/" separator, not "." which is common in
   European locales (e.g., "5.2.2026" for Feb 5th)
2. System format fell back to new Date() which interprets ambiguous
   dates in US format

Changes:
- Added splitDateParts() helper to accept /, ., and - separators
- Updated parseDateInput() to use proper locale detection for system
  format instead of relying on Date constructor
- All explicit formats (us, eu, iso) now accept any of the three
  separators

Closes #233
maziggy 7 месяцев назад
Родитель
Сommit
00caf3ee1a
3 измененных файлов с 46 добавлено и 19 удалено
  1. 45 18
      frontend/src/utils/date.ts
  2. 0 0
      static/assets/index-Dc108DF_.js
  3. 1 1
      static/index.html

+ 45 - 18
frontend/src/utils/date.ts

@@ -94,9 +94,22 @@ export function formatTimeInput(date: Date, timeFormat: TimeFormat = 'system'):
   }
   }
 }
 }
 
 
+/**
+ * Split a date string by common separators (/, ., -).
+ */
+function splitDateParts(value: string): string[] | null {
+  // Try common separators: /, ., -
+  for (const sep of ['/', '.', '-']) {
+    const parts = value.split(sep);
+    if (parts.length === 3) return parts;
+  }
+  return null;
+}
+
 /**
 /**
  * Parse a date string based on format setting.
  * Parse a date string based on format setting.
  * Returns null if parsing fails.
  * Returns null if parsing fails.
+ * Supports common separators: / . -
  */
  */
 export function parseDateInput(value: string, dateFormat: DateFormat = 'system'): Date | null {
 export function parseDateInput(value: string, dateFormat: DateFormat = 'system'): Date | null {
   if (!value) return null;
   if (!value) return null;
@@ -106,27 +119,27 @@ export function parseDateInput(value: string, dateFormat: DateFormat = 'system')
   try {
   try {
     switch (dateFormat) {
     switch (dateFormat) {
       case 'us': {
       case 'us': {
-        // MM/DD/YYYY
-        const parts = value.split('/');
-        if (parts.length !== 3) return null;
+        // MM/DD/YYYY (also accepts . and - separators)
+        const parts = splitDateParts(value);
+        if (!parts) return null;
         month = parseInt(parts[0], 10);
         month = parseInt(parts[0], 10);
         day = parseInt(parts[1], 10);
         day = parseInt(parts[1], 10);
         year = parseInt(parts[2], 10);
         year = parseInt(parts[2], 10);
         break;
         break;
       }
       }
       case 'eu': {
       case 'eu': {
-        // DD/MM/YYYY
-        const parts = value.split('/');
-        if (parts.length !== 3) return null;
+        // DD/MM/YYYY (also accepts . and - separators)
+        const parts = splitDateParts(value);
+        if (!parts) return null;
         day = parseInt(parts[0], 10);
         day = parseInt(parts[0], 10);
         month = parseInt(parts[1], 10);
         month = parseInt(parts[1], 10);
         year = parseInt(parts[2], 10);
         year = parseInt(parts[2], 10);
         break;
         break;
       }
       }
       case 'iso': {
       case 'iso': {
-        // YYYY-MM-DD
-        const parts = value.split('-');
-        if (parts.length !== 3) return null;
+        // YYYY-MM-DD (also accepts . and / separators)
+        const parts = splitDateParts(value);
+        if (!parts) return null;
         year = parseInt(parts[0], 10);
         year = parseInt(parts[0], 10);
         month = parseInt(parts[1], 10);
         month = parseInt(parts[1], 10);
         day = parseInt(parts[2], 10);
         day = parseInt(parts[2], 10);
@@ -134,15 +147,29 @@ export function parseDateInput(value: string, dateFormat: DateFormat = 'system')
       }
       }
       case 'system':
       case 'system':
       default: {
       default: {
-        // Try common formats
-        const date = new Date(value);
-        if (!isNaN(date.getTime())) return date;
-        // Try EU format
-        const euParts = value.split('/');
-        if (euParts.length === 3) {
-          day = parseInt(euParts[0], 10);
-          month = parseInt(euParts[1], 10);
-          year = parseInt(euParts[2], 10);
+        // Detect system format and parse accordingly
+        const testDate = new Date(2000, 11, 31); // Dec 31, 2000
+        const formatted = testDate.toLocaleDateString();
+        const parts = splitDateParts(value);
+
+        if (parts) {
+          // Detect format from system locale
+          if (formatted.startsWith('12')) {
+            // US format: MM/DD/YYYY
+            month = parseInt(parts[0], 10);
+            day = parseInt(parts[1], 10);
+            year = parseInt(parts[2], 10);
+          } else if (formatted.startsWith('31')) {
+            // EU format: DD/MM/YYYY
+            day = parseInt(parts[0], 10);
+            month = parseInt(parts[1], 10);
+            year = parseInt(parts[2], 10);
+          } else {
+            // ISO format: YYYY-MM-DD
+            year = parseInt(parts[0], 10);
+            month = parseInt(parts[1], 10);
+            day = parseInt(parts[2], 10);
+          }
           break;
           break;
         }
         }
         return null;
         return null;

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-Dc108DF_.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
 
     <!-- Splash screens for iOS -->
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-zgloQdA_.js"></script>
+    <script type="module" crossorigin src="/assets/index-Dc108DF_.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-CosC5iN4.css">
     <link rel="stylesheet" crossorigin href="/assets/index-CosC5iN4.css">
   </head>
   </head>
   <body>
   <body>

Некоторые файлы не были показаны из-за большого количества измененных файлов