Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting timezone (again) #1892

Closed
tmladek opened this issue Jul 26, 2019 · 2 comments · Fixed by #2502
Closed

Setting timezone (again) #1892

tmladek opened this issue Jul 26, 2019 · 2 comments · Fixed by #2502

Comments

@tmladek
Copy link

tmladek commented Jul 26, 2019

Hello,
Flask-Admin seems to show all timestamp fields as if they were UTC (which is also set in the locale of the server). However, I would like to show the dates in GMT+2, which is the timezone of all users of my app - without having to reconfigure the server it is running on.

I found #1246, which is now closed, referring to #772, which in fact discusses a different issue, and I have to concur with the last poster, that the solution there doesn't work - nothing at all changes in my forms if I override the widgets like described.

I also tried using Flask-BabelEx, setting the locale to 'cs' using @babel.localeselector, which successfully changed the form labels, but not the timezone - and changing the timezone directly, using @babel.timezoneselector, which also had no effect.

Is there a way to set Flask-Admin's timezone?

@chakritp
Copy link

Does anyone have an update or workaround on this?

@ElLorans
Copy link
Contributor

ElLorans commented Jun 4, 2023

Does anyone have an update or workaround on this?

@hmanicka posted a gist 2 years ago, but I would rather let the client do at least the conversion to local time. My approach has 2 advantages: bringing some load to the client rather than the server, and automatically getting the user's timezone. Unfortunately, I am not able to make it work with datepicker. This is not an issue to me, as nowadays browser's UI for datetime-local is excellent.

templates/admin/edit.html

{% extends 'admin/model/edit.html' %}
{% block tail %}
    <script>
        fetch('/set_timezone', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(Intl.DateTimeFormat().resolvedOptions().timeZone)
        })

        function convertToUserLocalTime() {
            const inputs = document.querySelectorAll('input[data-date-format]');
            const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
            inputs.forEach(input => {
                const localizedTime = new Date(input.getAttribute("value") + "Z");
                const formattedDate = `${localizedTime.getFullYear()}-${(localizedTime.getMonth() + 1)
                    .toString()
                    .padStart(2, '0')}-${localizedTime.getDate().toString().padStart(2, '0')}T${localizedTime
                    .getHours()
                    .toString()
                    .padStart(2, '0')}:${localizedTime.getMinutes().toString().padStart(2, '0')}`;
                input.value = formattedDate;
            });
        }

        convertToUserLocalTime();
    </script>
{% endblock %}

routes.py

app.route('/set_timezone', methods=['POST'])
def set_timezone():
    current_user.timezone = request.get_json()

admin.py

class AdminView(ModelView):
    edit_template = 'admin/edit.html'  # localize datetime

    date_args_format = dict(format='%Y-%m-%dT%H:%M')
    date_widget_args_format = {
        'data-date-format': '%Y-%m-%dT%H:%M',
        'data-role': 'none',
        'type': 'datetime-local',
    }

    form_args = dict(
        datefield1=date_args_format,
        datefield2=date_args_format,
    )
    form_widget_args = dict(
        datefield1=date_widget_args_format,
        datefield2=date_widget_args_format,
    )

    def validate_form(self, form, view) -> bool:
        for field in form:
            if field.type == 'DateTimeField':
                if field.data is not None:
                    try:
                        field_data = field.data.replace(tzinfo=ZoneInfo(current_user.timezone))
                        # convert to UTC
                        field.data = field_data.astimezone(ZoneInfo("UTC"))
                    except ZoneInfoNotFoundError as e:
                        current_app.logger.exception(e)
                        flash(current_user.timezone + _(
                            ' is not an accepted timezone. Please use a different timezone.'), 'danger')
                        return False
        return super(view, self).validate_form(form)

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
3 participants