Export your calendar as an ICS or CSV file, calculate each event’s duration, assign events to clients and projects, then import into your time tracking tool. Most developers can backfill a complete timesheet from calendar data in under 20 minutes.
Your timesheet is overdue and your memory is blank. But your calendar tells the story — every standup, client call, sprint review, and pairing session is right there with exact start and end times. Unlike recollection, calendar events carry precise timestamps: when the meeting started, when it ended, and who was in the room. With the right export and categorisation workflow, you can convert those events into billable time entries without guessing.
This guide walks through every step: exporting from Google Calendar, Outlook, and Apple Calendar; parsing events into time entries; categorising them by client and project; and automating the process so backfilling becomes a rare exception rather than a weekly scramble.
How to Export Calendar Events for Timesheet Data
Google Calendar
Open Google Calendar, go to Settings → Import & Export → Export. Google downloads an ICS archive containing all your calendars. To target a specific period, use the Google Calendar API with timeMin and timeMax parameters — this returns events as JSON, which is easier to script than parsing ICS manually.
Each exported event includes: SUMMARY (title), DTSTART (start time), DTEND (end time), DESCRIPTION, and ATTENDEE fields. That is enough to reconstruct a full meeting log.
Outlook / Microsoft 365
In Outlook on the web, select the calendar view, choose Settings → View all Outlook settings → Calendar → Shared calendars, then use Publish a calendar for ICS export. Alternatively, export directly from the Outlook desktop client via File → Open & Export → Import/Export → Export to a File → Comma Separated Values. The CSV output is immediately spreadsheet-friendly.
For programmatic access, the Microsoft Graph API endpoint GET /me/calendarView accepts startDateTime and endDateTime query parameters and returns structured JSON.
Apple Calendar
Right-click any calendar in the sidebar and choose Export → Export… to download an ICS file. For recurring access without manual export, enable CalDAV and read the feed programmatically using any ICS-compatible library.
What the export contains
Regardless of platform, every export gives you the fields that matter for timesheets: event title, start time, end time, computed duration, description, and attendee list. Filter by date range before exporting to limit the file to the backfill period you need.
How to Parse Calendar Events into Time Entries
Once you have the export, the conversion follows six steps.
Step 1 — Open the file. ICS files are plain text and can be opened in any text editor. CSV files open directly in a spreadsheet. For scripting, import the file into Python or Node.
Step 2 — Calculate duration. Subtract start time from end time for each event. Most calendar events are already formatted with clean ISO 8601 timestamps, so duration arithmetic is straightforward.
Step 3 — Assign to client or project. Match each event to a client based on the event title, the calendar it belongs to, or keywords in the description. A standing client call named “[Acme] Weekly Sync” maps immediately.
Step 4 — Mark as billable or non-billable. Client-facing meetings are typically billable; internal standups, team socials, and admin reviews are not. Apply the rule mechanically first, then spot-check.
Step 5 — Handle recurring events. Recurring standups and weeklies create multiple entries automatically. Verify each one actually occurred — a recurring event in your calendar does not mean you attended every instance.
Step 6 — Remove cancelled events. ICS exports include cancelled meetings with a STATUS:CANCELLED property. Filter those out before calculating totals. Some platforms do not update the status field when a meeting is declined; cross-reference with your sent-items or notes if accuracy is critical.
A minimal Python parser
from icalendar import Calendar
from datetime import datetime
def parse_calendar(ics_path):
with open(ics_path, 'rb') as f:
cal = Calendar.from_ical(f.read())
entries = []
for component in cal.walk():
if component.name != 'VEVENT':
continue
if str(component.get('STATUS', '')).upper() == 'CANCELLED':
continue
summary = str(component.get('SUMMARY', 'Unknown'))
start = component.get('DTSTART').dt
end = component.get('DTEND').dt
# Normalise to datetime if date-only
if not isinstance(start, datetime):
continue
duration_minutes = (end - start).seconds // 60
entries.append({
'title': summary,
'start': start.isoformat(),
'duration_minutes': duration_minutes,
})
return entries
Install the dependency with pip install icalendar. The output list feeds directly into a CSV writer or your time tracking tool’s API.
Categorisation Strategies for Calendar Events
Categorisation accuracy determines whether your backfilled timesheet is billable-accurate or just meeting-accurate. Four approaches work well in practice.
Separate calendars per client. If you already maintain one calendar for each client (e.g. “Client A”, “Client B”, “Internal”), the calendar name tells you the project automatically. This is the lowest-friction approach and works with any export format.
Event title conventions. Prefix meeting titles with a short client code: [ACME] Sprint Review, [BETA] Onboarding Call. A simple startswith check in a script assigns the entry without ambiguity. Establish this convention before you need it; retrofitting titles is the awkward part.
Colour coding. Calendar colours are stored in the ICS X-APPLE-CALENDAR-COLOR or equivalent vendor extension fields. Parsing them is platform-specific, but if you colour-code calendars by client already, it is a clean signal for categorisation scripts.
Attendee domain filtering. Events where all attendees share your company’s email domain are almost certainly internal. Events with external domain attendees are likely client-facing and billable. This heuristic works well for consulting and agency work where client communication happens through calendar invites.
After automatic categorisation, run a one-minute visual scan of the output. Look for prep sessions, travel time, and async review work that the calendar captured but that requires manual billing decisions.
Automation Scripts for Calendar-to-Timesheet Conversion
For one-off backfilling, a manual export and the Python parser above is sufficient. For ongoing use, automation removes the manual step entirely.
Google Apps Script
Google Apps Script can read your calendar programmatically and write entries directly to a Google Sheet for review:
function exportCalendarToSheet() {
const start = new Date('2026-04-14');
const end = new Date('2026-04-25');
const calendar = CalendarApp.getDefaultCalendar();
const events = calendar.getEvents(start, end);
const sheet = SpreadsheetApp.getActiveSheet();
events.forEach(event => {
const durationMinutes = (event.getEndTime() - event.getStartTime()) / 60000;
sheet.appendRow([
event.getTitle(),
event.getStartTime().toISOString(),
durationMinutes,
'' // client — fill manually or add lookup logic
]);
});
}
Attach this to a time-driven trigger to run nightly and you have a continuously updated meeting log without any manual export step.
Microsoft Power Automate
Create a scheduled cloud flow with the Get events action pointed at your Outlook calendar. Connect the output to a Create item action in SharePoint or an HTTP action to your time tracking tool’s API. No code required beyond setting up the connector and field mappings.
Direct API sync
If your time tracking tool exposes an API, connect it to your calendar API directly. The pattern is: authenticate both APIs, pull calendar events at a scheduled interval, transform the event format to match the time entry schema, and POST each entry. This approach eliminates the CSV/ICS intermediary and keeps your timesheet current within minutes of each meeting ending.
How to Prevent the Need for Backfilling
Backfilling is a recovery operation. The better long-term investment is eliminating the gap that requires it.
Real-time calendar integration. Many time tracking tools support direct calendar connections. When a meeting ends, the tool automatically creates a time entry with the correct duration. Review and categorise once at the end of the day rather than reconstructing at the end of the month.
Daily two-minute review. At the end of each working day, open your time tracker and verify that the day’s calendar events were captured. Adjusting one day while the context is fresh takes two minutes. Reconstructing three weeks from scratch takes an afternoon.
Combined git and calendar tracking. Calendar events capture meeting time. Git commits capture coding time. Together they cover the majority of a developer’s billable day automatically. See how to reconstruct a timesheet from git logs for the coding-time side of this approach.
Consistent naming conventions. Even if you backfill manually, event titles that include client codes and project names dramatically speed up the process. Five seconds of discipline when creating a calendar invite saves five minutes when processing it later.
If occasional backfilling is unavoidable — holidays, system outages, onboarding new tools — keep your categorisation script version-controlled and documented. Running it once a quarter takes ten minutes when the script already exists and has been tested.
Ready to Never Backfill a Timesheet Again?
Keito syncs with your calendar in real time. Meeting time is logged automatically alongside git-based coding time. No exports, no scripts.
Key Takeaway
Calendar events are the most reliable source of non-coding time data. Export as ICS or CSV, calculate duration, categorise by client, and filter out cancellations. The permanent fix is real-time calendar integration — set it up once and eliminate backfilling entirely.
Frequently Asked Questions
How do I convert Google Calendar events into timesheet entries?
Export your calendar as an ICS file via Settings → Import & Export, or use the Google Calendar API with timeMin and timeMax parameters to retrieve events as JSON. Parse each event to extract the title, start and end time, and duration, then assign each entry to a client or project and import into your time tracking tool.
Can I automate timesheet backfilling from my calendar?
Yes. Use a Python script with the icalendar library to parse ICS files and output CSV time entries, Google Apps Script to read Google Calendar and write directly to a Google Sheet, or Microsoft Power Automate to pull Outlook events and log them to a time tracking tool. For ongoing automation without manual exports, connect your calendar API to your time tracking tool’s API directly.
How do I categorise calendar events as billable or non-billable?
Maintain separate calendars per client for automatic categorisation. Use consistent event title prefixes such as [ClientCode] for parsing. Filter by attendee email domains — events with external attendees are typically billable, internal-only events are typically not. After automatic categorisation, run a brief manual review to catch prep sessions and edge cases.
What if I have cancelled meetings on my calendar?
Check the STATUS:CANCELLED property in your ICS export and filter out any events with that status before calculating totals. Some platforms do not always update the status field when a meeting is declined; cross-reference with your inbox or notes if billing accuracy is critical for those events.
Is calendar-based time tracking accurate enough for billing?
Calendar events capture meeting time accurately — they record exact start and end times. They do not capture coding, research, writing, or asynchronous work. For a complete billable picture, combine calendar data with git-based tracking to cover both meeting time and development time automatically.