Time/Date: accept different formats for date, YYYY-MM-DD [HH:MM[:SS]], DD-MM-YYYY [HH:MM[:SS]] and DD/MM/YYYY [HH:MM[:SS]], convert it to classic one used by pamhyr, and prevent user when he's using a wrong one

mesh_tab
Dylan Jeannin 2026-08-31 16:58:36 +02:00
parent 6586a7b191
commit 0f1d1b0797
8 changed files with 84 additions and 19 deletions

View File

@ -24,7 +24,7 @@ from datetime import date, time, datetime, timedelta
from tools import ( from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp old_pamhyr_date_to_timestamp, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -97,7 +97,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date(int(v)) value = timestamp_to_old_pamhyr_date(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -24,7 +24,7 @@ from datetime import date, time, datetime, timedelta
from tools import ( from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp old_pamhyr_date_to_timestamp, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -87,7 +87,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date(int(v)) value = timestamp_to_old_pamhyr_date(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -24,7 +24,7 @@ from datetime import date, time, datetime, timedelta
from tools import ( from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp old_pamhyr_date_to_timestamp, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -87,7 +87,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date(int(v)) value = timestamp_to_old_pamhyr_date(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -23,7 +23,7 @@ from datetime import date, time, datetime, timedelta
from tools import ( from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp old_pamhyr_date_to_timestamp, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -76,7 +76,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date(int(v)) value = timestamp_to_old_pamhyr_date(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -24,7 +24,7 @@ from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp, old_pamhyr_date_to_timestamp,
timestamp_to_old_pamhyr_date_adists timestamp_to_old_pamhyr_date_adists, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -90,7 +90,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date_adists(int(v)) value = timestamp_to_old_pamhyr_date_adists(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -19,9 +19,7 @@
import logging import logging
import traceback import traceback
from datetime import datetime from tools import trace, timer, parse_datetime
from tools import trace, timer
from Model.Except import NotImplementedMethodeError from Model.Except import NotImplementedMethodeError
@ -36,8 +34,11 @@ from PyQt5.QtWidgets import (
QFileDialog, QTableView, QAbstractItemView, QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate, QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QStyledItemDelegate, QHeaderView, QComboBox, QStyledItemDelegate, QHeaderView,
QMessageBox,
) )
_translate = QCoreApplication.translate
logger = logging.getLogger() logger = logging.getLogger()
@ -63,9 +64,22 @@ class PamhyrTextDelegate(QStyledItemDelegate):
class PamhyrTableModel(QAbstractTableModel): class PamhyrTableModel(QAbstractTableModel):
def date_to_elapsed_seconds(self, value): def date_to_elapsed_seconds(self, value):
"""Convert an entered date to seconds since the study start date.""" """Convert an entered date to seconds since the study start date."""
entered_date = value try:
if not isinstance(entered_date, datetime): entered_date = parse_datetime(value)
entered_date = datetime.fromisoformat(str(value).strip()) except ValueError as error:
QMessageBox.warning(
self._table_view,
_translate("PamhyrTableModel", "Invalid date/time"),
_translate(
"PamhyrTableModel",
"The entered date/time is invalid.\n"
"Expected formats:\n"
"YYYY-MM-DD [HH:MM[:SS]],\n"
"DD-MM-YYYY [HH:MM[:SS]] or\n"
"DD/MM/YYYY [HH:MM[:SS]]."
)
)
raise error
return (entered_date - self._start_date).total_seconds() return (entered_date - self._start_date).total_seconds()

View File

@ -23,7 +23,7 @@ from datetime import date, time, datetime, timedelta
from tools import ( from tools import (
trace, timer, trace, timer,
timestamp_to_old_pamhyr_date, timestamp_to_old_pamhyr_date,
old_pamhyr_date_to_timestamp old_pamhyr_date_to_timestamp, format_datetime
) )
from View.Tools.PamhyrTable import PamhyrTableModel from View.Tools.PamhyrTable import PamhyrTableModel
@ -77,7 +77,7 @@ class TableModel(PamhyrTableModel):
if self._opt_data == "time": if self._opt_data == "time":
value = timestamp_to_old_pamhyr_date(int(v)) value = timestamp_to_old_pamhyr_date(int(v))
else: else:
value = str( value = format_datetime(
self._start_date + timedelta(seconds=float(v)) self._start_date + timedelta(seconds=float(v))
) )
else: else:

View File

@ -22,7 +22,7 @@ import logging
import sqlite3 import sqlite3
import traceback import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta, timezone
from pathlib import Path from pathlib import Path
from colorama import Fore from colorama import Fore
@ -239,6 +239,57 @@ def timestamp(dt: datetime):
return dt.timestamp() return dt.timestamp()
SUPPORTED_DATETIME_FORMATS = (
"%d-%m-%Y %H:%M:%S.%f",
"%d-%m-%Y %H:%M:%S",
"%d-%m-%Y %H:%M",
"%d-%m-%Y",
"%d/%m/%Y %H:%M:%S.%f",
"%d/%m/%Y %H:%M:%S",
"%d/%m/%Y %H:%M",
"%d/%m/%Y",
"%d-%m-%y %H:%M:%S",
"%d/%m/%y %H:%M:%S",
)
def parse_datetime(value):
"""Parse a supported date representation into a naive UTC datetime."""
if isinstance(value, datetime):
parsed = value
else:
text = str(value).strip()
if text.endswith(("Z", "z")):
text = text[:-1] + "+00:00"
try:
parsed = datetime.fromisoformat(text)
except ValueError as iso_error:
for date_format in SUPPORTED_DATETIME_FORMATS:
try:
parsed = datetime.strptime(text, date_format)
break
except ValueError:
continue
else:
raise ValueError(
f"Unsupported date format: {value!r}. Expected an ISO "
"date/time or one of: "
+ ", ".join(SUPPORTED_DATETIME_FORMATS)
) from iso_error
# If the parsed datetime has timezone information, convert it to UTC and remove the timezone info
if parsed.tzinfo is not None:
parsed = parsed.astimezone(timezone.utc).replace(tzinfo=None)
return parsed
def format_datetime(value):
"""Return a datetime using the canonical application format."""
return parse_datetime(value).strftime("%Y-%m-%d %H:%M:%S")
def date_iso_to_timestamp(date: str): def date_iso_to_timestamp(date: str):
if type(date) is str: if type(date) is str:
return timestamp(datetime.fromisoformat(date)) return timestamp(datetime.fromisoformat(date))