mhc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/COPYRIGHT +28 -0
- data/Gemfile +8 -0
- data/README.org +209 -0
- data/Rakefile +13 -0
- data/bin/mhc +312 -0
- data/emacs/Cask +25 -0
- data/emacs/Makefile +58 -0
- data/emacs/mhc-calendar.el +1723 -0
- data/emacs/mhc-calfw.el +135 -0
- data/emacs/mhc-compat.el +90 -0
- data/emacs/mhc-date.el +642 -0
- data/emacs/mhc-day.el +149 -0
- data/emacs/mhc-db.el +158 -0
- data/emacs/mhc-draft.el +211 -0
- data/emacs/mhc-e21.el +167 -0
- data/emacs/mhc-face.el +236 -0
- data/emacs/mhc-file.el +224 -0
- data/emacs/mhc-guess.el +648 -0
- data/emacs/mhc-header.el +176 -0
- data/emacs/mhc-logic.el +563 -0
- data/emacs/mhc-message.el +130 -0
- data/emacs/mhc-minibuf.el +466 -0
- data/emacs/mhc-misc.el +248 -0
- data/emacs/mhc-mua.el +260 -0
- data/emacs/mhc-parse.el +286 -0
- data/emacs/mhc-process.el +35 -0
- data/emacs/mhc-ps.el +1174 -0
- data/emacs/mhc-record.el +201 -0
- data/emacs/mhc-schedule.el +202 -0
- data/emacs/mhc-summary.el +763 -0
- data/emacs/mhc-sync.el +158 -0
- data/emacs/mhc-vars.el +149 -0
- data/emacs/mhc.el +1114 -0
- data/icons/Anniversary.xbm +6 -0
- data/icons/Anniversary.xpm +27 -0
- data/icons/Birthday.xbm +6 -0
- data/icons/Birthday.xpm +25 -0
- data/icons/Business.xbm +6 -0
- data/icons/Business.xpm +24 -0
- data/icons/CheckBox.xbm +6 -0
- data/icons/CheckBox.xpm +24 -0
- data/icons/CheckedBox.xbm +6 -0
- data/icons/CheckedBox.xpm +25 -0
- data/icons/Conflict.xbm +6 -0
- data/icons/Conflict.xpm +22 -0
- data/icons/Date.xbm +6 -0
- data/icons/Date.xpm +29 -0
- data/icons/Holiday.xbm +6 -0
- data/icons/Holiday.xpm +25 -0
- data/icons/Link.xbm +6 -0
- data/icons/Link.xpm +25 -0
- data/icons/Other.xbm +6 -0
- data/icons/Other.xpm +28 -0
- data/icons/Party.xbm +6 -0
- data/icons/Party.xpm +23 -0
- data/icons/Private.xbm +6 -0
- data/icons/Private.xpm +26 -0
- data/icons/Recurrence.xbm +6 -0
- data/icons/Recurrence.xpm +98 -0
- data/icons/Vacation.xbm +6 -0
- data/icons/Vacation.xpm +26 -0
- data/lib/mhc.rb +45 -0
- data/lib/mhc/builder.rb +64 -0
- data/lib/mhc/caldav.rb +304 -0
- data/lib/mhc/calendar.rb +106 -0
- data/lib/mhc/command.rb +13 -0
- data/lib/mhc/command/cache.rb +14 -0
- data/lib/mhc/command/completions.rb +108 -0
- data/lib/mhc/command/init.rb +133 -0
- data/lib/mhc/command/scan.rb +33 -0
- data/lib/mhc/command/sync.rb +22 -0
- data/lib/mhc/config.rb +229 -0
- data/lib/mhc/converter.rb +330 -0
- data/lib/mhc/datastore.rb +164 -0
- data/lib/mhc/date_enumerator.rb +274 -0
- data/lib/mhc/date_frame.rb +124 -0
- data/lib/mhc/date_helper.rb +49 -0
- data/lib/mhc/etag.rb +68 -0
- data/lib/mhc/event.rb +396 -0
- data/lib/mhc/formatter.rb +312 -0
- data/lib/mhc/logger.rb +94 -0
- data/lib/mhc/modifier.rb +149 -0
- data/lib/mhc/occurrence.rb +94 -0
- data/lib/mhc/occurrence_enumerator.rb +113 -0
- data/lib/mhc/property_value.rb +33 -0
- data/lib/mhc/property_value/date.rb +190 -0
- data/lib/mhc/property_value/integer.rb +15 -0
- data/lib/mhc/property_value/list.rb +41 -0
- data/lib/mhc/property_value/period.rb +49 -0
- data/lib/mhc/property_value/range.rb +100 -0
- data/lib/mhc/property_value/recurrence_condition.rb +272 -0
- data/lib/mhc/property_value/text.rb +11 -0
- data/lib/mhc/property_value/time.rb +45 -0
- data/lib/mhc/query.rb +210 -0
- data/lib/mhc/sync.rb +46 -0
- data/lib/mhc/sync/driver.rb +108 -0
- data/lib/mhc/sync/status.rb +70 -0
- data/lib/mhc/sync/status_manager.rb +142 -0
- data/lib/mhc/sync/strategy.rb +233 -0
- data/lib/mhc/sync/syncinfo.rb +98 -0
- data/lib/mhc/templates/config.yml.erb +142 -0
- data/lib/mhc/version.rb +4 -0
- data/lib/mhc/webdav.rb +319 -0
- data/mhc.gemspec +24 -0
- data/samples/DOT.mhc-config.yml +116 -0
- data/samples/japanese-holidays.mhcc +153 -0
- data/samples/mhc-completions.zsh +11 -0
- data/spec/mhc_spec.rb +682 -0
- data/spec/spec_helper.rb +9 -0
- data/xpm/close.xpm +18 -0
- data/xpm/delete.xpm +19 -0
- data/xpm/exit.xpm +18 -0
- data/xpm/month.xpm +18 -0
- data/xpm/next.xpm +18 -0
- data/xpm/next2.xpm +18 -0
- data/xpm/next_year.xpm +18 -0
- data/xpm/open.xpm +19 -0
- data/xpm/prev.xpm +18 -0
- data/xpm/prev2.xpm +18 -0
- data/xpm/prev_year.xpm +18 -0
- data/xpm/save.xpm +19 -0
- data/xpm/today.xpm +18 -0
- metadata +214 -0
data/emacs/mhc-calfw.el
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
;;; calfw-mhc.el --- calfw calendar view for mhc
|
2
|
+
|
3
|
+
;; Author: Yoshinari Nomura <nom@quickhack.net>
|
4
|
+
|
5
|
+
;;; Commentary:
|
6
|
+
|
7
|
+
;; setting example:
|
8
|
+
;;
|
9
|
+
;; (require 'calfw)
|
10
|
+
;; (require 'calfw-mhc)
|
11
|
+
;; (require 'calfw-org)
|
12
|
+
;;
|
13
|
+
;; (defun open-calendar ()
|
14
|
+
;; (interactive)
|
15
|
+
;; (cfw:open-calendar-buffer
|
16
|
+
;; :view 'month
|
17
|
+
;; :contents-sources
|
18
|
+
;; (list
|
19
|
+
;; (cfw:org-create-source "Seagreen4")
|
20
|
+
;; (cfw:mhc-create-source "all" "black" "!(Holiday || Birthday)")
|
21
|
+
;; (cfw:mhc-create-source "birthday" "yellow" "Birthday")
|
22
|
+
;; (cfw:mhc-create-source "holiday" "red" "Holiday"))))
|
23
|
+
|
24
|
+
;;; Code:
|
25
|
+
|
26
|
+
(require 'mhc)
|
27
|
+
(require 'calfw)
|
28
|
+
|
29
|
+
(defvar cfw:mhc-text-keymap
|
30
|
+
(let ((map (make-sparse-keymap)))
|
31
|
+
(define-key map [mouse-1] 'cfw:mhc-open-article)
|
32
|
+
(define-key map (kbd "<return>") 'cfw:mhc-open-article)
|
33
|
+
map)
|
34
|
+
"key map on the calendar item text.")
|
35
|
+
|
36
|
+
(defvar cfw:mhc-schedule-map
|
37
|
+
(cfw:define-keymap
|
38
|
+
'(
|
39
|
+
("q" . cfw:mhc-close-article)
|
40
|
+
("SPC" . cfw:mhc-open-article)
|
41
|
+
))
|
42
|
+
"Key map for the mhc calendar mode.")
|
43
|
+
|
44
|
+
(defun cfw:mhc-schedule-cache-clear ())
|
45
|
+
|
46
|
+
(defun cfw:to-mhc-date (date)
|
47
|
+
(mhc-date-new (nth 2 date) (nth 0 date) (nth 1 date)))
|
48
|
+
|
49
|
+
(defun cfw:mhc-to-calfw-date (mhc-date)
|
50
|
+
(mhc-day-let mhc-date
|
51
|
+
(list month day-of-month year)))
|
52
|
+
|
53
|
+
(defun cfw:mhc-make-one-day-entry (day-info &optional category-predicate)
|
54
|
+
(cons
|
55
|
+
(cfw:mhc-to-calfw-date
|
56
|
+
(mhc-day-date day-info))
|
57
|
+
(delq nil
|
58
|
+
(mapcar
|
59
|
+
(lambda (sch)
|
60
|
+
(if (funcall category-predicate sch)
|
61
|
+
(cfw:mhc-make-summary-string sch) nil))
|
62
|
+
(mhc-day-schedules day-info)))))
|
63
|
+
|
64
|
+
(defun blank-p (s)
|
65
|
+
(not (and s (not (string= s "")))))
|
66
|
+
|
67
|
+
;;
|
68
|
+
;; Although mhc has its own formatting functions for this purpose,
|
69
|
+
;; they seems to require some modification to get along with calfw.
|
70
|
+
;; I'm in the mood for fixing the functions in mhc for the
|
71
|
+
;; first time almost in a decade :-)
|
72
|
+
;;
|
73
|
+
(defun cfw:mhc-make-summary-string (schedule)
|
74
|
+
(let ((line
|
75
|
+
(format "%s %s %s"
|
76
|
+
(mhc-schedule-time-as-string schedule)
|
77
|
+
(mhc-schedule-subject-as-string schedule)
|
78
|
+
(if (blank-p (mhc-schedule-location schedule))
|
79
|
+
""
|
80
|
+
(format "[%s]" (mhc-schedule-location schedule))))))
|
81
|
+
(propertize
|
82
|
+
line
|
83
|
+
'keymap cfw:mhc-text-keymap
|
84
|
+
'mhc-schedule schedule)))
|
85
|
+
|
86
|
+
(defun cfw:mhc-schedule-period-to-calendar (begin end &optional category)
|
87
|
+
(let ((category-predicate (mhc-expr-compile category)))
|
88
|
+
(mapcar
|
89
|
+
(lambda (day-info)
|
90
|
+
(cfw:mhc-make-one-day-entry day-info category-predicate))
|
91
|
+
(mhc-db-scan
|
92
|
+
(cfw:to-mhc-date begin)
|
93
|
+
(cfw:to-mhc-date end)
|
94
|
+
'nosort))))
|
95
|
+
|
96
|
+
(defun cfw:mhc-create-source (name &optional color category)
|
97
|
+
(lexical-let ((category category))
|
98
|
+
(make-cfw:source
|
99
|
+
:name (concat "mhc:" name)
|
100
|
+
:color (or color "SteelBlue")
|
101
|
+
:update 'cfw:mhc-schedule-cache-clear
|
102
|
+
:data (lambda (begin end) (cfw:mhc-schedule-period-to-calendar begin end category)))))
|
103
|
+
|
104
|
+
(defun cfw:mhc-close-article ()
|
105
|
+
(interactive)
|
106
|
+
(mhc-window-pop)
|
107
|
+
(kill-buffer))
|
108
|
+
|
109
|
+
(defun cfw:mhc-open-article ()
|
110
|
+
(interactive)
|
111
|
+
(mhc-window-push)
|
112
|
+
(let ((schedule (get-text-property (point) 'mhc-schedule)))
|
113
|
+
(if schedule
|
114
|
+
(cfw:details-popup
|
115
|
+
(with-temp-buffer
|
116
|
+
(insert-file-contents
|
117
|
+
(mhc-record-name (mhc-schedule-record schedule)))
|
118
|
+
(mhc-calendar/view-file-decode-header)
|
119
|
+
(buffer-string)
|
120
|
+
))
|
121
|
+
(message "mhc schedule not found"))))
|
122
|
+
|
123
|
+
(defun cfw:open-mhc-calendar ()
|
124
|
+
(interactive)
|
125
|
+
(cfw:open-calendar-buffer
|
126
|
+
:view 'month
|
127
|
+
:contents-sources
|
128
|
+
(list
|
129
|
+
(cfw:mhc-create-source "all" "black" "!(Holiday | Birthday)")
|
130
|
+
(cfw:mhc-create-source "birthday" "brown" "Birthday")
|
131
|
+
(cfw:mhc-create-source "holiday" "red" "Holiday"))))
|
132
|
+
|
133
|
+
(provide 'mhc-calfw)
|
134
|
+
|
135
|
+
;;; mhc-calfw.el ends here
|
data/emacs/mhc-compat.el
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
;;; -*- mode: Emacs-Lisp; coding: utf-8 -*-
|
2
|
+
|
3
|
+
;; Author: Yoshinari Nomura <nom@quickhack.net>,
|
4
|
+
;; TSUCHIYA Masatoshi <tsuchiya@namazu.org>
|
5
|
+
;; Created: 2000/05/01
|
6
|
+
;; Revised: $Date$
|
7
|
+
|
8
|
+
|
9
|
+
;;; Commentary:
|
10
|
+
|
11
|
+
;; This file is a part of MHC, and includes definitions to absorb
|
12
|
+
;; incompatibilities between emacsen.
|
13
|
+
|
14
|
+
|
15
|
+
;;; Code:
|
16
|
+
|
17
|
+
(if (fboundp 'insert-file-contents-as-coding-system)
|
18
|
+
(defalias 'mhc-insert-file-contents-as-coding-system
|
19
|
+
'insert-file-contents-as-coding-system)
|
20
|
+
(defun mhc-insert-file-contents-as-coding-system
|
21
|
+
(coding-system filename &optional visit beg end replace)
|
22
|
+
"Like `insert-file-contents', q.v., but CODING-SYSTEM the first arg will
|
23
|
+
be applied to `coding-system-for-read'."
|
24
|
+
(let ((coding-system-for-read coding-system)
|
25
|
+
(file-coding-system-for-read coding-system))
|
26
|
+
(insert-file-contents filename visit beg end replace))))
|
27
|
+
|
28
|
+
|
29
|
+
(if (fboundp 'write-region-as-coding-system)
|
30
|
+
(defalias 'mhc-write-region-as-coding-system
|
31
|
+
'write-region-as-coding-system)
|
32
|
+
(defun mhc-write-region-as-coding-system
|
33
|
+
(coding-system start end filename &optional append visit lockname)
|
34
|
+
"Like `write-region', q.v., but CODING-SYSTEM the first arg will be
|
35
|
+
applied to `coding-system-for-write'."
|
36
|
+
(let ((coding-system-for-write coding-system)
|
37
|
+
(file-coding-system coding-system))
|
38
|
+
(write-region start end filename append visit))))
|
39
|
+
|
40
|
+
(if (and (fboundp 'regexp-opt)
|
41
|
+
(not (featurep 'xemacs)))
|
42
|
+
(defalias 'mhc-regexp-opt 'regexp-opt)
|
43
|
+
(defun mhc-regexp-opt (strings &optional paren)
|
44
|
+
"Return a regexp to match a string in STRINGS.
|
45
|
+
Each string should be unique in STRINGS and should not contain any regexps,
|
46
|
+
quoted or not. If optional PAREN is non-nil, ensure that the returned regexp
|
47
|
+
is enclosed by at least one regexp grouping construct."
|
48
|
+
(let ((open-paren (if paren "\\(" "")) (close-paren (if paren "\\)" "")))
|
49
|
+
(concat open-paren (mapconcat 'regexp-quote strings "\\|") close-paren))))
|
50
|
+
|
51
|
+
|
52
|
+
(if (fboundp 'string-to-char-list)
|
53
|
+
(defalias 'mhc-string-to-char-list 'string-to-char-list)
|
54
|
+
(defun mhc-string-to-char-list (string)
|
55
|
+
(string-to-list string)))
|
56
|
+
|
57
|
+
(provide 'mhc-compat)
|
58
|
+
|
59
|
+
;;; Copyright Notice:
|
60
|
+
|
61
|
+
;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
|
62
|
+
;; Copyright (C) 2000 MHC developing team. All rights reserved.
|
63
|
+
|
64
|
+
;; Redistribution and use in source and binary forms, with or without
|
65
|
+
;; modification, are permitted provided that the following conditions
|
66
|
+
;; are met:
|
67
|
+
;;
|
68
|
+
;; 1. Redistributions of source code must retain the above copyright
|
69
|
+
;; notice, this list of conditions and the following disclaimer.
|
70
|
+
;; 2. Redistributions in binary form must reproduce the above copyright
|
71
|
+
;; notice, this list of conditions and the following disclaimer in the
|
72
|
+
;; documentation and/or other materials provided with the distribution.
|
73
|
+
;; 3. Neither the name of the team nor the names of its contributors
|
74
|
+
;; may be used to endorse or promote products derived from this software
|
75
|
+
;; without specific prior written permission.
|
76
|
+
;;
|
77
|
+
;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
|
78
|
+
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
79
|
+
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
80
|
+
;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
81
|
+
;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
82
|
+
;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
83
|
+
;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
84
|
+
;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
85
|
+
;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
86
|
+
;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
87
|
+
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
88
|
+
;; OF THE POSSIBILITY OF SUCH DAMAGE.
|
89
|
+
|
90
|
+
;;; mhc-compat.el ends here
|
data/emacs/mhc-date.el
ADDED
@@ -0,0 +1,642 @@
|
|
1
|
+
;;; mhc-date.el -- Digit style Date Calculation Lib.
|
2
|
+
|
3
|
+
;; Author: Yoshinari Nomura <nom@quickhack.net>,
|
4
|
+
;; TSUCHIYA Masatoshi <tsuchiya@namazu.org>
|
5
|
+
;;
|
6
|
+
;; Created: 2000/06/14
|
7
|
+
;; Revised: $Date: 2004/05/06 16:35:13 $
|
8
|
+
|
9
|
+
;;;
|
10
|
+
;;; Commentary:
|
11
|
+
;;;
|
12
|
+
|
13
|
+
;;
|
14
|
+
;; mhc-date format is simple. It expresses a date by
|
15
|
+
;; days from 1970/1/1
|
16
|
+
;;
|
17
|
+
;; for example:
|
18
|
+
;;
|
19
|
+
;; (mhc-date-new 1970 1 1) -> 0
|
20
|
+
;; (mhc-date-new 2000 6 14) -> 11122
|
21
|
+
;;
|
22
|
+
;; mhc-time is also simple. It expresses a time by minits from midnight.
|
23
|
+
|
24
|
+
;;;
|
25
|
+
;;; Code:
|
26
|
+
;;;
|
27
|
+
|
28
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
29
|
+
;;; mhc-time
|
30
|
+
|
31
|
+
(defsubst mhc-time/check (HH MM)
|
32
|
+
(and (integerp HH) (>= HH 0) (<= HH 99)
|
33
|
+
(integerp MM) (>= MM 0) (<= MM 59)))
|
34
|
+
|
35
|
+
(defmacro mhc-time-HH (time)
|
36
|
+
`(/ ,time 60))
|
37
|
+
|
38
|
+
(defmacro mhc-time-MM (time)
|
39
|
+
`(% ,time 60))
|
40
|
+
|
41
|
+
;; All constructors emit error signal if args are illegal.
|
42
|
+
;; In case called with noerror is t, return nil quietly.
|
43
|
+
|
44
|
+
(defsubst mhc-time-new (HH MM &optional noerror)
|
45
|
+
(if (mhc-time/check HH MM)
|
46
|
+
(+ (* HH 60) MM)
|
47
|
+
(if noerror
|
48
|
+
nil
|
49
|
+
(error "mhc-time-new: arg error (%s,%s)" HH MM))))
|
50
|
+
|
51
|
+
(defsubst mhc-time-new-from-string (str &optional noerror regexp)
|
52
|
+
(let (ret (match (match-data)))
|
53
|
+
(if (string-match (or regexp "^\\([0-9][0-9]\\):\\([0-9][0-9]\\)$") str)
|
54
|
+
(setq ret (mhc-time-new (mhc-date/substring-to-int str 1)
|
55
|
+
(mhc-date/substring-to-int str 2)
|
56
|
+
t)))
|
57
|
+
(store-match-data match)
|
58
|
+
(if (or noerror ret)
|
59
|
+
ret
|
60
|
+
(error "mhc-time-new-from-string: format error (%s)" str))))
|
61
|
+
|
62
|
+
(defsubst mhc-time-now ()
|
63
|
+
(let* ((now (decode-time (current-time)))
|
64
|
+
(HH (nth 2 now))
|
65
|
+
(MM (nth 1 now)))
|
66
|
+
(mhc-time-new HH MM)))
|
67
|
+
|
68
|
+
;; xxx: use defmacro for speed !!
|
69
|
+
(defalias 'mhc-time-max 'max)
|
70
|
+
(defalias 'mhc-time-min 'min)
|
71
|
+
(defalias 'mhc-time< '<)
|
72
|
+
(defalias 'mhc-time= '=)
|
73
|
+
(defalias 'mhc-time<= '<=)
|
74
|
+
(defalias 'mhc-time> '>)
|
75
|
+
(defalias 'mhc-time>= '>=)
|
76
|
+
|
77
|
+
(defun mhc-time-sort (time-list)
|
78
|
+
(sort time-list (function mhc-time<)))
|
79
|
+
|
80
|
+
(defmacro mhc-time-let (time &rest form)
|
81
|
+
(let ((tempvar (make-symbol "tempvar")))
|
82
|
+
`(let* ((,tempvar ,time)
|
83
|
+
(hh (mhc-time-HH ,tempvar))
|
84
|
+
(mm (mhc-time-MM ,tempvar)))
|
85
|
+
,@form)))
|
86
|
+
(put 'mhc-time-let 'lisp-indent-function 1)
|
87
|
+
(put 'mhc-time-let 'edebug-form-spec '(form body))
|
88
|
+
|
89
|
+
(defmacro mhc-time-to-string (time)
|
90
|
+
`(mhc-time-let ,time (format "%02d:%02d" hh mm)))
|
91
|
+
|
92
|
+
(defsubst mhc-time-to-list (time)
|
93
|
+
(list (mhc-time-HH time)
|
94
|
+
(mhc-time-MM time)))
|
95
|
+
|
96
|
+
(defalias 'mhc-time+ '+)
|
97
|
+
(defalias 'mhc-time- '-)
|
98
|
+
|
99
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
100
|
+
;;; mhc-date
|
101
|
+
|
102
|
+
;;
|
103
|
+
;; special form.
|
104
|
+
;;
|
105
|
+
|
106
|
+
(defmacro mhc-date-let (date &rest form) "\
|
107
|
+
This special form converts DATE, as the number of days since
|
108
|
+
1970/01/01, to following local variables, and evaluates FORM.
|
109
|
+
|
110
|
+
yy The year, an integer typically greater than 1900.
|
111
|
+
mm The month of the year, as an integer between 1 and 12.
|
112
|
+
dd The day of the month, as an integer between 1 and 31.
|
113
|
+
ww The day of week, as an integer between 0 and 6, where 0
|
114
|
+
stands for Sunday.
|
115
|
+
"
|
116
|
+
(let ((tempvar (make-symbol "tempvar")))
|
117
|
+
`(let* ((,tempvar (mhc-date-to-list ,date))
|
118
|
+
(yy (nth 0 ,tempvar))
|
119
|
+
(mm (nth 1 ,tempvar))
|
120
|
+
(dd (nth 2 ,tempvar))
|
121
|
+
(ww (nth 3 ,tempvar)))
|
122
|
+
,@form)))
|
123
|
+
(put 'mhc-date-let 'lisp-indent-function 1)
|
124
|
+
(put 'mhc-date-let 'edebug-form-spec '(form body))
|
125
|
+
|
126
|
+
|
127
|
+
(defmacro mhc-date-let-for-month (date &rest form) "\
|
128
|
+
This special form converts DATE, as the number of days since
|
129
|
+
1970/01/01, to following local variables, and evaluates FORM.
|
130
|
+
|
131
|
+
yy The year, an integer typically greater than 1900.
|
132
|
+
mm The month of the year, as an integer between 1 and 12.
|
133
|
+
dd The day of the month, as an integer between 1 and 31.
|
134
|
+
ww The day of week, as an integer between 0 and 6, where 0
|
135
|
+
stands for Sunday.
|
136
|
+
oo The order of week, as an integer between 0 and 4.
|
137
|
+
last-p Predicate to check if the dd is in the last week.
|
138
|
+
"
|
139
|
+
(let ((tempvar (make-symbol "tempvar")))
|
140
|
+
`(let* ((,tempvar (mhc-date-to-list ,date))
|
141
|
+
(yy (nth 0 ,tempvar))
|
142
|
+
(mm (nth 1 ,tempvar))
|
143
|
+
(dd 1)
|
144
|
+
(ww (nth 3 ,tempvar))
|
145
|
+
(end (mhc-date/last-day-of-month yy mm))
|
146
|
+
(days ,date)
|
147
|
+
(last-p nil))
|
148
|
+
(while (<= dd end)
|
149
|
+
,@form
|
150
|
+
(setq days (mhc-date++ days)
|
151
|
+
dd (1+ dd)
|
152
|
+
oo (/ (1- dd) 7)
|
153
|
+
ww (% (1+ ww) 7)
|
154
|
+
last-p (< (- end 7) dd))))))
|
155
|
+
(put 'mhc-date-let-for-month 'lisp-indent-function 1)
|
156
|
+
(put 'mhc-date-let-for-month 'edebug-form-spec '(form body))
|
157
|
+
|
158
|
+
|
159
|
+
;;
|
160
|
+
;; private
|
161
|
+
;;
|
162
|
+
|
163
|
+
(defsubst mhc-date/leap-year-p (yy)
|
164
|
+
(and (zerop (% yy 4))
|
165
|
+
(or (not (zerop (% yy 100)))
|
166
|
+
(zerop (% yy 400)))))
|
167
|
+
|
168
|
+
(defsubst mhc-date/last-day-of-month (yy mm)
|
169
|
+
(if (and (= mm 2) (mhc-date/leap-year-p yy))
|
170
|
+
29
|
171
|
+
(aref '[0 31 28 31 30 31 30 31 31 30 31 30 31] mm)))
|
172
|
+
|
173
|
+
(defsubst mhc-date/check (yy mm dd)
|
174
|
+
(and (integerp yy) (>= yy 1000)
|
175
|
+
(integerp mm) (>= mm 1) (<= mm 12)
|
176
|
+
(integerp dd) (>= dd 1) (<= dd (mhc-date/last-day-of-month yy mm))
|
177
|
+
t))
|
178
|
+
|
179
|
+
(defmacro mhc-date/day-number (yy mm dd)
|
180
|
+
`(if (mhc-date/leap-year-p ,yy)
|
181
|
+
(+ (aref '[0 0 31 60 91 121 152 182 213 244 274 305 335] ,mm) ,dd)
|
182
|
+
(+ (aref '[0 0 31 59 90 120 151 181 212 243 273 304 334] ,mm) ,dd)))
|
183
|
+
|
184
|
+
(defsubst mhc-date/absolute-from-epoch (yy mm dd)
|
185
|
+
(let ((xx (1- yy)))
|
186
|
+
(+ (mhc-date/day-number yy mm dd)
|
187
|
+
(* xx 365)
|
188
|
+
(/ xx 4)
|
189
|
+
(/ xx -100)
|
190
|
+
(/ xx 400)
|
191
|
+
-719163)))
|
192
|
+
|
193
|
+
(defsubst mhc-date/iso-week-days (yday wday)
|
194
|
+
(- yday -3 (% (- yday wday -382) 7)))
|
195
|
+
|
196
|
+
(defmacro mhc-date/substring-to-int (str pos)
|
197
|
+
`(string-to-number
|
198
|
+
(substring ,str (match-beginning ,pos) (match-end ,pos))))
|
199
|
+
|
200
|
+
;; according to our current time zone,
|
201
|
+
;; convert timezone string into offset minutes
|
202
|
+
;;
|
203
|
+
;; for example, if current time zone is in Japan,
|
204
|
+
;; convert "GMT" or "+0000" into 540.
|
205
|
+
(defun mhc-date/string-to-timezone-offset (timezone)
|
206
|
+
(let ((tz (or (cdr (assoc timezone
|
207
|
+
'(("PST" . "-0800") ("PDT" . "-0700")
|
208
|
+
("MST" . "-0700") ("MDT" . "-0600")
|
209
|
+
("CST" . "-0600") ("CDT" . "-0500")
|
210
|
+
("EST" . "-0500") ("EDT" . "-0400")
|
211
|
+
("AST" . "-0400") ("NST" . "-0300")
|
212
|
+
("UT" . "+0000") ("GMT" . "+0000")
|
213
|
+
("BST" . "+0100") ("MET" . "+0100")
|
214
|
+
("EET" . "+0200") ("JST" . "+0900"))))
|
215
|
+
timezone))
|
216
|
+
min
|
217
|
+
offset)
|
218
|
+
(if (string-match "\\([-+]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" tz)
|
219
|
+
(progn
|
220
|
+
(setq min (* (+ (* 60 (mhc-date/substring-to-int tz 2))
|
221
|
+
(mhc-date/substring-to-int tz 3))
|
222
|
+
(if (string= "+"
|
223
|
+
(substring tz
|
224
|
+
(match-beginning 1)
|
225
|
+
(match-end 1)))
|
226
|
+
1 -1))
|
227
|
+
offset (- (/ (car (current-time-zone)) 60) min))))))
|
228
|
+
|
229
|
+
;;
|
230
|
+
;; conversion.
|
231
|
+
;;
|
232
|
+
|
233
|
+
(defsubst mhc-date-to-second (date)
|
234
|
+
;; It has workaround in case of 28 bit integer.
|
235
|
+
(let (high low)
|
236
|
+
(setq low (* (+ date (if (< (nth 0 (current-time-zone)) 0) 1 0)) 240)
|
237
|
+
high (/ low 65536)
|
238
|
+
low (* (% low 65536) 360)
|
239
|
+
high (+ (* high 360) (/ low 65536))
|
240
|
+
low (% low 65536))
|
241
|
+
(list high low 0)))
|
242
|
+
|
243
|
+
|
244
|
+
(defsubst mhc-date/to-list1 (date)
|
245
|
+
(let ((lst (decode-time (mhc-date-to-second date))))
|
246
|
+
(list (nth 5 lst)
|
247
|
+
(nth 4 lst)
|
248
|
+
(nth 3 lst)
|
249
|
+
(nth 6 lst))))
|
250
|
+
|
251
|
+
(defsubst mhc-date/to-list2 (date)
|
252
|
+
(let (x b c d e w dom)
|
253
|
+
(setq w (% (+ date 25568) 7)
|
254
|
+
date (+ date 2440588)
|
255
|
+
x (floor (/ (- date 1867216.25) 36524.25))
|
256
|
+
b (- (+ date 1525 x) (floor (/ x 4.0)))
|
257
|
+
c (floor (/ (- b 122.1) 365.25))
|
258
|
+
d (floor (* 365.25 c))
|
259
|
+
e (floor (/ (- b d) 30.6001))
|
260
|
+
dom (- b d (floor (* 30.6001 e))))
|
261
|
+
(if (<= e 13)
|
262
|
+
(list (- c 4716) (1- e) dom w)
|
263
|
+
(list (- c 4715) (- e 13) dom w))))
|
264
|
+
|
265
|
+
(defsubst mhc-date-to-list (date)
|
266
|
+
(if (and (<= 0 date) (<= date 24837))
|
267
|
+
(mhc-date/to-list1 date)
|
268
|
+
(mhc-date/to-list2 date)))
|
269
|
+
|
270
|
+
;;
|
271
|
+
;; constructor.
|
272
|
+
;;
|
273
|
+
|
274
|
+
;; All constructors emit error signal if args are illegal.
|
275
|
+
;; In case called with noerror is t, return nil quietly.
|
276
|
+
|
277
|
+
;; new from 3 digits.
|
278
|
+
(defsubst mhc-date-new (yy mm dd &optional noerror)
|
279
|
+
(if (mhc-date/check yy mm dd)
|
280
|
+
(mhc-date/absolute-from-epoch yy mm dd)
|
281
|
+
(if noerror
|
282
|
+
nil
|
283
|
+
(error "mhc-date-new: arg error (%s,%s,%s)" yy mm dd))))
|
284
|
+
|
285
|
+
|
286
|
+
;; new from emacs style time such as (14654 3252 689999).
|
287
|
+
(defsubst mhc-date-new-from-second (&optional second)
|
288
|
+
(let ((now (decode-time (or second (current-time)))))
|
289
|
+
(mhc-date/absolute-from-epoch
|
290
|
+
(nth 5 now)
|
291
|
+
(nth 4 now)
|
292
|
+
(nth 3 now))))
|
293
|
+
|
294
|
+
;; new from current time.
|
295
|
+
(defalias 'mhc-date-now 'mhc-date-new-from-second)
|
296
|
+
|
297
|
+
;; new from string. 19990101
|
298
|
+
(defsubst mhc-date-new-from-string (str &optional noerror)
|
299
|
+
(let (ret (match (match-data)))
|
300
|
+
(if (string-match
|
301
|
+
"^\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)$" str)
|
302
|
+
(setq ret (mhc-date-new (mhc-date/substring-to-int str 1)
|
303
|
+
(mhc-date/substring-to-int str 2)
|
304
|
+
(mhc-date/substring-to-int str 3)
|
305
|
+
t)))
|
306
|
+
(store-match-data match)
|
307
|
+
(if (or noerror ret)
|
308
|
+
ret
|
309
|
+
(error "mhc-date-new-from-string: format error (%s)" str))))
|
310
|
+
|
311
|
+
;; new from string. [[yyyy/]mm]/dd
|
312
|
+
(defsubst mhc-date-new-from-string2 (str &optional base-date noerror)
|
313
|
+
(mhc-date-let (or base-date (mhc-date-now))
|
314
|
+
(let ((match (match-data)) fail ret)
|
315
|
+
(cond
|
316
|
+
((string-match
|
317
|
+
"^\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)$" str)
|
318
|
+
(setq yy (mhc-date/substring-to-int str 1)
|
319
|
+
mm (mhc-date/substring-to-int str 2)
|
320
|
+
dd (mhc-date/substring-to-int str 3)))
|
321
|
+
((string-match "^\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)$" str)
|
322
|
+
(setq yy (mhc-date/substring-to-int str 1)
|
323
|
+
mm (mhc-date/substring-to-int str 2)
|
324
|
+
dd (mhc-date/substring-to-int str 3)))
|
325
|
+
((string-match "^\\([0-9]+\\)/\\([0-9]+\\)$" str)
|
326
|
+
(setq mm (mhc-date/substring-to-int str 1)
|
327
|
+
dd (mhc-date/substring-to-int str 2)))
|
328
|
+
((string-match "^\\([0-9]+\\)$" str)
|
329
|
+
(setq dd (mhc-date/substring-to-int str 1)))
|
330
|
+
(t
|
331
|
+
(setq fail t)))
|
332
|
+
(store-match-data match)
|
333
|
+
(if (not fail) (setq ret (mhc-date-new yy mm dd t)))
|
334
|
+
(if (or noerror ret)
|
335
|
+
ret
|
336
|
+
(error "mhc-date-new-from-string2: format error (%s)" str)))))
|
337
|
+
|
338
|
+
;; regexp for rfc822 Date: field.
|
339
|
+
(defconst mhc-date/rfc822-date-regex
|
340
|
+
;; assuming ``Tue, 9 May 2000 12:15:12 -0700 (PDT)''
|
341
|
+
(concat
|
342
|
+
"\\([0-9]+\\)[ \t]+" ;; day
|
343
|
+
"\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|" ;;
|
344
|
+
"Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ \t]+" ;; month
|
345
|
+
"\\([0-9]+\\)[ \t]+" ;; year
|
346
|
+
"\\([0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?[ \t]*" ;; hh:mm(:ss)?
|
347
|
+
"\\([A-Z][A-Z][A-Z]\\|[-+][0-9][0-9][0-9][0-9]\\)" ;; JST or +0900
|
348
|
+
))
|
349
|
+
|
350
|
+
;; new from rfc822 Date: field.
|
351
|
+
(defun mhc-date-new-from-string3 (string)
|
352
|
+
(if (and (stringp string) (string-match mhc-date/rfc822-date-regex string))
|
353
|
+
(let ((dd (mhc-date/substring-to-int string 1))
|
354
|
+
(mm nil)
|
355
|
+
(mon (substring string (match-beginning 2) (match-end 2)))
|
356
|
+
(yy (mhc-date/substring-to-int string 3))
|
357
|
+
(MM (+ (* 60 (mhc-date/substring-to-int string 4))
|
358
|
+
(mhc-date/substring-to-int string 5)))
|
359
|
+
(tz (substring string (match-beginning 8) (match-end 8)))
|
360
|
+
tz-offset)
|
361
|
+
(setq
|
362
|
+
yy (cond
|
363
|
+
((< yy 50) (+ yy 2000))
|
364
|
+
((< yy 100) (+ yy 1900))
|
365
|
+
(t yy))
|
366
|
+
mm (1+ (/ (string-match mon
|
367
|
+
"JanFebMarAprMayJunJulAugSepOctNovDec") 3))
|
368
|
+
tz-offset (mhc-date/string-to-timezone-offset tz)
|
369
|
+
MM (+ MM tz-offset))
|
370
|
+
(car
|
371
|
+
(cond
|
372
|
+
((< MM 0)
|
373
|
+
(setq MM (+ MM 1440))
|
374
|
+
(list (mhc-date-- (mhc-date-new yy mm dd))
|
375
|
+
(mhc-time-new (/ MM 60) (% MM 60))
|
376
|
+
tz-offset))
|
377
|
+
((>= MM 1440)
|
378
|
+
(setq MM (- MM 1440))
|
379
|
+
(list (mhc-date++ (mhc-date-new yy mm dd))
|
380
|
+
(mhc-time-new (/ MM 60) (% MM 60))
|
381
|
+
tz-offset))
|
382
|
+
(t
|
383
|
+
(list (mhc-date-new yy mm dd)
|
384
|
+
(mhc-time-new (/ MM 60) (% MM 60))
|
385
|
+
tz-offset)))))))
|
386
|
+
|
387
|
+
;;
|
388
|
+
;; manipulate yy, mm, dd.
|
389
|
+
;;
|
390
|
+
|
391
|
+
(defmacro mhc-date-yy (date)
|
392
|
+
`(nth 0 (mhc-date-to-list ,date)))
|
393
|
+
|
394
|
+
(defmacro mhc-date-mm (date)
|
395
|
+
`(nth 1 (mhc-date-to-list ,date)))
|
396
|
+
|
397
|
+
(defmacro mhc-date-dd (date)
|
398
|
+
`(nth 2 (mhc-date-to-list ,date)))
|
399
|
+
|
400
|
+
(defmacro mhc-date-ww (date)
|
401
|
+
`(nth 3 (mhc-date-to-list ,date)))
|
402
|
+
|
403
|
+
(defmacro mhc-date-oo (date)
|
404
|
+
`(/ (1- (mhc-date-dd ,date)) 7))
|
405
|
+
|
406
|
+
(defsubst mhc-date-cw (date)
|
407
|
+
(mhc-date-let date
|
408
|
+
(let* ((yday (mhc-date/day-number yy mm dd))
|
409
|
+
(days (mhc-date/iso-week-days yday ww))
|
410
|
+
(d))
|
411
|
+
(if (< days 0)
|
412
|
+
(setq days (mhc-date/iso-week-days
|
413
|
+
(+ yday 365 (if (mhc-date/leap-year-p (1- yy)) 1 0)) ww))
|
414
|
+
(setq d (mhc-date/iso-week-days
|
415
|
+
(- yday 365 (if (mhc-date/leap-year-p yy) 1 0)) ww))
|
416
|
+
(if (<= 0 d) (setq days d)))
|
417
|
+
(1+ (/ days 7)))))
|
418
|
+
|
419
|
+
;;
|
420
|
+
;; compare.
|
421
|
+
;;
|
422
|
+
|
423
|
+
(defalias 'mhc-date= '= )
|
424
|
+
(defalias 'mhc-date< '< )
|
425
|
+
(defalias 'mhc-date<= '<= )
|
426
|
+
(defalias 'mhc-date> '> )
|
427
|
+
(defalias 'mhc-date>= '>= )
|
428
|
+
|
429
|
+
(defalias 'mhc-date-max 'max)
|
430
|
+
(defalias 'mhc-date-min 'min)
|
431
|
+
(defmacro mhc-date-sort (date-list)
|
432
|
+
`(sort ,date-list (function mhc-date<)))
|
433
|
+
|
434
|
+
(defsubst mhc-date-yy= (d1 d2) (= (mhc-date-yy d1) (mhc-date-yy d2)))
|
435
|
+
(defsubst mhc-date-yy< (d1 d2) (< (mhc-date-yy d1) (mhc-date-yy d2)))
|
436
|
+
(defsubst mhc-date-yy<= (d1 d2) (<= (mhc-date-yy d1) (mhc-date-yy d2)))
|
437
|
+
(defsubst mhc-date-yy> (d1 d2) (mhc-date-yy< d2 d1))
|
438
|
+
(defsubst mhc-date-yy>= (d1 d2) (mhc-date-yy<= d2 d1))
|
439
|
+
|
440
|
+
(defsubst mhc-date-yymm= (d1 d2)
|
441
|
+
(and (mhc-date-yy= d1 d2)
|
442
|
+
(= (mhc-date-mm d1) (mhc-date-mm d2))))
|
443
|
+
|
444
|
+
(defsubst mhc-date-yymm< (d1 d2)
|
445
|
+
(or (mhc-date-yy< d1 d2)
|
446
|
+
(and (mhc-date-yy= d1 d2)
|
447
|
+
(< (mhc-date-mm d1) (mhc-date-mm d2)))))
|
448
|
+
|
449
|
+
(defmacro mhc-date-yymm> (d1 d2) `(mhc-date-yymm< ,d2 ,d1))
|
450
|
+
(defmacro mhc-date-yymm<= (d1 d2) `(not (mhc-date-yymm> ,d1 ,d2)))
|
451
|
+
(defmacro mhc-date-yymm>= (d1 d2) `(mhc-date-yymm<= ,d2 ,d1))
|
452
|
+
|
453
|
+
;;
|
454
|
+
;; increment, decrement.
|
455
|
+
;;
|
456
|
+
|
457
|
+
(defalias 'mhc-date+ '+ )
|
458
|
+
(defalias 'mhc-date- '- )
|
459
|
+
(defalias 'mhc-date++ '1+)
|
460
|
+
(defalias 'mhc-date-- '1-)
|
461
|
+
|
462
|
+
(defsubst mhc-date-mm+ (date c)
|
463
|
+
(mhc-date-let date
|
464
|
+
(let (xx pp)
|
465
|
+
(setq xx (+ mm c))
|
466
|
+
(setq pp (if (< 0 xx ) (/ (- xx 1) 12) (/ (- xx 12) 12)))
|
467
|
+
(setq yy (+ yy pp) mm (- xx (* 12 pp)))
|
468
|
+
(if (mhc-date/check yy mm dd)
|
469
|
+
(mhc-date-new yy mm dd)
|
470
|
+
(mhc-date-new yy mm (mhc-date/last-day-of-month yy mm))))))
|
471
|
+
|
472
|
+
(defmacro mhc-date-mm- (date c) `(mhc-date-mm+ ,date (- ,c)))
|
473
|
+
(defmacro mhc-date-mm++ (date) `(mhc-date-mm+ ,date 1))
|
474
|
+
(defmacro mhc-date-mm-- (date) `(mhc-date-mm- ,date 1))
|
475
|
+
|
476
|
+
(defsubst mhc-date-yy+ (date c)
|
477
|
+
(mhc-date-let date
|
478
|
+
(setq yy (+ yy c))
|
479
|
+
(if (mhc-date/check yy mm dd)
|
480
|
+
(mhc-date-new yy mm dd)
|
481
|
+
(mhc-date-new yy mm (mhc-date/last-day-of-month yy mm)))))
|
482
|
+
|
483
|
+
(defmacro mhc-date-yy- (date c) `(mhc-date-yy+ ,date (- ,c)))
|
484
|
+
(defmacro mhc-date-yy++ (date) `(mhc-date-yy+ ,date 1))
|
485
|
+
(defmacro mhc-date-yy-- (date) `(mhc-date-yy- ,date 1))
|
486
|
+
|
487
|
+
;;
|
488
|
+
;; get meaninful date.
|
489
|
+
;;
|
490
|
+
(defmacro mhc-date-mm-first (date)
|
491
|
+
"Return the number of days since 1970/01/01 to the first day of month, DATE."
|
492
|
+
`(mhc-date-let ,date
|
493
|
+
(mhc-date-new yy mm 1 t)))
|
494
|
+
|
495
|
+
(defmacro mhc-date-mm-last (date)
|
496
|
+
"Return the number of days since 1970/01/01 to the last day of month, DATE."
|
497
|
+
`(mhc-date-let ,date
|
498
|
+
(mhc-date-new yy mm (mhc-date/last-day-of-month yy mm) t)))
|
499
|
+
|
500
|
+
(defun mhc-date-ww-first (date &optional wkst)
|
501
|
+
"Return the first day of week immediate before DATE.
|
502
|
+
WKST specifies start day of week (0:Sunday...6:Saturday).
|
503
|
+
If WKST is not specified, 0 (Sunday) is used."
|
504
|
+
(setq wkst (or wkst 0))
|
505
|
+
(mhc-date- date (mod (- (mhc-date-ww date) wkst) 7)))
|
506
|
+
|
507
|
+
(defun mhc-date-ww-last (date &optional wkst)
|
508
|
+
"Return the last day of week immediate after DATE.
|
509
|
+
WKST specifies start day of week (0:Sunday...6:Saturday).
|
510
|
+
If WKST is not specified, 0 (Sunday) is used."
|
511
|
+
(mhc-date+ (mhc-date-ww-first date wkst) 6))
|
512
|
+
|
513
|
+
;;
|
514
|
+
;; predicate
|
515
|
+
;;
|
516
|
+
|
517
|
+
;; check if the date is in the last week of a month.
|
518
|
+
(defsubst mhc-date-oo-last-p (date)
|
519
|
+
(< (- (mhc-date/last-day-of-month
|
520
|
+
(mhc-date-yy date)
|
521
|
+
(mhc-date-mm date)) 7) (mhc-date-dd date)))
|
522
|
+
|
523
|
+
|
524
|
+
(defalias 'mhc-date-p 'integerp)
|
525
|
+
|
526
|
+
|
527
|
+
;;
|
528
|
+
;; miscellaneous.
|
529
|
+
;;
|
530
|
+
|
531
|
+
(defmacro mhc-end-day-of-week ()
|
532
|
+
`(nth mhc-start-day-of-week '(6 0 1 2 3 4 5)))
|
533
|
+
|
534
|
+
;;
|
535
|
+
;; to string.
|
536
|
+
;;
|
537
|
+
|
538
|
+
;; (mhc-date-format date "%04d%02d%02d" yy mm dd)
|
539
|
+
(defmacro mhc-date-format (date format &rest vars)
|
540
|
+
`(mhc-date-let ,date
|
541
|
+
(format ,format ,@vars)))
|
542
|
+
|
543
|
+
(defun mhc-date-digit-to-mm-string (mm &optional long)
|
544
|
+
(if long
|
545
|
+
(aref
|
546
|
+
'[nil "January" "February" "March" "April" "May" "June"
|
547
|
+
"July" "August" "September" "October" "November" "December"]
|
548
|
+
mm)
|
549
|
+
(aref
|
550
|
+
[nil "Jan" "Feb" "Mar" "Apr" "May" "Jun"
|
551
|
+
"Jul" "Aug" "Sep" "Oct" "Nov" "Dec"]
|
552
|
+
mm)))
|
553
|
+
|
554
|
+
(defun mhc-date-digit-to-ww-string (ww &optional long)
|
555
|
+
(if long
|
556
|
+
(aref ["Sunday" "Monday" "Tuesday" "Wednesday"
|
557
|
+
"Thursday" "Friday" "Saturday"] ww)
|
558
|
+
(aref ["Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat"] ww)))
|
559
|
+
|
560
|
+
(defun mhc-date-digit-to-ww-japanese-string (ww &optional long)
|
561
|
+
(if long
|
562
|
+
(aref ["日曜日" "月曜日" "火曜日" "水曜日"
|
563
|
+
"木曜日" "金曜日" "土曜日"] ww)
|
564
|
+
(aref ["日" "月" "火" "水" "木" "金" "土"] ww)))
|
565
|
+
|
566
|
+
(defun mhc-date-digit-to-oo-string (oo &optional long)
|
567
|
+
(aref ["1st" "2nd" "3rd" "4th" "5th"] oo))
|
568
|
+
|
569
|
+
;; format-time-string subset (but has enough spec)
|
570
|
+
(defun mhc-date-format-time-string (format date)
|
571
|
+
(mhc-date-let date
|
572
|
+
(let (head match (ret "") char)
|
573
|
+
(while (string-match "%." format)
|
574
|
+
(setq head (substring format 0 (match-beginning 0))
|
575
|
+
match (match-string 0 format)
|
576
|
+
format (substring format (match-end 0))
|
577
|
+
char (aref match 1))
|
578
|
+
(cond
|
579
|
+
((eq char ?Y) ;; 100年単位の年
|
580
|
+
(setq match (format "%d" yy)))
|
581
|
+
|
582
|
+
((eq char ?y) ;; 年の下2桁 (00-99)
|
583
|
+
(setq match (format "%02d" (% yy 100))))
|
584
|
+
|
585
|
+
((or (eq char ?b) (eq char ?h)) ;; 月 略称
|
586
|
+
(setq match (mhc-date-digit-to-mm-string mm)))
|
587
|
+
|
588
|
+
((eq char ?B) ;; 月 名称
|
589
|
+
(setq match (mhc-date-digit-to-mm-string mm t)))
|
590
|
+
|
591
|
+
((eq char ?m) ;; 月 (01-12)
|
592
|
+
(setq match (format "%02d" mm)))
|
593
|
+
|
594
|
+
((eq char ?d) ;; 日 (ゼロ padding)
|
595
|
+
(setq match (format "%02d" dd)))
|
596
|
+
|
597
|
+
((eq char ?e) ;; 日 (空白 padding)
|
598
|
+
(setq match (format "%2d" dd)))
|
599
|
+
|
600
|
+
((eq char ?a) ;; 曜日 略称
|
601
|
+
(setq match (mhc-date-digit-to-ww-string ww)))
|
602
|
+
|
603
|
+
((eq char ?A) ;; 曜日 名称
|
604
|
+
(setq match (mhc-date-digit-to-ww-string ww t))))
|
605
|
+
|
606
|
+
(setq ret (concat ret head match)))
|
607
|
+
(concat ret format))))
|
608
|
+
|
609
|
+
(provide 'mhc-date)
|
610
|
+
|
611
|
+
;;; Copyright Notice:
|
612
|
+
|
613
|
+
;; Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
|
614
|
+
;; Copyright (C) 2000 MHC developing team. All rights reserved.
|
615
|
+
|
616
|
+
;; Redistribution and use in source and binary forms, with or without
|
617
|
+
;; modification, are permitted provided that the following conditions
|
618
|
+
;; are met:
|
619
|
+
;;
|
620
|
+
;; 1. Redistributions of source code must retain the above copyright
|
621
|
+
;; notice, this list of conditions and the following disclaimer.
|
622
|
+
;; 2. Redistributions in binary form must reproduce the above copyright
|
623
|
+
;; notice, this list of conditions and the following disclaimer in the
|
624
|
+
;; documentation and/or other materials provided with the distribution.
|
625
|
+
;; 3. Neither the name of the team nor the names of its contributors
|
626
|
+
;; may be used to endorse or promote products derived from this software
|
627
|
+
;; without specific prior written permission.
|
628
|
+
;;
|
629
|
+
;; THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
|
630
|
+
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
631
|
+
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
632
|
+
;; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
633
|
+
;; THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
634
|
+
;; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
635
|
+
;; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
636
|
+
;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
637
|
+
;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
638
|
+
;; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
639
|
+
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
640
|
+
;; OF THE POSSIBILITY OF SUCH DAMAGE.
|
641
|
+
|
642
|
+
;;; mhc-date.el ends here.
|