From 5647279e2c3e9e56225d3442ed133149752c1057 Mon Sep 17 00:00:00 2001
From: XANTRONIX Industrial <xan@xantronix.com>
Date: Tue, 1 Apr 2025 12:06:17 -0400
Subject: [PATCH] Add timestamps to SPC outlook maps

---
 bin/xmet-spc-render-file |  4 ++--
 lib/xmet/spc.py          | 41 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/bin/xmet-spc-render-file b/bin/xmet-spc-render-file
index 3aa4595..7b34b04 100755
--- a/bin/xmet-spc-render-file
+++ b/bin/xmet-spc-render-file
@@ -41,7 +41,7 @@ def render_categorical(conus: SPCOutlookMap,
         if args.dark:
             cr.set_source_rgb(1, 1, 1)
 
-        conus.draw_annotation(cr, f"Day {outlook.day} Categorical Severe Weather Outlook")
+        conus.draw_annotation(cr, outlook, SPCOutlookType.CATEGORICAL)
 
 def render_probabilistic(conus: SPCOutlookMap,
                          outlook: SPCOutlook,
@@ -66,7 +66,7 @@ def render_probabilistic(conus: SPCOutlookMap,
 
         hazard = ' '.join(map(lambda p: p.lower().capitalize(), hazard.split(' ')))
 
-        conus.draw_annotation(cr, f"Day {outlook.day} Probabilistic {hazard} Risk")
+        conus.draw_annotation(cr, outlook, SPCOutlookType.PROBABILISTIC, hazard)
 
 argparser = argparse.ArgumentParser(description='Render graphical SPC outlooks from text file')
 argparser.add_argument('db',                          help='Spatialite database file')
diff --git a/lib/xmet/spc.py b/lib/xmet/spc.py
index 4773ba8..fc06afe 100644
--- a/lib/xmet/spc.py
+++ b/lib/xmet/spc.py
@@ -4,6 +4,8 @@ import shapely
 import datetime
 import cairo
 
+from typing import Optional
+
 from xmet.db    import Database, DatabaseTable
 from xmet.coord import COORD_SYSTEM
 from xmet.city  import City
@@ -733,17 +735,50 @@ class SPCOutlookMap(EquirectMap):
 
         cr.restore()
 
-    def draw_annotation(self, cr: cairo.Context, text: str):
+    def draw_annotation(self,
+                        cr: cairo.Context,
+                        outlook: SPCOutlook,
+                        kind: SPCOutlookType,
+                        hazard: Optional[str]=None):
         cr.save()
 
         cr.select_font_face(self.TEXT_FONT)
         cr.set_font_size(28)
 
+        if kind is SPCOutlookType.CATEGORICAL:
+            text = f"Day {outlook.day} Categorical Severe Weather Outlook"
+        elif kind is SPCOutlookType.PROBABILISTIC:
+            text = f"Day {outlook.day} Probabilistic {hazard} Risk"
+
         extents = cr.text_extents(text)
 
-        cr.move_to(self.width  - extents.width  - 48,
-                   self.height - extents.height - 16)
+        x = self.width  - extents.width - 48
+        y = self.height - extents.height - 16
 
+        cr.move_to(x, y)
+        cr.show_text(text)
+
+        #
+        # Draw timestamp
+        #
+        cr.set_font_size(14)
+
+        text = "Issued %s; valid %s" % (
+            outlook.timestamp_issued.strftime("%Y-%m-%d %H:%M UTC"),
+            outlook.timestamp_start.strftime("%Y-%m-%d %H:%M UTC"),
+        )
+
+        extents = cr.text_extents(text)
+
+        x = self.width - extents.width - 32
+        y = 8 + extents.height
+
+        cr.set_source_rgba(1, 1, 1, 0.9)
+        cr.rectangle(x - 4, y - 4, extents.width + 8, extents.height + 8)
+        cr.fill()
+
+        cr.set_source_rgb(0, 0, 0)
+        cr.move_to(x, y + extents.height)
         cr.show_text(text)
 
         cr.restore()