aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/__init__.py1
-rw-r--r--fietsboek/jinja2.py40
-rw-r--r--fietsboek/static/fietsboek.js8
-rw-r--r--fietsboek/templates/details.jinja22
-rw-r--r--fietsboek/templates/layout.jinja23
5 files changed, 52 insertions, 2 deletions
diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py
index 4a28dd4..9de9cbd 100644
--- a/fietsboek/__init__.py
+++ b/fietsboek/__init__.py
@@ -67,5 +67,6 @@ def main(global_config, **settings):
jinja2_env = config.get_jinja2_environment()
jinja2_env.filters['format_decimal'] = fiets_jinja2.filter_format_decimal
jinja2_env.filters['format_datetime'] = fiets_jinja2.filter_format_datetime
+ jinja2_env.filters['local_datetime'] = fiets_jinja2.filter_local_datetime
return config.make_wsgi_app()
diff --git a/fietsboek/jinja2.py b/fietsboek/jinja2.py
index def61a6..6043791 100644
--- a/fietsboek/jinja2.py
+++ b/fietsboek/jinja2.py
@@ -1,5 +1,8 @@
"""Custom filters for Jinja2."""
+import datetime
+
import jinja2
+from markupsafe import Markup
from babel.numbers import format_decimal
from babel.dates import format_datetime
@@ -37,3 +40,40 @@ def filter_format_datetime(ctx, value):
request = ctx.get('request')
locale = request.localizer.locale_name
return format_datetime(value, locale=locale)
+
+
+@jinja2.pass_context
+def filter_local_datetime(ctx, value):
+ """Format a UTC datetime to show in the user's local timezone.
+
+ This is done by embedding the UTC timestamp in the page, such that we can
+ do some client-side magic and replace it with the time in the user's local
+ timezone. As a fallback value, we do apply the locale's standard
+ formatting, in case JavaScript is disabled - however, that will not
+ represent the time in the user's timezone, but in UTC.
+
+ :param ctx: The jinja context, passed automatically.
+ :type ctx: jinja2.runtime.Context
+ :param value: The value to format.
+ :type value: datetime.datetime
+ :return: The formatted date.
+ :rtype: Markup
+ """
+ # If we get a naive object in, we assume that we got it from the database
+ # and we have to treat it like a UTC-aware object. This happens when we
+ # access object's DateTime columns directly, as SQLAlchemy only returns
+ # naive datetimes.
+ if value.tzinfo is None:
+ value = value.replace(tzinfo=datetime.timezone.utc)
+ else:
+ value = value.astimezone(datetime.timezone.utc)
+
+ request = ctx.get('request')
+ locale = request.localizer.locale_name
+ fallback = Markup.escape(format_datetime(value, locale=locale))
+
+ # Forget about the fractional seconds
+ timestamp = int(value.timestamp())
+ return Markup(
+ f'<span class="fietsboek-local-datetime" data-utc-timestamp="{timestamp}">{fallback}</span>'
+ )
diff --git a/fietsboek/static/fietsboek.js b/fietsboek/static/fietsboek.js
index d27e21e..515f45e 100644
--- a/fietsboek/static/fietsboek.js
+++ b/fietsboek/static/fietsboek.js
@@ -150,4 +150,12 @@ document.addEventListener('DOMContentLoaded', function(event) {
$("#archiveDownloadButton").disabled = (checked.length == 0);
});
});
+
+ /* Format all datetimes to the local timezone */
+ document.querySelectorAll(".fietsboek-local-datetime").forEach((obj) => {
+ let timestamp = obj.attributes["data-utc-timestamp"].value;
+ let date = new Date(timestamp * 1000);
+ let intl = new Intl.DateTimeFormat(LOCALE, {dateStyle: "medium", timeStyle: "medium"});
+ obj.innerHTML = intl.format(date);
+ });
});
diff --git a/fietsboek/templates/details.jinja2 b/fietsboek/templates/details.jinja2
index 4d88224..e22efbc 100644
--- a/fietsboek/templates/details.jinja2
+++ b/fietsboek/templates/details.jinja2
@@ -150,7 +150,7 @@
{{ comment_md_to_html(comment.text) }}
</div>
<div class="card-footer text-muted">
- {{ comment.date | format_datetime }}
+ {{ comment.date | local_datetime }}
</div>
</div>
{% endfor %}
diff --git a/fietsboek/templates/layout.jinja2 b/fietsboek/templates/layout.jinja2
index a03b7c1..83a8f33 100644
--- a/fietsboek/templates/layout.jinja2
+++ b/fietsboek/templates/layout.jinja2
@@ -19,7 +19,8 @@
<link href="{{request.static_url('fietsboek:static/theme.css')}}" rel="stylesheet">
<script>
-var FRIENDS_URL = "{{ request.route_url('json-friends') }}";
+const FRIENDS_URL = "{{ request.route_url('json-friends') }}";
+const LOCALE = "{{ request.localizer.locale_name.replace('_', '-') }}";
</script>
</head>