From f770614c4e842b7095256e77b53a5a8381634512 Mon Sep 17 00:00:00 2001
From: JCC1998 <57444325+JCC1998@users.noreply.github.com>
Date: Sun, 4 May 2025 19:46:26 +0200
Subject: [PATCH] feat: add date_format and hour_format settings (#904)
* feat: add date_format and hour_format settings
* fix: fix ruff validation errors
* fix: use ruff format command
* fix: Refactor code and improve some logic
* fix: remove unused import
* Added zero padding setting and implement some comments
* Add test assert property
* fix: Unclutter selector and clarify zero-padding literal
* fix: Use static strings
Co-authored-by: Tony <1414927+zfbx@users.noreply.github.com>
---------
Co-authored-by: Tony <1414927+zfbx@users.noreply.github.com>
---
src/tagstudio/core/global_settings.py | 3 ++
src/tagstudio/qt/modals/settings_panel.py | 46 +++++++++++++++++++
.../qt/widgets/preview/file_attributes.py | 22 ++++++++-
src/tagstudio/resources/translations/en.json | 6 +++
src/tagstudio/resources/translations/es.json | 6 +++
tests/qt/test_global_settings.py | 6 +++
6 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/src/tagstudio/core/global_settings.py b/src/tagstudio/core/global_settings.py
index 70b4144c..a2e1b1c2 100644
--- a/src/tagstudio/core/global_settings.py
+++ b/src/tagstudio/core/global_settings.py
@@ -49,6 +49,9 @@ class GlobalSettings(BaseModel):
page_size: int = Field(default=100)
show_filepath: ShowFilepathOption = Field(default=ShowFilepathOption.DEFAULT)
theme: Theme = Field(default=Theme.SYSTEM)
+ date_format: str = Field(default="%x")
+ hour_format: bool = Field(default=True)
+ zero_padding: bool = Field(default=True)
@staticmethod
def read_settings(path: Path = DEFAULT_GLOBAL_SETTINGS_PATH) -> "GlobalSettings":
diff --git a/src/tagstudio/qt/modals/settings_panel.py b/src/tagstudio/qt/modals/settings_panel.py
index 905c65d8..e7ec82c8 100644
--- a/src/tagstudio/qt/modals/settings_panel.py
+++ b/src/tagstudio/qt/modals/settings_panel.py
@@ -3,6 +3,7 @@
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
+from datetime import datetime as dt
from typing import TYPE_CHECKING
from PySide6.QtCore import Qt
@@ -37,6 +38,24 @@ THEME_MAP: dict[Theme, str] = {
Theme.SYSTEM: Translations["settings.theme.system"],
}
+DATE_FORMAT_MAP: dict[str, str] = {
+ "%d/%m/%y": "21/08/24",
+ "%d/%m/%Y": "21/08/2024",
+ "%d.%m.%y": "21.08.24",
+ "%d.%m.%Y": "21.08.2024",
+ "%d-%m-%y": "21-08-24",
+ "%d-%m-%Y": "21-08-2024",
+ "%x": "08/21/24",
+ "%m/%d/%Y": "08/21/2024",
+ "%m-%d-%y": "08-21-24",
+ "%m-%d-%Y": "08-21-2024",
+ "%m.%d.%y": "08.21.24",
+ "%m.%d.%Y": "08.21.2024",
+ "%Y/%m/%d": "2024/08/21",
+ "%Y-%m-%d": "2024-08-21",
+ "%Y.%m.%d": "2024.08.21",
+}
+
class SettingsPanel(PanelWidget):
driver: "QtDriver"
@@ -147,6 +166,27 @@ class SettingsPanel(PanelWidget):
self.theme_combobox.currentIndexChanged.connect(self.__update_restart_label)
form_layout.addRow(Translations["settings.theme.label"], self.theme_combobox)
+ # Date Format
+ self.dateformat_combobox = QComboBox()
+ for k in DATE_FORMAT_MAP:
+ self.dateformat_combobox.addItem(DATE_FORMAT_MAP[k], k)
+ dateformat: str = self.driver.settings.date_format
+ if dateformat not in DATE_FORMAT_MAP:
+ dateformat = "%x"
+ self.dateformat_combobox.setCurrentIndex(list(DATE_FORMAT_MAP.keys()).index(dateformat))
+ self.dateformat_combobox.currentIndexChanged.connect(self.__update_restart_label)
+ form_layout.addRow(Translations["settings.dateformat.label"], self.dateformat_combobox)
+
+ # 24-Hour Format
+ self.hourformat_checkbox = QCheckBox()
+ self.hourformat_checkbox.setChecked(self.driver.settings.hour_format)
+ form_layout.addRow(Translations["settings.hourformat.label"], self.hourformat_checkbox)
+
+ # Zero-padding
+ self.zeropadding_checkbox = QCheckBox()
+ self.zeropadding_checkbox.setChecked(self.driver.settings.zero_padding)
+ form_layout.addRow(Translations["settings.zeropadding.label"], self.zeropadding_checkbox)
+
def __build_library_settings(self):
self.library_settings_container = QWidget()
form_layout = QFormLayout(self.library_settings_container)
@@ -167,6 +207,9 @@ class SettingsPanel(PanelWidget):
"page_size": int(self.page_size_line_edit.text()),
"show_filepath": self.filepath_combobox.currentData(),
"theme": self.theme_combobox.currentData(),
+ "date_format": self.dateformat_combobox.currentData(),
+ "hour_format": self.hourformat_checkbox.isChecked(),
+ "zero_padding": self.zeropadding_checkbox.isChecked(),
}
def update_settings(self, driver: "QtDriver"):
@@ -179,6 +222,9 @@ class SettingsPanel(PanelWidget):
driver.settings.page_size = settings["page_size"]
driver.settings.show_filepath = settings["show_filepath"]
driver.settings.theme = settings["theme"]
+ driver.settings.date_format = settings["date_format"]
+ driver.settings.hour_format = settings["hour_format"]
+ driver.settings.zero_padding = settings["zero_padding"]
driver.settings.save()
diff --git a/src/tagstudio/qt/widgets/preview/file_attributes.py b/src/tagstudio/qt/widgets/preview/file_attributes.py
index d894af18..49098d5f 100644
--- a/src/tagstudio/qt/widgets/preview/file_attributes.py
+++ b/src/tagstudio/qt/widgets/preview/file_attributes.py
@@ -109,11 +109,11 @@ class FileAttributes(QWidget):
created = dt.fromtimestamp(filepath.stat().st_ctime)
modified: dt = dt.fromtimestamp(filepath.stat().st_mtime)
self.date_created_label.setText(
- f"{Translations['file.date_created']}: {dt.strftime(created, '%a, %x, %X')}"
+ f"{Translations['file.date_created']}: {self.get_date_with_format(created)}"
)
self.date_modified_label.setText(
f"{Translations['file.date_modified']}: "
- f"{dt.strftime(modified, '%a, %x, %X')}"
+ f"{self.get_date_with_format(modified)}"
)
self.date_created_label.setHidden(False)
self.date_modified_label.setHidden(False)
@@ -246,3 +246,21 @@ class FileAttributes(QWidget):
self.file_label.set_file_path("")
self.dimensions_label.setText("")
self.dimensions_label.setHidden(True)
+
+ def get_date_with_format(self, date: dt) -> str:
+ date_format = self.driver.settings.date_format
+ is_24h = self.driver.settings.hour_format
+ hour_format = "%H:%M:%S" if is_24h else "%I:%M:%S %p"
+ zero_padding = self.driver.settings.zero_padding
+ zero_padding_symbol = ""
+
+ if not zero_padding:
+ zero_padding_symbol = "#" if platform.system() == "Windows" else "-"
+ date_format = date_format.replace("%d", f"%{zero_padding_symbol}d").replace(
+ "%m", f"%{zero_padding_symbol}m"
+ )
+ hour_format = hour_format.replace("%H", f"%{zero_padding_symbol}H").replace(
+ "%I", f"%{zero_padding_symbol}I"
+ )
+
+ return dt.strftime(date, f"{date_format}, {hour_format}")
diff --git a/src/tagstudio/resources/translations/en.json b/src/tagstudio/resources/translations/en.json
index 2d0b029b..281f69c7 100644
--- a/src/tagstudio/resources/translations/en.json
+++ b/src/tagstudio/resources/translations/en.json
@@ -247,6 +247,12 @@
"settings.theme.label": "Theme:",
"settings.theme.light": "Light",
"settings.theme.system": "System",
+ "settings.dateformat.label": "Date Format",
+ "settings.dateformat.system": "System",
+ "settings.dateformat.english": "English",
+ "settings.dateformat.international": "International",
+ "settings.hourformat.label": "24-Hour Time",
+ "settings.zeropadding.label": "Date Zero-Padding",
"settings.title": "Settings",
"sorting.direction.ascending": "Ascending",
"sorting.direction.descending": "Descending",
diff --git a/src/tagstudio/resources/translations/es.json b/src/tagstudio/resources/translations/es.json
index 7eccc3c0..aa1fc05e 100644
--- a/src/tagstudio/resources/translations/es.json
+++ b/src/tagstudio/resources/translations/es.json
@@ -236,6 +236,12 @@
"settings.restart_required": "Por favor, reinicia TagStudio para que se los cambios surtan efecto.",
"settings.show_filenames_in_grid": "Mostrar el nombre de archivo en la cuadrícula",
"settings.show_recent_libraries": "Mostrar bibliotecas recientes",
+ "settings.dateformat.label": "Formato fecha",
+ "settings.dateformat.system": "Sistema",
+ "settings.dateformat.english": "Inglés",
+ "settings.dateformat.international": "Internacional",
+ "settings.hourformat.label": "Formato 24-horas",
+ "settings.zeropadding.label": "Rellenar ceros en fechas",
"settings.title": "Ajustes",
"sorting.direction.ascending": "Ascendiente",
"sorting.direction.descending": "Descendiente",
diff --git a/tests/qt/test_global_settings.py b/tests/qt/test_global_settings.py
index 21953e96..25d78086 100644
--- a/tests/qt/test_global_settings.py
+++ b/tests/qt/test_global_settings.py
@@ -16,6 +16,9 @@ def test_read_settings():
page_size = 1337
show_filepath = 0
dark_mode = 2
+ date_format = "%x"
+ hour_format = true
+ zero_padding = true
""")
settings = GlobalSettings.read_settings(settings_path)
@@ -26,3 +29,6 @@ def test_read_settings():
assert settings.page_size == 1337
assert settings.show_filepath == 0
assert settings.theme == Theme.SYSTEM
+ assert settings.date_format == "%x"
+ assert settings.hour_format
+ assert settings.zero_padding