TimeSampleHistogram: handle relative weeks
authorDan White <dan@whiteaudio.com>
Thu, 6 Mar 2025 16:54:17 +0000 (10:54 -0600)
committerDan White <dan@whiteaudio.com>
Thu, 6 Mar 2025 16:54:17 +0000 (10:54 -0600)
TimeSampleHistogram

index 4289a5c219d3936cae8ba120836c297f6ad340a7..794509104f23ba94aa3be90389afe1854e91f6e0 100755 (executable)
@@ -75,18 +75,6 @@ if not args:
 #opt.today = True
 #testing
 
-# these are from
-# http://stackoverflow.com/questions/304256/whats-the-best-way-to-find-the-inverse-of-datetime-isocalendar/1700069#1700069
-def iso_year_start(iso_year):
-    "The gregorian calendar date of the first day of the given ISO year"
-    fourth_jan = dt.date(iso_year, 1, 4)
-    delta = dt.timedelta(fourth_jan.isoweekday()-1)
-    return fourth_jan - delta
-
-def iso_to_gregorian(iso_year, iso_week, iso_day):
-    "Gregorian calendar date for the given ISO year, week and day"
-    year_start = iso_year_start(iso_year)
-    return year_start + dt.timedelta(iso_day-1, 0, 0, 0, 0, 0, iso_week-1)
 
 #
 # Date range filter
@@ -124,31 +112,49 @@ if opt.days > 0:
 elif opt.days < 0:
     startdate = enddate + dt.timedelta(opt.days)
 
-if opt.isoweek:
+
+if args.isoweek:
+    ## Formats accepted:
+    # 3    week 3 of this year
+    # 2025-09  week 3 of 2025
+    # 1..4 range including weeks 1 through 4
+    #
+    ### Nonstandard forms:
+    # 0    (this week)
+    # -1   (last week)
+    # +1   (next week)
+    # -3..-2 range including 3 weeks ago through 2 weeks ago
+
     # any number of periods denote a range of weeks
-    wrange = opt.isoweek.replace('.', ' ').split()
+    wrange = args.isoweek.replace('.', ' ').split()
 
     # may be one or two items
     # if only one list item, then the second needs to be a copy of the first
+    # if there are already two items, then the added third one is unused
     wrange.append(wrange[0])
 
     def wstr_to_date(wstr):
-        *year, week = wstr.split('-')
-
-        if year:
-            year = int(year[0])
+        now_dt = dt.datetime.now()
+        year = now_dt.year
+        # handle relative weeks first
+        if wstr[0] in ('+', '-') or wstr == '0':
+            woffset = int(wstr)
+            x = now_dt + dt.timedelta(weeks=woffset)
+            year, week, _ = x.isocalendar()
         else:
-            year = dt.datetime.now().year
-
-        week = int(week)
+            *year, week = wstr.split('-')
+            week = int(week)
+            if year:  # it was provided
+                year = int(year[0])
+            else:  # only week number provided, assume this year
+                year, *_ = now_dt.isocalendar()
         return (year, week)
 
     year, week = wstr_to_date(wrange[0])
-    startdate = iso_to_gregorian(year, week, 1)
+    startdate = dt.date.fromisocalendar(year, week, 1)
 
     year, week = wstr_to_date(wrange[1])
-    enddate = iso_to_gregorian(year, week, 7)
-
+    enddate = dt.date.fromisocalendar(year, week, 7)
 
 
 # modify to include all of enddate instead of start-of-day