diff --git a/mathesar/api/display_options.py b/mathesar/api/display_options.py index 89d22498da..a4a4f63bdf 100644 --- a/mathesar/api/display_options.py +++ b/mathesar/api/display_options.py @@ -16,6 +16,10 @@ {"name": "locale", "type": "string"}] }, MathesarTypeIdentifier.DATETIME.value: + { + "options": [{"name": "format", "type": "string"}] + }, + MathesarTypeIdentifier.DURATION.value: { "options": [{"name": "format", "type": "string"}] } diff --git a/mathesar/api/serializers/shared_serializers.py b/mathesar/api/serializers/shared_serializers.py index f05c369a13..dfc828bf9e 100644 --- a/mathesar/api/serializers/shared_serializers.py +++ b/mathesar/api/serializers/shared_serializers.py @@ -165,7 +165,7 @@ def validate(self, datetime_obj, display_format, serializer_field): class TimeWithTimeZoneFormatValidator(AbstractDateTimeFormatValidator): def validate(self, datetime_obj, display_format, serializer_field): - time_only_format = 'HH:mm:ssZZ' + time_only_format = 'HH:mm:ss.SSSZZ' time_str = arrow.get('2013-09-30T15:34:00.000-07:00').format(time_only_format) parsed_time_str = arrow.get(time_str, time_only_format) if parsed_time_str.date() != datetime_obj.date(): @@ -180,6 +180,15 @@ def validate(self, datetime_obj, display_format, serializer_field): return super().validate(datetime_obj, display_format, serializer_field) +class DurationFormatValidator(AbstractDateTimeFormatValidator): + + def validate(self, datetime_obj, display_format, serializer_field): + if 'z' in display_format.lower(): + raise serializers.ValidationError( + "Duration column cannot contain timezone display format" + ) + + class DateDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer): format = serializers.CharField(validators=[DateFormatValidator()]) @@ -216,6 +225,10 @@ class TimeWithoutTimezoneDisplayOptionSerializer( format = serializers.CharField(validators=[TimeWithoutTimeZoneFormatValidator()]) +class DurationDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer): + format = serializers.CharField(validators=[DurationFormatValidator()]) + + class DisplayOptionsMappingSerializer( MathesarErrorMessageMixin, ReadWritePolymorphicSerializerMappingMixin, @@ -231,6 +244,7 @@ class DisplayOptionsMappingSerializer( ('date', MathesarTypeIdentifier.DATETIME.value): DateDisplayOptionSerializer, ('time with time zone', MathesarTypeIdentifier.DATETIME.value): TimeWithTimezoneDisplayOptionSerializer, ('time without time zone', MathesarTypeIdentifier.DATETIME.value): TimeWithoutTimezoneDisplayOptionSerializer, + MathesarTypeIdentifier.DURATION.value: DurationDisplayOptionSerializer, } def get_mapping_field(self): diff --git a/mathesar/tests/api/test_column_api.py b/mathesar/tests/api/test_column_api.py index d99e0dd2b2..5f9bcc2755 100644 --- a/mathesar/tests/api/test_column_api.py +++ b/mathesar/tests/api/test_column_api.py @@ -238,6 +238,7 @@ def test_column_create_invalid_default(column_test_table, client): ("BOOLEAN", {"input": "dropdown"}), ("BOOLEAN", {"input": "checkbox", "custom_labels": {"TRUE": "yes", "FALSE": "no"}}), ("DATE", {'format': 'YYYY-MM-DD'}), + ("INTERVAL", {'format': 'DD HH:mm:ss.SSS'}), ("NUMERIC", {"show_as_percentage": True}), ("NUMERIC", {"show_as_percentage": True, "locale": "en_US"}), ("TIMESTAMP WITH TIME ZONE", {'format': 'YYYY-MM-DD hh:mm'}),