My 2022 Wrapped
Article • 2,171 Words • Living Better • 12/25/2022
Pages That Link Here:
I use my calendar to track everything, so I thought that, inspired by Spotify Wrapped, the logical conclusion would be analyzing my calendar data.
The Inspiration: Spotify Wrapped
Spotify Wrapped started a movement of reporting back some of the data that a service collects on you at the end of the year. I’ve seen Resy, Doordash, GrubHub give some analytics at the end, or something like the BeReal or Locket recap where at the end of the year, all of your photos are shown to you put together in a video collage or something of that nature. Spotify Wrapped is such an enduring cultural moment (so let’s give credit where it’s due), that people try to recreate it in their person lives, this year a big trend on TikTok was the “Dating Wrapped” trend. This is where people would make their own PowerPoints detailing how many dates they went on that year, how long it lasted, why it ended, etc. I think this is a bit different than other “Wrappeds” because it seems more like a narrative device.
I think the reason that Spotify Wrapped works so well is that sharing something like music taste on social media works really well. Millennials and Gen Z-ers love to share things because you get to judge people (neutral affect because it could be the case that the person has good taste or bad taste). In this same way, analyzing my calendar data allows an insight into the kind of person I am as well, so I’m willing to share it.
If you just want to see the results and not read about how I did it, you can skip to the results section.
My Methodology
I did this all in Node.js because I didn’t want to have to design any UI elements, I just wanted some cold hard numbers, and that is padded with some natural language to convert the statistics into normal sentences. I think that if I repeat this project in 2023 that it would maybe be fun for it to have a UI, or at least some nice icons to go along with the activities that I am keeping track of. You can find all of the code here on my GitHub.
It was actually stupid simple getting started with analyzing my calendar data. I just use Google Calendar, and they make it very easy to download your own data into an .ics file (How to Export Your Google Calendar). Funny enough, the thought that I could write my own parser for .ics files didn’t even cross my mind, and while I think a fun project for someone wanting to practice programming would be to create their own .ics (iCalendar File Format) parser, I am glad that I did not. Instead, I used the node-ical package, which provides a few very straightforward functions that parse .ics files into JavaScript objects, and then after that, you’re off to the races just manipulating calendar events as JavaScript objects just as you would in any other program.
All in all, that looked like something like this:
// import ical
const ical = require("node-ical");
// use the sync function so we don't have to use promises/callbacks
const data = ical.sync.parseFile("events.ics");
// get the events in reverse chronological order
const events = Object.values(data).reverse();
// get the start time of the window
const timeWindow = new Date("January 1, 2022");
// get events that are within the time window
const eventsThisYear = events.filter(event => new Date(event.start) > timeWindow);
What I think is nice about doing this yourself is that you can track whatever things you want. I wanted to track “healthy habits” (workouts, walks, hikes, etc.), media consumption (TV, YouTube, movies, etc.), hanging out with friends, as well as the more “mandatory events” like cooking and transportation. This was really easy to do once I created some helper functions and my analysis function ended up like this:
// log total events in calendar
console.log(`You logged ${eventsThisYear.length.toLocaleString()} events this year.`);
console.log();
// log healthy events
logTimeStats(getEventsByFuzzyName(eventsThisYear, "workout"), "worked out");
logTimeStats(getEventsByName(eventsThisYear, "walk"), "went walking");
logTimeStats(getEventsByFuzzyName(eventsThisYear, "hike"), "went hiking");
// log media consumption
logTimeStats(getEventsByFuzzyName(eventsThisYear, "read"), "read");
logTimeStats(getEventsByFuzzyName(eventsThisYear, "watch youtube"), "watched YouTube");
logTimeStats(getEventsByFuzzyName(eventsThisYear, "watch tv"), "watched TV");
// log cooking
logTimeStats(getEventsByFuzzyName(eventsThisYear, "cook"), "cooked");
logTimeStats(getEventsByFuzzyName(eventsThisYear, "make food"), "made food");
// log boring tasks
logTimeStats(getEventsByFuzzyName(eventsThisYear, "eat"), "ate");
logTimeStats(getEventsByFuzzyName(eventsThisYear, "transit"), "spent time in transit");
console.log();
// log the time spent with people
logTimeStats(getEventsByFuzzyName(eventsThisYear, "hang"), "hung out with friends");
getEventsByFuzzyName()
is kind of a bad name because I’m not really doing any kind of real fuzzy search, but what it’s doing is doing events.filter(event => event.summary.includes(name))
vs getEventsByName()
which is just event.summary == name
.
I also mark hang outs/events with people by saying “hang w/ name” or “eat w/ name”. In this way, I am able to analyze how many times and for how long I hung out with someone during the year. This was a lot of fun, and lead me to send some funny ominous texts to my friends.
@dinglehopp3r @Google if y’all need a software engineer #googlecalendarsupremacy ♬ Christmas commercial(1139078) - Kids Sound
The code for this was a little messy, but still simple, I just had to do some event name clean up because my notation for listing multiple people in an event is not always consistent, with me switching between an “&” or a “+” just depending on how I’m feeling at the moment. I’m sorry for the weird format of commenting in between the functions in the function chain, but I thought that it would just format better on smaller screens.
function getEventsWithPerson(events, name) {
return events.filter(event => {
// if the event title has people's names in it
if (event.summary && event.summary.includes("w/"))
{
// get list of people after the "w/" at the end of the event name
const attendeesRaw = event.summary.substring(event.summary.indexOf("w/") + 3);
// process the attendee string into an array
const attendeesProcessed = attendeesRaw
// convert to just another CSV
.replaceAll("&", ", ")
// convert to just another CSV
.replaceAll("+", ", ")
// split by comma bc list is CSV
.split(", ")
// get rid of empty elements
.filter(x => x)
// go to lowercase and trim trailing whitespace
.map(x => x.toLowerCase().trim());
// check if person is part of attendees array
return attendeesProcessed.includes(name.toLowerCase());
}
// otherwise the event has no attendees
return false;
});
}
My Results
These results are a bit skewed because of how I record events and how its not always the easiest to automatically parse those non-standardized records. Additionally, I only record events in 15-minute increments (who wants to see an event end at 1:06pm? shudders), and I also don’t typically create events for things that last shorter than 30-minutes. With that being said, I think I have enough data to see general trends and make adjustments next year accordingly. Also, for cooking and eating a lot of times I only recorded it when those events took a significant amount of time, often times I just heat something up and eat it rather quickly, which I don’t think warrants an event.
Healthy Habits:
- You worked out 80 times for 2,775 minutes or 46.25 hours. This accounts for 0.53% of the year.
- You went walking 68 times for 2,805 minutes or 46.75 hours. This accounts for 0.53% of the year.
- You went hiking 3 times for 315 minutes or 5.25 hours. This accounts for 0.06% of the year.
Media Consumption:
- You watched YouTube 81 times for 4,335 minutes or 72.25 hours. This accounts for 0.82% of the year.
- You watched TV 68 times for 4,605 minutes or 76.75 hours. This accounts for 0.88% of the year.
- You read 101 times for 6,465 minutes or 107.75 hours. This accounts for 1.23% of the year.
Cooking:
- You cooked 53 times for 2,925 minutes or 48.75 hours. This accounts for 0.56% of the year.
- You made food 8 times for 405 minutes or 6.75 hours. This accounts for 0.08% of the year.
“Mandatory” Tasks:
- You ate 114 times for 6,065 minutes or 101.08 hours. This accounts for 1.15% of the year.
- You spent time in transit 87 times for 3,915 minutes or 65.25 hours. This accounts for 0.74% of the year.
Social Time:
- You hung out with friends 342 times for 61,125 minutes or 1018.75 hours. This accounts for 11.63% of the year.
Next Steps
Improving the depth of analysis for calendar data
I want to add some more functionality to the analysis to see what days of the weeks certain events happen more on, as well as what months certain activities waxed and waned in frequency. I understand that data visualization is a very big field for a reason, and I think that graphs would allow me to better conceptualize how I am spending my time throughout the year.
Creating a better notation for keeping track of events
Since the majority of my data analysis is done on event name only, I will keep easy-to-enter standard names, and then put any extraneous detail in the notes section or in the location section.
Examples:
- cook
- eat
- workout (exercise name)
- walk
- hike
- transit
- watch youtube
- watch tv (show name)
- watch movie (movie name)
Creating a better calendar app
My dream is to create a better calendar app that is more suited to this kind of use case of being a second brain. It would be extensible with a lot of tracking related features that were traditionally part of other apps like a meal tracking app or a habit tracking app, but I think that would be far too much to tackle for the MVP. In my mind the core features are as follow:
- Charts: Visualize how you spend your time, who you spend your time with, how much driving you do, etc.
- Event Tagging: A system to allow for better event search/filtering, can assign icons, pictures, or colors for tagged events
- Life360-like location duration tracking so that you can track where you are geographically and log driving time easily.
- Exercise and Sleep Tracking: Integrations with Fitness/Health apps to keep track of workouts and sleep time
- People Section/Database: A people database that keeps track of past people/your contacts. Currently calendar sections keep track of attendees by people RSVPing, but for me I would want it to be a closed way of keeping track of who was at an event.