agenda list显示农历生日

%%(diary-chinese-anniversary 2 7 7810) ABC’s %d%s birthday 这样写没有报错,但是在agenda list里面没有出现变化啊,没有这个事项啊。

2 7 7810 是指农历 1993 年 2 月 7 号,也就是说公历 2017 年 3 月 4 号过 24 岁生日,你打开 agenda 的年视图(y)应该能发现。

1 个赞

我失误了,忘记了,抱歉,谢谢你的回答。

周期的计算有点小问题,要向下取整加1

(let* ((cycle (/ (+ 1993 2637) 60.0))
       (year  (- (+ 1993 2637) (* 60 (truncate cycle)))))
  (list  (+ 1 (floor cycle)) year))
     => (78 10)

能不能直接这么写 %%(diary-chinese-anniversary 9 23 1993) 这是农历 1993 年 9 月 23 日生人的第 %d%s 个生日 然后用你写的这段代码来防止emacs报错啊?免得每次还要再计算一下cycle和year。

加上这段:

(defun diary-chinese-anniversary (lunar-month lunar-day &optional year mark)
  (let* ((ddate (diary-make-date lunar-month lunar-day year))
         (dd (calendar-extract-day ddate))
         (mm (calendar-extract-month ddate))
         (yy (calendar-extract-year ddate))
         (a-date (calendar-absolute-from-gregorian date))
         (c-date (calendar-chinese-from-absolute a-date))
         (mm2 (nth 2 c-date))
         (dd2 (nth 3 c-date))
         (y (calendar-extract-year date))
         (diff (if year (- y year) 100)))
    (and (> diff 0) (= mm mm2) (= dd dd2)
         (cons mark (format entry diff (diary-ordinal-suffix diff))))))

然后就可以这样撸农历了

%%(diary-chinese-anniversary 9 23 1993) 这是农历 1993 年 9 月 23 日生人的第 %d%s 个生日

3 个赞

运行出现问题,这段代码的适用范围是多少啊?我对这段代码不熟悉。

直接覆盖diary-chinese-anniversary可能造成问题,可以改个名字,再利用自带的diary-chinese-anniversary

(defun my--diary-chinese-anniversary (lunar-month lunar-day &optional year mark)
  (if year
      (let* ((d-date (diary-make-date lunar-month lunar-day year))
             (a-date (calendar-absolute-from-gregorian d-date))
             (c-date (calendar-chinese-from-absolute a-date))
             (cycle (car c-date))
             (yy (cadr c-date))
             (y (+ (* 100 cycle) yy)))
        (diary-chinese-anniversary lunar-month lunar-day y mark))
    (diary-chinese-anniversary lunar-month lunar-day year mark)))

然后这样写 %%(my–diary-chinese-anniversary 9 23 1993) 这是农历 1993 年 9 月 23 日生人的第 %d%s 个生日

5 个赞

目前运行正常,非常感谢。

这段代码有一个小问题:emacs25.1可以用,emacs24.5会运行出错,我不懂lisp语言,所以不知道怎么修改。

有个包叫cal-china-x,这个包有个函数holiday-lunar,可以直接定义农历节日。

不仅如此,通过配置,它还能在日历上显示农历。

安装了这个包后,可以用如下函数进行农历和公历转换:

(defun date-to-lunar-date (date)
  "把calendar表示的公历日期转换成农历日期"
  (calendar-chinese-from-absolute
  (calendar-absolute-from-gregorian date)))

date是个list,具体什么结构我忘记了,试一下就知道了。

自带的 diary-chinese-anniversary 是不是有问题?有一个 undefined 的变量 date

;;;###cal-autoload
(defun diary-chinese-anniversary (month day &optional year mark)
  "Like `diary-anniversary' (which see) but accepts Chinese date."
  (pcase-let* ((ddate (diary-make-date month day year))
               (`(,dc ,dy ,dm ,dd)      ;diary chinese date
                (if year
                    (calendar-chinese-from-absolute
                     (calendar-chinese-to-absolute-for-diary ddate))
                  (list nil nil (calendar-extract-month ddate)
                        (calendar-extract-day ddate))))
               (`(,cc ,cy ,cm ,cd)      ;current chinese date
                (calendar-chinese-from-absolute
                 (calendar-absolute-from-gregorian date)))
               (diff (if (and dc dy)
                         (+ (* 60 (- cc dc)) (- cy dy))
                       100)))
    (and (> diff 0)
         ;; The Chinese month can differ by 0.5 in a leap month.
         (or (= dm cm) (= (+ 0.5 dm) cm))
         (= dd cd)
         (cons mark (format entry diff (diary-ordinal-suffix diff))))))
1 个赞

你似乎发现了一个bug。应该是 ddate 的样子

debug 了半天,发现不是。这个函数实际是这么使用的:

(let ((entry "entry")
      (date '(7 23 2018)))
      (diary-chinese-anniversary ...))

感觉被欺骗了感情

同样很困惑,看了下 diary-sexp-entry,其中用了 calendar-dlet*,大概类似于

x
;; error-> Symbol's value as variable is void: x

(defun foo ()
  x)
;; => foo

(progn (defvar x)
       (let ((x 42))
         (foo)))
;; => 42

x
;; error-> Symbol's value as variable is void: x

改写了一下貌似可以了:

      (require 'cal-china)

      ;; diary for chinese birthday
      (defun my--diary-chinese-anniversary (lunar-month lunar-day &optional year mark)
        (if year
            (let* ((d-date (diary-make-date lunar-month lunar-day year))
                   (a-date (calendar-absolute-from-gregorian d-date))
                   (c-date (calendar-chinese-from-absolute a-date))
                   (date a-date)
                   (cycle (car c-date))
                   (yy (cadr c-date))
                   (y (+ (* 100 cycle) yy)))
              (diary-chinese-anniversary lunar-month lunar-day y mark))
          (diary-chinese-anniversary lunar-month lunar-day year mark)))

主要是加了 (require 'cal-china) 不然函数 calendar-chinese-from-absolute 找不到。 另外 date 变量报错的问题,我加了一个 (date a-date)

我这里calendar-date-style默认是’iso,会出现 Bad sexp at line 2错误,在let里将calendar-date-style改成american后正常。

;; diary for chinese birthday
      (defun my-diary-chinese-anniversary (lunar-month lunar-day &optional year mark)
        (if year
            (let* ((calendar-date-style 'american)
                   (d-date (diary-make-date lunar-month lunar-day year))
                   (a-date (calendar-absolute-from-gregorian d-date))
                   (c-date (calendar-chinese-from-absolute a-date))
                   (date a-date)
                   (cycle (car c-date))
                   (yy (cadr c-date))
                   (y (+ (* 100 cycle) yy)))
              (diary-chinese-anniversary lunar-month lunar-day y mark))
          (diary-chinese-anniversary lunar-month lunar-day year mark)))
1 个赞

这个如果想提前一周显示应该怎么写?我试了一下<%%(my-diary-chinese-anniversary 2 5) +1y -1w>好像不行

我也报错非法date,你解决了吗?