Who is Kairos?

Kairos (Ancient Greek: καιρός) is an ancient Greek word meaning ‘the right, critical, or opportune moment’.

It is one of two words that the ancient Greeks had for ‘time’; the other being chronos (χρόνος). Whereas the latter refers to chronological or sequential time, kairos signifies a proper or opportune time for action. In this sense, while chronos is quantitative, kairos has a qualitative, permanent nature .

For a really long time I’ve had trouble with arriving on time to places. I wouldn’t really admit that until a couple of years ago, when I had been dating my current girlfriend for about a year. Up until then, I was able to believe that I only arrived late sometimes. Even if everyone around me had picked up the pattern and told me several times, I tended to think they were exaggerating. However, it is much harder to deny that you are consistently late when, after dating for about a year, you keep making the same mistake and hurting someone’s feelings.

Still, fast forward two years, and I still tend to be late. I think I have improved a lot, at least because I’m aware that there is an issue and I try to improve, and when I fail I try to recognise it and apologise. But I make all sorts of mistakes, generally along the lines of underestimating how long things will take.1

A timely budget

Last week I arrived late to a video call with my girlfriend, and I remembered a couple of tweets by visakanv:

Since I wrote Order and Chaos, I have been thinking a lot about automations and workflows that could make my life easier, like My Obsidian Templates, and I’ve thought a couple of times about creating a “timely budget”.

I hadn’t done it before because it seemed like a lot work, but last week, thinking about how I really wanted to make a change, I thought, why not give it a try? A part of me thinks this may be too coercive to work, but so far I feel really good about it, if only because of my recent fixation with automations and because I love nerding out about the technical side of how it works.

Speaking of, how does it work?

I have set up a very simple Google Sheet with three columns: meeting date, arrival date and difference.

I complete this Google Sheet with an iOS shortcut that does the following:

  1. It asks me if I want to add a meeting date or arrival date.
  2. If meeting date
    1. It asks for the date of the meeting
    2. Gives me the option to create a calendar event (with an alert 1.5 hours earlier that I may increase/decrease in the future).
    3. Adds a row to the spreadsheet with the meeting date and time
  3. If arrival date
    1. It gets a list of the meeting dates that currently don’t have an arrival date in the spreadsheet and lets me choose which one I’m arriving to.
    2. Gets the current date and time and adds it next to the specified date and time
    3. Adds =A(row) - B(row) to the difference column to calculate the difference

While that sounds simple enough, turns out that Google Sheets and iOS shortcuts don’t have any integrations, so you have to build them yourself. Following the steps in this reddit post, I learned that you can create Google Apps Scripts, and that Google will host and run them for free. These scripts are written in Javascript (basically) and include libraries to integrate with all of Google’s apps, with a surprising amount of depth, to the point where you can basically build your own extensions right there.

But I didn’t get that far, I just wrote the following script, which awaits for the input from my shortcut:

const spreadsheetId = "qwertyuiop1234567890";
const sheetName = "Sheet1";
const budget = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
 
function doGet(e) {
  if (e.parameters.getOpenTimes) {
    return getOpenMeetingTimes();
  }
 
  if (e.parameters.meeting_time && e.parameters.meeting_time !== '""') {
    addMeetingTime(e.parameters.meeting_time);
  }
 
  if (e.parameters.arrival_time && e.parameters.arrival_time !== '""') {
    addArrivalTime(e.parameters.arrival_time);
  }
}
 
function getOpenMeetingTimes() {
  const meetings = budget.getRange("A2:B").getValues().filter(row => row[0] !== '' && row[1] === '');
  const meetingTimes = meetings.map(row => row[0]);
  return ContentService.createTextOutput(JSON.stringify(meetingTimes)).setMimeType(ContentService.MimeType.JSON);
}
 
function addMeetingTime(meetingTimeParam) {
  const meetingTime = new Date(JSON.parse(meetingTimeParam));
  const existingMeetingTimes = budget.getRange("A2:A").getValues().flat().filter(time => time !== '');
 
  if (!existingMeetingTimes.some(time => time.toISOString() === meetingTime.toISOString())) {
    budget.appendRow([meetingTime]);
  }
}
 
function addArrivalTime(arrivalTimeParam) {
  const arrivalTime = new Date(JSON.parse(arrivalTimeParam));
  const existingMeetingTimes = budget.getRange("A2:A").getValues().flat().filter(time => time !== '');
 
  const duplicate = existingMeetingTimes.findIndex(time => time.toISOString() === arrivalTime.toISOString());
 
  if (duplicate !== -1) {
    const row = duplicate + 2;
    const arrivalTimeCells = budget.getRange(row, 2, 1, 2);
    const newValues = [[arrivalTime, `=A${row}-B${row}`]];
    arrivalTimeCells.setValues(newValues);
  }
}

With this, the shortcut just needs to open the following URL to get the open meeting times:

https://script.google.com/macros/s/[webappid]/exec?getOpenTimes=True

And the following URL to input the meeting and/or arrival times:

https://script.google.com/macros/s/[webappid]/exec?meeting_time=%22[meeting_time]%22&arrival_time=%22[arrival_time]%22

Footnotes

  1. One mistake that I find particularly funny is how sometimes, if I don’t make a conscious effort, I will assume that I can just teleport places if they are <10 min away.