# Custom org-id format

**URL:** <https://org-roam.discourse.group/t/custom-org-id-format/3448>\
**Category:** Tips\
**Created:** [April 28, 2024, 10:55pm UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448 "2024-04-28T22:55:21Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![akashp](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/akashp/32/1383_2.png) [@akashp](https://org-roam.discourse.group/u/akashp)\
**Post date:** [April 28, 2024, 10:55pm UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448/1 "2024-04-28T22:55:21Z")

</div>

Problem: Make org-id more human readable while ensuring uniqueness.

Persistent daily counter – highjacking 'ts format.

```auto
;; org-id-counter - definition and infrastructure for org-id format %date-%counter

(defvar org-id-counter (make-hash-table :size 1 :test 'equal)
  "Hash table to store the counter for each day.")

(defvar org-id-counter-location (locate-user-emacs-file "org-id-counter"))

(setq org-id-method 'ts)

(defun org-id-counter-format ()
  "Generate an Org ID using the format %Y/%m/%d-%counter."
  (let* ((today (format-time-string "%Y/%m/%d"))
         (counter (or (gethash today org-id-counter) 1))
         (id (format "%s:%s" today (number-to-string counter))))
    (puthash today (1+ counter) org-id-counter)
    id))

;; iteration logic
(defun org-id-counter-advice (&rest args)
  "Advice function to set `org-id-ts-format` before calling `org-id-new`."
  (setq org-id-ts-format (funcall #'org-id-counter-format)))

(advice-add 'org-id-new :before #'org-id-counter-advice)

;; Persistent counter for the day
(defun org-id-counter-save ()
  "Save org-id-counter hash table to disk."
  (with-temp-file org-id-counter-location
    (prin1 org-id-counter (current-buffer))))

(add-hook 'kill-emacs-hook #'org-id-counter-save) ;; Save the hash table on Emacs exit

(defun org-id-counter-load ()
  "Load org-id-counter hash table from disk."
  (when (file-exists-p org-id-counter-location)
    (if (= 0 (nth 7 (file-attributes org-id-counter-location))) ; Check if file is empty
        (setq org-id-counter (make-hash-table :test 'equal)) ; Initialize with empty hash table
      (with-temp-buffer
        (insert-file-contents org-id-counter-location)
        (let ((data (read (current-buffer))))
          (when (hash-table-p data)
            (setq org-id-counter data)))))))

(org-id-counter-load) ;; Load the hash table on Emacs start

;; debug
(defun org-id-counter-show ()
  "Display the contents of org-id-counter hash table."
  (interactive)
  (message "Contents of org-id-counter hash table:")
  (maphash (lambda (key value)
             (message "%s: %s" key value))
           org-id-counter))

(defun org-id-counter-reset ()
    "Reset the counter on request.
Caution: make sure you make appropriate provisions to not have conflicting IDs"
  ;(interactive)
(setq org-id-counter (make-hash-table :test 'equal)))

(provide 'org-id-counter)

```

![Screenshot_2024-04-29_04-23-26](https://global.discourse-cdn.com/free1/uploads/orgroam/original/2X/6/6482d64f5bc31ff883f2daa04ef5f32908d51091.png)

Lightly tested - will update on finding bugs and the like.

---

<div class="post-metadata">

**Author:** ![alanz](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/alanz/32/717_2.png) [@alanz](https://org-roam.discourse.group/u/alanz)\
**Post date:** [April 30, 2024, 6:33pm UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448/2 "2024-04-30T18:33:48Z")

</div>

FWIW, I am happy with the normal timestamp format, via

```auto
  ;; Use an ISO8601 timestamp for IDs
  (org-id-method 'ts)

```

Which shows up as `20240430T181635.273283`

---

<div class="post-metadata">

**Author:** ![akashp](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/akashp/32/1383_2.png) [@akashp](https://org-roam.discourse.group/u/akashp)\
**Post date:** [April 30, 2024, 7:07pm UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448/3 "2024-04-30T19:07:31Z")

</div>

Ofcourse its a very simple yet effective way to ensure uniqueness - although I have trouble reading them at a glance and also keeping manual records of them.

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [May 9, 2024, 10:28am UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448/4 "2024-05-09T10:28:35Z")

</div>

I use a variation of what @alanz uses. I do not like to use the global variable to keep track of the counter for the day (feels a bit too complex for what we want).

The time stamp format is now customizable with Org 9.5 = Emacs 28.

I use this format: `"%Y-%m-%dT%H%M%S"`:  
`=> 2024-05-09T122208`.

The part `Thhmmss` makes the ID unique to the second (enough for me) and still readable for me. It’s useful as a time stamp as well.

Other variations without global counter may be like these.  
For what it’s worth…

```auto
;; ISO 8601 format
(let ((org-id-method 'ts)
      (org-id-ts-format "%FT%T"))
  (org-id-new))

```

`=> 2024-05-09T12:19:30`

```auto
;; Uniquify without global variable
(let ((org-id-method 'ts)
      (org-id-ts-format "%F:"))
  (concat (org-id-new) (substring (org-id-uuid) 0 8)))

```

`=> 2024-05-09:a24dd299`

You can use a forward slash to divide year, month, and day, of course:

```auto
(let ((org-id-method 'ts)
      (org-id-ts-format "%Y/%m/%d:"))
  (concat (org-id-new) (substring (org-id-uuid) 0 8)))

```

`=> 2024/05/09:fdb00bd5`

```auto

```

---

<div class="post-metadata">

**Author:** ![akashp](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/akashp/32/1383_2.png) [@akashp](https://org-roam.discourse.group/u/akashp)\
**Post date:** [May 9, 2024, 3:05pm UTC](https://org-roam.discourse.group/t/custom-org-id-format/3448/5 "2024-05-09T15:05:36Z")

</div>

I agree with both you and @alanz in that I think its too overcomplicated for trying to do something simple - I was working in a different context, but I ended by creating this out of whatever was left. I treat this as a more proof of concept - rather than something we should use.

– this has some big limitations - insofar as much, syncing between different computers becomes a forgone task without making the thing more complex –

I had given up on this and I simply have learnt to live life with the full 'ts format – the absoluteness of time is in itself a global variable.

Perhaps this could be an example in context for future readers in how to handle variables :- and save and load them from disk – nothing much more should be used out of it – for it imposes handicaps that are too expensive in nature.
