session-slides 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "session-slides",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Convert Claude Code session transcripts into navigable HTML slide presentations",
5
5
  "keywords": [
6
6
  "claude",
@@ -1056,6 +1056,8 @@ def _format_datetime(dt_string: str) -> tuple:
1056
1056
  """
1057
1057
  Parse and format a datetime string into readable date and time components.
1058
1058
 
1059
+ Converts UTC timestamps to the local timezone before formatting.
1060
+
1059
1061
  Args:
1060
1062
  dt_string: ISO format datetime string or similar
1061
1063
 
@@ -1065,32 +1067,33 @@ def _format_datetime(dt_string: str) -> tuple:
1065
1067
  if not dt_string:
1066
1068
  return None, None
1067
1069
 
1068
- # Handle timezone offset by stripping it (e.g., +00:00)
1069
- clean_dt = re.sub(r'[+-]\d{2}:\d{2}$', '', dt_string)
1070
-
1071
- # Try various datetime formats
1072
- formats = [
1073
- '%Y-%m-%dT%H:%M:%S.%fZ',
1074
- '%Y-%m-%dT%H:%M:%SZ',
1075
- '%Y-%m-%dT%H:%M:%S.%f',
1076
- '%Y-%m-%dT%H:%M:%S',
1077
- '%Y-%m-%d %H:%M:%S.%f',
1078
- '%Y-%m-%d %H:%M:%S',
1079
- '%Y-%m-%d',
1080
- ]
1081
-
1070
+ # Try Python's fromisoformat first (handles +00:00, Z, microseconds)
1082
1071
  dt = None
1083
- for fmt in formats:
1084
- try:
1085
- dt = datetime.strptime(clean_dt, fmt)
1086
- break
1087
- except ValueError:
1088
- continue
1072
+ try:
1073
+ dt = datetime.fromisoformat(dt_string.replace('Z', '+00:00'))
1074
+ except (ValueError, AttributeError):
1075
+ # Fall back to manual parsing for non-standard formats
1076
+ clean_dt = re.sub(r'[+-]\d{2}:\d{2}$', '', dt_string)
1077
+ for fmt in [
1078
+ '%Y-%m-%dT%H:%M:%S.%f',
1079
+ '%Y-%m-%dT%H:%M:%S',
1080
+ '%Y-%m-%d %H:%M:%S.%f',
1081
+ '%Y-%m-%d %H:%M:%S',
1082
+ '%Y-%m-%d',
1083
+ ]:
1084
+ try:
1085
+ dt = datetime.strptime(clean_dt, fmt)
1086
+ break
1087
+ except ValueError:
1088
+ continue
1089
1089
 
1090
1090
  if dt is None:
1091
- # Return the raw string if we can't parse it
1092
1091
  return dt_string, None
1093
1092
 
1093
+ # Convert to local timezone if the datetime is timezone-aware
1094
+ if dt.tzinfo is not None:
1095
+ dt = dt.astimezone()
1096
+
1094
1097
  # Format nicely: "February 4, 2026" and "2:30 PM"
1095
1098
  date_str = dt.strftime('%B %d, %Y').replace(' 0', ' ') # Remove leading zero from day
1096
1099
  time_str = dt.strftime('%I:%M %p').lstrip('0') # Remove leading zero from hour
@@ -1120,28 +1123,18 @@ def _calculate_duration(turns: list) -> str:
1120
1123
  if len(timestamps) < 2:
1121
1124
  return None
1122
1125
 
1123
- # Strip timezone offsets before parsing (e.g., +00:00)
1124
- first_ts = re.sub(r'[+-]\d{2}:\d{2}$', '', timestamps[0])
1125
- last_ts = re.sub(r'[+-]\d{2}:\d{2}$', '', timestamps[-1])
1126
-
1127
- # Try to parse first and last timestamps
1128
- formats = [
1129
- '%Y-%m-%dT%H:%M:%S.%fZ',
1130
- '%Y-%m-%dT%H:%M:%SZ',
1131
- '%Y-%m-%dT%H:%M:%S.%f',
1132
- '%Y-%m-%dT%H:%M:%S',
1133
- ]
1134
-
1126
+ # Parse first and last timestamps
1135
1127
  first_dt = None
1136
1128
  last_dt = None
1137
-
1138
- for fmt in formats:
1129
+ for ts_str, target in [(timestamps[0], 'first'), (timestamps[-1], 'last')]:
1139
1130
  try:
1140
- first_dt = datetime.strptime(first_ts, fmt)
1141
- last_dt = datetime.strptime(last_ts, fmt)
1142
- break
1143
- except ValueError:
1144
- continue
1131
+ dt = datetime.fromisoformat(ts_str.replace('Z', '+00:00'))
1132
+ except (ValueError, AttributeError):
1133
+ dt = None
1134
+ if target == 'first':
1135
+ first_dt = dt
1136
+ else:
1137
+ last_dt = dt
1145
1138
 
1146
1139
  if first_dt is None or last_dt is None:
1147
1140
  return None