Add attend_start/attend_end fields for partial conference attendance.

Allows recording when you arrive late or leave early at a multi-day
conference. Both fields accept a plain date or datetime with time.
Trip pages display the attendance dates instead of the official
conference dates when these fields are set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Edward Betts 2026-02-18 18:14:27 +00:00
parent 2edfb40e66
commit 49e5a3000e
4 changed files with 17 additions and 3 deletions

View file

@ -31,6 +31,17 @@ This is a personal agenda web application built with Flask that tracks various e
- Only commit relevant project files
- Personal data directory (`personal-data/`) is excluded from git
## Conference attendance fields
Conferences in `conferences.yaml` support optional `attend_start` and `attend_end` fields for when you arrive late or leave early. Both accept a plain date or a datetime with time and timezone (YAML datetime syntax). When present, the trip page shows the attendance dates instead of the official conference dates. The official `start`/`end` fields are always kept for context.
```yaml
- name: FOSDEM
start: 2023-02-04
end: 2023-02-05
attend_end: 2023-02-04 # left after day 1
attend_start: 2023-02-04 14:00:00+00:00 # or with time
```
## Notes
- Trip stats new-country badges come from `agenda.stats.calculate_yearly_stats` via `year_stats.new_countries` (first-visit year, excluding `PREVIOUSLY_VISITED`).
- Trip stats are calculated in `agenda/stats.py`:

View file

@ -36,6 +36,8 @@ class Conference:
currency: str | None = None
latitude: float | None = None
longitude: float | None = None
attend_start: date | datetime | None = None
attend_end: date | datetime | None = None
cfp_end: date | None = None
cfp_url: str | None = None
free: bool | None = None

View file

@ -4,6 +4,7 @@
{% endmacro %}
{% macro display_date(dt) %}{{ dt.strftime("%a %-d %b %Y") }}{% endmacro %}
{% macro display_date_no_year(dt) %}{{ dt.strftime("%a %-d %b") }}{% endmacro %}
{% macro display_conf_date_no_year(dt) %}{%- if dt.hour is defined %}{{ dt.strftime("%a %-d %b %H:%M") }}{% else %}{{ dt.strftime("%a %-d %b") }}{% endif %}{% endmacro %}
{% macro format_distance(distance) %}
{{ "{:,.0f} km / {:,.0f} miles".format(distance, distance / 1.60934) }}
@ -363,7 +364,7 @@ https://www.flightradar24.com/data/flights/{{ flight.airline_detail.iata | lower
<h5 class="card-title">
<a href="{{ item.url }}">{{ item.name }}</a>
<small class="text-muted">
{{ display_date_no_year(item.start) }} to {{ display_date_no_year(item.end) }}
{{ display_conf_date_no_year(item.attend_start if item.attend_start else item.start) }} to {{ display_conf_date_no_year(item.attend_end if item.attend_end else item.end) }}
</small>
</h5>
<p class="card-text">

View file

@ -2,7 +2,7 @@
{% block title %}{{ trip.title }} ({{ display_date(trip.start) }}) - Edward Betts{% endblock %}
{% from "macros.html" import trip_link, display_datetime, display_date_no_year, display_date, conference_row, accommodation_row, flight_row, train_row, ferry_row, coach_row, bus_row with context %}
{% from "macros.html" import trip_link, display_datetime, display_date_no_year, display_date, display_conf_date_no_year, conference_row, accommodation_row, flight_row, train_row, ferry_row, coach_row, bus_row with context %}
{% set row = {"flight": flight_row, "train": train_row, "ferry": ferry_row, "coach": coach_row, "bus": bus_row} %}
@ -159,7 +159,7 @@
<h5 class="card-title">
<a href="{{ item.url }}">{{ item.name }}</a>
<small class="text-muted">
{{ display_date_no_year(item.start) }} to {{ display_date_no_year(item.end) }}
{{ display_conf_date_no_year(item.attend_start if item.attend_start else item.start) }} to {{ display_conf_date_no_year(item.attend_end if item.attend_end else item.end) }}
</small>
</h5>
<p class="card-text">