December Adventure Day 02
ISO 8601 Timestamps in OPL
Despite writing OpoLua, a modern OPL runtime for iOS and macOS, it’s a long time since I’ve actually written anything in OPL. So what better for a Psion-themed December Adventure than to return to one of the languages that started it all for me?
Earlier this year, I published Thoughts, a lightweight Markdown-based note taking app for macOS which I use primarily for journaling and I thought it would be nice to bring a couple of the main features to my writing experience on EPOC32—a kind of ‘Thoughts-lite’ if you will.
Thoughts is a simple app offering the following functionality:
- global hotkey for starting new notes
- automatic date and location tagging (stored in Frontmatter)
- Markdown syntax highlighting
- tag editor
It generates Markdown files that look something like this:
---
date: '2024-11-26T09:23:55-10:00'
tags: []
location:
latitude: 2.15791762399229e+1
longitude: -1.58105437871125e+2
name: 61-535 Kamehameha Hwy
locality: "Hale\u02BBiwa"
---
Selecting multiple matching words in Helix can be done using:
miw*vn
While it might disappoint some members of the Psion community1, I’ve no plans to tackle a dedicated Markdown editor—I find the Symbian-published Editor just great for writing—but I would like to automatically create and timestamp new notes, and pre-populate them with some Frontmatter for filling in tags.
Starting simple, my initial focus is on generating an IS0 8601-formatted timestamp as used by Thoughts. Unfortunately OPL doesn’t make this easy as it’s lacking some basics—I first had to write a way to zero-pad numbers:
PROC ZPAD$:(value&,length%)
REM Left-pad numbers with '0' up to a length, length%, maximum 10.
LOCAL result$(10)
result$=NUM$(value&,length%)
IF LEN(result$) < length%
result$ = "0" + result$
ENDIF
RETURN result$
ENDP
With that in place, I was able to approach a procedure to format a datetime as ISO 8601:
PROC ISO8601$:(datetime&)
LOCAL year&, month&, day&, hour&, minute&, second&, result$(25)
REM Extract the relevant components.
year&=DTYEAR&:(datetime&)
month&=DTMONTH&:(datetime&)
day&=DTDAY&:(datetime&)
hour&=DTHOUR&:(datetime&)
minute&=DTMINUTE&:(datetime&)
second&=DTSECOND&:(datetime&)
REM Construct the ISO8601 string.
result$=NUM$(year&,4) + "-" + ZPAD$:(month&,2) + "-" + ZPAD$:(day&,2) + "T" + ZPAD$:(hour&,2) + ":" + ZPAD$:(minute&,2) + ":" + ZPAD$:(second&,2)
RETURN result$
ENDP
During this process, I found myself relying heavily on nOPL+, a minimal OPL IDE that, crucially, includes a built-in OPL reference:
With my newly-crafted procedure, testing it is simply a matter of getting the current date, calling it with OPL’s weird syntax, and printing the output (not forgetting to use GET
to wait for the user to press a key lest my program exits before I see what it’s done):
INCLUDE "date.opx"
PROC main:
LOCAL now&, date$(25)
now&=DTNOW&:
date$=ISO8601$:(now&)
PRINT date$
GET
ENDP
Success:
2024-12-03T03:23:25
You might notice I’ve made no attempt to tackle time zones in this implementation, but that’s enough for day 2—remembering OPL’s many quirks took quite a bit longer than I’d expected and the seasonal festivities are already underway. 🎉
-
You know who you are. ↩