How to turn Google Calendar into a timesheet in Google Sheets
Short answer: Google Calendar has no “export to Google Sheets”. Its export gives you .ics files, which a spreadsheet cannot open as a table. The free way that works is a short Apps Script: open Extensions → Apps Script in your spreadsheet and paste a script that calls CalendarApp.getEvents and writes one row per event. It gives you start, end and hours, but no clients and no rounding, and it rebuilds the sheet each time. An add-on such as HourLane adds those parts.
1. First, put the client in the event
A timesheet needs to know who each hour was for. Whatever you use, make the client easy to find in Google Calendar™:
- In the title, the same way every time:
[Acme] Design reviewat the start, orDesign review #acme. - Or one calendar per client, or one event colour per client.
It takes a few characters per event and saves sorting the rows out later.
2. The manual way: export the calendar
- In Google Calendar on a computer, click the gear icon → Settings.
- Choose Import & export → Export. Google downloads a .zip file with one .ics file for each calendar you own. For a single calendar, open it under Settings for my calendars and choose Export calendar.
- Unzip the file. An .ics file is plain text, one field per line:
BEGIN:VEVENT,DTSTART:20261116T140000Z,DTEND:…,SUMMARY:[Acme] Design reviewand so on.
Google Sheets™ cannot open an .ics file as a table. To get rows, you convert it with another tool, or import it as text and rebuild each event from its lines with formulas. Either way, expect clean-up:
- Everything, every year. The export holds all events of the calendar, not one month, so you filter by date first.
- Times are often in UTC, such as
20261116T140000Z, not in your own time zone. - Recurring events are one entry with a repeat rule (
RRULE), not one row per meeting. - No hours and no clients. You add a duration column, round it, and work out the client from each title.
- Next month, again. The export is a copy. When the calendar changes, you export and clean up again.
It works once, for a small calendar. For a timesheet you keep every week, a script is less work.
3. The Apps Script way
- In your spreadsheet, add a tab named Timesheet.
- Choose Extensions → Apps Script, replace the code with the script below and click Save.
- Click Run. The first time, Google asks you to allow the script to see your calendar and your spreadsheet.
function calendarToTimesheet() {
const cal = CalendarApp.getDefaultCalendar(); // your main calendar
const from = new Date(2026, 10, 1), to = new Date(2026, 11, 1); // November 2026
const rows = cal.getEvents(from, to)
.filter(function (e) { return !e.isAllDayEvent(); })
.map(function (e) {
const hours = (e.getEndTime() - e.getStartTime()) / 3600000;
return [e.getStartTime(), e.getEndTime(), hours, e.getTitle()];
});
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Timesheet');
sheet.clearContents();
sheet.getRange(1, 1, 1, 4).setValues([['Start', 'End', 'Hours', 'Event']]);
if (rows.length) sheet.getRange(2, 1, rows.length, 4).setValues(rows);
}
The Timesheet tab now has one row per event of November, with its start, end, hours and title. getEvents returns each occurrence of a recurring event separately, so a weekly call appears once a week. Change the two dates for another month.
4. Where the simple script falls short
- No clients. The client is still inside the title. Splitting
[Acme]off, and adding rules for events without a tag, is more code. - No rounding. A 52-minute meeting is 0.8666… hours. To bill in 15-minute steps, round in code or with
=CEILING(C2*4)/4in the sheet. - It rebuilds the sheet.
clearContentswipes the tab on every run, so a note, a “not billable” mark or a corrected hour you typed is gone the next time. Keeping them means matching each row to its event by ID. - One calendar. For another calendar, use
CalendarApp.getCalendarById, and run it once per calendar. - Declined events count. A meeting you said no to still has hours. Filter with
e.getMyStatus(). - Time zones. The two dates are read in the script’s own time zone (Project settings), and the times are shown in the spreadsheet’s (File → Settings). If either differs from your calendar’s, the period or the times shift by the difference.
- No totals. Hours per client per month need a pivot table or
SUMIFSon top.
None of this is hard on its own. Together, it is a small program to keep up every time the way you bill changes.
5. With an add-on: HourLane
HourLane is our Google Sheets add-on for this job. It is not on Google Workspace Marketplace yet. It does what the script above leaves to you:
- One row per event in a Timesheet tab: date, start, end, hours, client, event, calendar, billable, notes, attendees, location and a link to the event. Times are in your main calendar’s time zone.
- Any calendars you tick, and a period: this week, last week, this month, last month, the last 30 days or your own dates.
- The client from
[Acme]or#acmein the title, or from rules by title, calendar, guest email domain or event colour. - Rounding to 6, 10, 15, 30 or 60 minutes, to the nearest step or always up. All-day and declined events are skipped unless you want them.
- Refresh keeps what you typed: Billable, Notes, a client you changed and hours you corrected. Rows outside the period stay, so the sheet becomes a running log.
- A Summary tab with hours and billable hours per client and month.
- It only reads your calendar. It never creates, changes or deletes an event.
- The timesheet is free. Pro, for $4.99 a month or $39 a year, adds hourly rates and amounts, a statement per client and month by email, and an automatic refresh every morning.
How to set it up: HourLane help.
Questions
Can Google Calendar export to Google Sheets?
Not directly. Google Calendar exports .ics files, and Google Sheets has no way to open them as a table. To get events into a spreadsheet, use a short Apps Script or an add-on.
How do I calculate hours from Google Calendar events?
Subtract the start from the end. In a script, (end - start) / 3600000 gives hours. In a sheet with Start and End as date-times, =(End-Start)*24 does the same. Round the result if you bill in steps, such as 15 minutes.
How do I track time per client in Google Calendar?
Put the client in each event, for example in square brackets at the start of the title, [Acme] Design review, or give each client its own calendar or colour. A script or an add-on can then read the client from there.
Are recurring events included?
In a script, CalendarApp.getEvents returns each occurrence separately. In an .ics export, a recurring event is one entry with a repeat rule, so its occurrences have to be worked out by hand.