From 8418e01a840cd2d6f55291929b126b1e6b1f028f Mon Sep 17 00:00:00 2001 From: sterni Date: Sat, 29 May 2021 16:02:00 +0200 Subject: feat(fun/πŸ•°οΈ): get the time as an emoji clock face MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This small tool prints the current time rounded to half-hour precision as an emoji clock face and exists. It can use both the local time zone and UTC. Additionally it supports a pseudo dot time format. Via fun.πŸ•°οΈ.lib we reexpose the internal library which allows conversion from LOCAL-TIME:TIMESTAMP to an emoji clock face β€” maybe we'll want to integrate this into //web/panettone? //fun/πŸ•°οΈ is the spritual (and actual) successor to . It likely only works in SBCL due to its heavy usage of unicode symbol names. Change-Id: I44204107a14f99b04b0c5290d88e8659f013f423 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3164 Tested-by: BuildkiteCI Reviewed-by: tazjin --- "fun/\360\237\225\260\357\270\217/OWNERS" | 3 + "fun/\360\237\225\260\357\270\217/bin.lisp" | 91 ++++++++++++++++++++++++++ "fun/\360\237\225\260\357\270\217/default.nix" | 36 ++++++++++ "fun/\360\237\225\260\357\270\217/lib.lisp" | 32 +++++++++ 4 files changed, 162 insertions(+) create mode 100644 "fun/\360\237\225\260\357\270\217/OWNERS" create mode 100644 "fun/\360\237\225\260\357\270\217/bin.lisp" create mode 100644 "fun/\360\237\225\260\357\270\217/default.nix" create mode 100644 "fun/\360\237\225\260\357\270\217/lib.lisp" (limited to 'fun') diff --git "a/fun/\360\237\225\260\357\270\217/OWNERS" "b/fun/\360\237\225\260\357\270\217/OWNERS" new file mode 100644 index 0000000000..f16dd105d7 --- /dev/null +++ "b/fun/\360\237\225\260\357\270\217/OWNERS" @@ -0,0 +1,3 @@ +inherited: true +owners: + - sterni diff --git "a/fun/\360\237\225\260\357\270\217/bin.lisp" "b/fun/\360\237\225\260\357\270\217/bin.lisp" new file mode 100644 index 0000000000..8bd8aa136d --- /dev/null +++ "b/fun/\360\237\225\260\357\270\217/bin.lisp" @@ -0,0 +1,91 @@ +(defpackage πŸ•°οΈ.bin + (:shadow :describe) + (:use :cl :opts) + (:import-from :uiop :quit) + (:import-from :local-time + :now :timestamp-subtimezone :+utc-zone+ + :*default-timezone* :define-timezone) + (:import-from :klatre :format-dottime-offset) + (:import-from :πŸ•°οΈ :⌚) + (:export :πŸš‚)) + +(in-package :πŸ•°οΈ.bin) +(declaim (optimize (safety 3))) + +(opts:define-opts + (:name :help + :description "Print this help text" + :short #\h + :long "help") + (:name :dot-time + :description "Use pseudo dot-time format (implies -u)" + :short #\d + :long "dot-time") + (:name :utc + :description "Display time in UTC instead of local time" + :short #\u + :long "utc") + (:name :no-newline + :description "Don't print a trailing newline" + :short #\n + :long "no-newline")) + +(defun make-slash-terminated (str) + (if (eq (char str (1- (length str))) #\/) + str + (concatenate 'string str "/"))) + +; TODO(sterni): upstream this into local-time +(defun setup-default-timezone () + (let* ((tz (uiop:getenv "TZ")) + (tz-dir (uiop:getenv "TZDIR")) + (tz-file (if (and tz tz-dir) + (merge-pathnames + (pathname tz) + (pathname (make-slash-terminated tz-dir))) + (pathname "/etc/localtime")))) + (handler-case + (define-timezone *default-timezone* tz-file :load t) + (t () (setf *default-timezone* +utc-zone+))))) + + +(defun πŸš‚ () + (let ((ts (now))) + (multiple-value-bind (options free-args) + (handler-case (opts:get-opts) + ; only handle subset of conditions that can happen here + (opts:unknown-option (c) + (format t "error: unknown option ~s~%" (opts:option c)) + (quit 100))) + + ; check if we have any free args we don't know what to do with + (when (> (length free-args) 0) + (write-string "error: unexpected command line argument(s): ") + (loop for arg in free-args + do (progn (write-string arg) (write-char #\space))) + (write-char #\newline) + (quit 100)) + + ; print help and exit + (when (getf options :help) + (opts:describe :usage-of "πŸ•°οΈ") + (quit 0)) + + ; reinit *default-timezone* as it is cached from compilation + (setup-default-timezone) + ; dot-time implies UTC, naturally + (when (getf options :dot-time) + (setf (getf options :utc) t)) + ; print clock face + (format t "~A" (⌚ ts (if (getf options :utc) + local-time:+utc-zone+ + local-time:*default-timezone*))) + ; render dot-time offset if necessary + (when (getf options :dot-time) + (multiple-value-bind (offset-secs _dst _name) + (timestamp-subtimezone ts local-time:*default-timezone*) + (write-string + (format-dottime-offset (round (/ offset-secs 3600)))))) + ; write newline if necessary + (when (not (getf options :no-newline)) + (write-char #\newline))))) diff --git "a/fun/\360\237\225\260\357\270\217/default.nix" "b/fun/\360\237\225\260\357\270\217/default.nix" new file mode 100644 index 0000000000..d6fd5fc35e --- /dev/null +++ "b/fun/\360\237\225\260\357\270\217/default.nix" @@ -0,0 +1,36 @@ +{ depot, ... }: + +let + inherit (depot.nix) + buildLisp + ; + + lib = buildLisp.library { + name = "libπŸ•°οΈ"; + deps = [ + depot.third_party.lisp.local-time + ]; + + srcs = [ + ./lib.lisp + ]; + }; + + bin = buildLisp.program { + name = "πŸ•°οΈ"; + deps = [ + depot.third_party.lisp.unix-opts + depot.lisp.klatre + (buildLisp.bundled "uiop") + lib + ]; + + srcs = [ + ./bin.lisp + ]; + + main = "πŸ•°οΈ.bin:πŸš‚"; + }; +in bin // { + inherit lib; +} diff --git "a/fun/\360\237\225\260\357\270\217/lib.lisp" "b/fun/\360\237\225\260\357\270\217/lib.lisp" new file mode 100644 index 0000000000..d23db03374 --- /dev/null +++ "b/fun/\360\237\225\260\357\270\217/lib.lisp" @@ -0,0 +1,32 @@ +(defpackage πŸ•°οΈ + (:use :cl) + (:import-from :local-time + :timestamp-subtimezone :*default-timezone* :sec-of) + (:export :⌚)) + +(in-package :πŸ•°οΈ) +(declaim (optimize (safety 3))) + +(defparameter *clock-emojis* + (vector #\πŸ•› #\πŸ•§ ; 00:00 - 00:30 + #\πŸ• #\πŸ•œ ; 01:00 - 01:30 + #\πŸ•‘ #\πŸ• ; 00:00 - 00:30 + #\πŸ•’ #\πŸ•ž ; 00:00 - 00:30 + #\πŸ•“ #\πŸ•Ÿ ; 00:00 - 00:30 + #\πŸ•” #\πŸ•  ; 00:00 - 00:30 + #\πŸ•• #\πŸ•‘ ; 00:00 - 00:30 + #\πŸ•– #\πŸ•’ ; 00:00 - 00:30 + #\πŸ•— #\πŸ•£ ; 00:00 - 00:30 + #\πŸ•˜ #\πŸ•€ ; 00:00 - 00:30 + #\πŸ•™ #\πŸ•₯ ; 00:00 - 00:30 + #\πŸ•š #\πŸ•¦)) ; 11:00 - 11:30 + +(defun ⌚ (timestamp &optional (tz *default-timezone*)) + "Convert a LOCAL-TIME:TIMESTAMP into the nearest Unicode clock face. + Use TZ (which defaults to LOCAL-TIME:*DEFAULT-TIMEZONE*) to determine + the UTC offset to factor when determining the local clock face." + (let* ((offset (multiple-value-bind (offset-secs _dst _name) + (timestamp-subtimezone timestamp tz) + offset-secs)) + (secs (+ (sec-of timestamp) offset))) + (elt *clock-emojis* (mod (round (/ secs 1800)) 24)))) -- cgit 1.4.1