diff --git a/issues/templates/issues/breadcrumbs.html b/issues/templates/issues/breadcrumbs.html
index 48f6143..2fc7dbd 100644
--- a/issues/templates/issues/breadcrumbs.html
+++ b/issues/templates/issues/breadcrumbs.html
@@ -49,8 +49,7 @@
{{ breadcrumb.message }}
- {{ breadcrumb.timestamp }}
- {# {{ breadcrumb.timestamp|date:"G:i T" and milis }} #}
+ {{ breadcrumb.timestamp|timestamp_with_millis }}
|
diff --git a/issues/views.py b/issues/views.py
index 990793a..f3096c1 100644
--- a/issues/views.py
+++ b/issues/views.py
@@ -7,8 +7,6 @@ from django.db.models import Q
from django.utils import timezone
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponseRedirect, HttpResponseNotAllowed
-from django.utils.safestring import mark_safe
-from django.template.defaultfilters import date
from django.urls import reverse
from django.core.exceptions import PermissionDenied
from django.http import Http404
@@ -31,6 +29,7 @@ from events.ua_stuff import get_contexts_enriched_with_ua
from compat.timestamp import format_timestamp
from projects.models import ProjectMembership
from tags.search import search_issues, search_events, search_events_optimized
+from theme.templatetags.issues import timestamp_with_millis
from .models import Issue, IssueQuerysetStateManager, IssueStateManager, TurningPoint, TurningPointKind
from .forms import CommentForm
@@ -555,12 +554,6 @@ def issue_event_breadcrumbs(request, issue, event_pk=None, digest_order=None, na
})
-def _date_with_milis_html(timestamp):
- return mark_safe(
- date(timestamp, "j M G:i:s") + "." +
- '' + date(timestamp, "u")[:3] + '')
-
-
def _first_last(qs_with_digest_order):
# this was once implemented with Min/Max, but just doing 2 queries is (on sqlite at least) much faster.
first = qs_with_digest_order.order_by("digest_order").values_list("digest_order", flat=True).first()
@@ -604,9 +597,9 @@ def issue_event_details(request, issue, event_pk=None, digest_order=None, nav=No
("mechanism", get_path(get_main_exception(parsed_data), "mechanism", "type")),
("issue_id", issue.id),
- ("timestamp", _date_with_milis_html(event.timestamp)),
- ("ingested at", _date_with_milis_html(event.ingested_at)),
- ("digested at", _date_with_milis_html(event.digested_at)),
+ ("timestamp", timestamp_with_millis(event.timestamp)),
+ ("ingested at", timestamp_with_millis(event.ingested_at)),
+ ("digested at", timestamp_with_millis(event.digested_at)),
("digest order", event.digest_order),
("remote_addr", event.remote_addr),
]
diff --git a/theme/templatetags/issues.py b/theme/templatetags/issues.py
index 98e67b1..9f0032a 100644
--- a/theme/templatetags/issues.py
+++ b/theme/templatetags/issues.py
@@ -1,3 +1,4 @@
+from datetime import datetime
import re
from django import template
from pygments import highlight
@@ -5,6 +6,9 @@ from pygments.formatters import HtmlFormatter
from django.utils.html import escape
from django.utils.safestring import mark_safe
+from django.template.defaultfilters import date
+
+from compat.timestamp import parse_timestamp
from bugsink.pygments_extensions import guess_lexer_for_filename, lexer_for_platform
@@ -235,3 +239,31 @@ def format_var(value):
def incomplete(value):
# needed to disinguish between 'has an incomplete' attr (set by us) and 'contains an incomplete key' (event-data)
return hasattr(value, "incomplete")
+
+
+def _date_with_milis_html(timestamp):
+ return mark_safe(
+ '' +
+ date(timestamp, "j M G:i:s") + "." +
+ '' + date(timestamp, "u")[:3] + '')
+
+
+@register.filter
+def timestamp_with_millis(value):
+ """
+ Timestamp formatting with milliseconds; robust for datetime.datetime, as well as the strings/floats/ints that may
+ show up in the event data.
+ """
+ if isinstance(value, datetime):
+ dt = value
+
+ else:
+ try:
+ dt = parse_timestamp(value)
+ except Exception:
+ return value
+
+ if dt is None:
+ return value
+
+ return _date_with_milis_html(dt)