comparison lisp/calendar/icalendar.el @ 95273:4d3975347028

Ulf Jasper <ulf.jasper at web.de> (icalendar-version): Increase to "0.19". (icalendar--date-style): New function. (icalendar--datetime-to-diary-date): Doc fix. Use icalendar--date-style. (icalendar--datestring-to-isodate): Doc fix. Handle iso date style. (icalendar--convert-yearly-to-ical): (icalendar--convert-recurring-to-diary): Handle iso date style, use icalendar-date-style.
author Glenn Morris <rgm@gnu.org>
date Sat, 24 May 2008 02:26:06 +0000
parents e49abd957e81
children b39c4aef1848
comparison
equal deleted inserted replaced
95272:b3a22f3768c6 95273:4d3975347028
101 ;; + Which chars to (un)escape? 101 ;; + Which chars to (un)escape?
102 102
103 103
104 ;;; Code: 104 ;;; Code:
105 105
106 (defconst icalendar-version "0.18" 106 (defconst icalendar-version "0.19"
107 "Version number of icalendar.el.") 107 "Version number of icalendar.el.")
108 108
109 ;; ====================================================================== 109 ;; ======================================================================
110 ;; Customizables 110 ;; Customizables
111 ;; ====================================================================== 111 ;; ======================================================================
199 Some calendar browsers only propagate recurring events for 199 Some calendar browsers only propagate recurring events for
200 several years beyond the start time. Set this string to a year 200 several years beyond the start time. Set this string to a year
201 just before the start of your personal calendar." 201 just before the start of your personal calendar."
202 :type 'integer 202 :type 'integer
203 :group 'icalendar) 203 :group 'icalendar)
204
205 204
206 (defcustom icalendar-export-hidden-diary-entries 205 (defcustom icalendar-export-hidden-diary-entries
207 t 206 t
208 "Determines whether hidden diary entries are exported. 207 "Determines whether hidden diary entries are exported.
209 If non-nil hidden diary entries (starting with `&') get exported, 208 If non-nil hidden diary entries (starting with `&') get exported,
666 (or separator " ") 665 (or separator " ")
667 (nth 3 datetime)) ;day 666 (nth 3 datetime)) ;day
668 ;; datetime == nil 667 ;; datetime == nil
669 nil)) 668 nil))
670 669
670 (defun icalendar--date-style ()
671 "Return current calendar date style.
672 Convenience function to handle transition from old
673 `european-calendar-style' to new `calendar-date-style'."
674 (if (boundp 'calendar-date-style)
675 calendar-date-style
676 (if (with-no-warnings european-calendar-style)
677 'european
678 'american)))
679
671 (defun icalendar--datetime-to-diary-date (datetime &optional separator) 680 (defun icalendar--datetime-to-diary-date (datetime &optional separator)
672 "Convert the decoded DATETIME to diary format. 681 "Convert the decoded DATETIME to diary format.
673 Optional argument SEPARATOR gives the separator between month, 682 Optional argument SEPARATOR gives the separator between month,
674 day, and year. If nil a blank character is used as separator. 683 day, and year. If nil a blank character is used as separator.
675 Call icalendar--datetime-to-*-date according to the 684 Call icalendar--datetime-to-*-date according to the current
676 value of `calendar-date-style' (or the older `european-calendar-style')." 685 calendar date style."
677 (funcall (intern-soft (format "icalendar--datetime-to-%s-date" 686 (funcall (intern-soft (format "icalendar--datetime-to-%s-date"
678 (if (boundp 'calendar-date-style) 687 (icalendar--date-style)))
679 calendar-date-style
680 (if (with-no-warnings european-calendar-style)
681 'european
682 'american))))
683 datetime separator)) 688 datetime separator))
684 689
685 (defun icalendar--datetime-to-colontime (datetime) 690 (defun icalendar--datetime-to-colontime (datetime)
686 "Extract the time part of a decoded DATETIME into 24-hour format. 691 "Extract the time part of a decoded DATETIME into 24-hour format.
687 Note that this silently ignores seconds." 692 Note that this silently ignores seconds."
744 749
745 (defun icalendar--datestring-to-isodate (datestring &optional day-shift) 750 (defun icalendar--datestring-to-isodate (datestring &optional day-shift)
746 "Convert diary-style DATESTRING to iso-style date. 751 "Convert diary-style DATESTRING to iso-style date.
747 If DAY-SHIFT is non-nil, the result is shifted by DAY-SHIFT days 752 If DAY-SHIFT is non-nil, the result is shifted by DAY-SHIFT days
748 -- DAY-SHIFT must be either nil or an integer. This function 753 -- DAY-SHIFT must be either nil or an integer. This function
749 takes care of european-style." 754 tries to figure the date style from DATESTRING itself. If that
755 is not possible it uses the current calendar date style."
750 (let ((day -1) month year) 756 (let ((day -1) month year)
751 (save-match-data 757 (save-match-data
752 (cond ( ;; numeric date 758 (cond ( ;; iso-style numeric date
759 (string-match (concat "\\s-*"
760 "\\([0-9]\\{4\\}\\)[ \t/]\\s-*"
761 "0?\\([1-9][0-9]?\\)[ \t/]\\s-*"
762 "0?\\([1-9][0-9]?\\)")
763 datestring)
764 (setq year (read (substring datestring (match-beginning 1)
765 (match-end 1))))
766 (setq month (read (substring datestring (match-beginning 2)
767 (match-end 2))))
768 (setq day (read (substring datestring (match-beginning 3)
769 (match-end 3)))))
770 ( ;; non-iso numeric date -- must rely on configured
771 ;; calendar style
753 (string-match (concat "\\s-*" 772 (string-match (concat "\\s-*"
754 "0?\\([1-9][0-9]?\\)[ \t/]\\s-*" 773 "0?\\([1-9][0-9]?\\)[ \t/]\\s-*"
755 "0?\\([1-9][0-9]?\\),?[ \t/]\\s-*" 774 "0?\\([1-9][0-9]?\\),?[ \t/]\\s-*"
756 "\\([0-9]\\{4\\}\\)") 775 "\\([0-9]\\{4\\}\\)")
757 datestring) 776 datestring)
759 (match-end 1)))) 778 (match-end 1))))
760 (setq month (read (substring datestring (match-beginning 2) 779 (setq month (read (substring datestring (match-beginning 2)
761 (match-end 2)))) 780 (match-end 2))))
762 (setq year (read (substring datestring (match-beginning 3) 781 (setq year (read (substring datestring (match-beginning 3)
763 (match-end 3)))) 782 (match-end 3))))
764 (unless european-calendar-style 783 (if (eq (icalendar--date-style) 'american)
765 (let ((x month)) 784 (let ((x month))
766 (setq month day) 785 (setq month day)
767 (setq day x)))) 786 (setq day x))))
768 ( ;; date contains month names -- european-style 787 ( ;; date contains month names -- iso style
788 (string-match (concat "\\s-*"
789 "\\([0-9]\\{4\\}\\)[ \t/]\\s-*"
790 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*"
791 "0?\\([123]?[0-9]\\)")
792 datestring)
793 (setq year (read (substring datestring (match-beginning 1)
794 (match-end 1))))
795 (setq month (icalendar--get-month-number
796 (substring datestring (match-beginning 2)
797 (match-end 2))))
798 (setq day (read (substring datestring (match-beginning 3)
799 (match-end 3)))))
800 ( ;; date contains month names -- european style
769 (string-match (concat "\\s-*" 801 (string-match (concat "\\s-*"
770 "0?\\([123]?[0-9]\\)[ \t/]\\s-*" 802 "0?\\([123]?[0-9]\\)[ \t/]\\s-*"
771 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" 803 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*"
772 "\\([0-9]\\{4\\}\\)") 804 "\\([0-9]\\{4\\}\\)")
773 datestring) 805 datestring)
776 (setq month (icalendar--get-month-number 808 (setq month (icalendar--get-month-number
777 (substring datestring (match-beginning 2) 809 (substring datestring (match-beginning 2)
778 (match-end 2)))) 810 (match-end 2))))
779 (setq year (read (substring datestring (match-beginning 3) 811 (setq year (read (substring datestring (match-beginning 3)
780 (match-end 3))))) 812 (match-end 3)))))
781 ( ;; date contains month names -- non-european-style 813 ( ;; date contains month names -- american style
782 (string-match (concat "\\s-*" 814 (string-match (concat "\\s-*"
783 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" 815 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*"
784 "0?\\([123]?[0-9]\\),?[ \t/]\\s-*" 816 "0?\\([123]?[0-9]\\),?[ \t/]\\s-*"
785 "\\([0-9]\\{4\\}\\)") 817 "\\([0-9]\\{4\\}\\)")
786 datestring) 818 datestring)
796 (if (> day 0) 828 (if (> day 0)
797 (let ((mdy (calendar-gregorian-from-absolute 829 (let ((mdy (calendar-gregorian-from-absolute
798 (+ (calendar-absolute-from-gregorian (list month day 830 (+ (calendar-absolute-from-gregorian (list month day
799 year)) 831 year))
800 (or day-shift 0))))) 832 (or day-shift 0)))))
833 (icalendar--dmsg (format "%04d%02d%02d" (nth 2 mdy) (nth 0 mdy) (nth 1 mdy)))
801 (format "%04d%02d%02d" (nth 2 mdy) (nth 0 mdy) (nth 1 mdy))) 834 (format "%04d%02d%02d" (nth 2 mdy) (nth 0 mdy) (nth 1 mdy)))
802 nil))) 835 nil)))
803 836
804 (defun icalendar--diarytime-to-isotime (timestring ampmstring) 837 (defun icalendar--diarytime-to-isotime (timestring ampmstring)
805 "Convert a time like 9:30pm to an iso-conform string like T213000. 838 "Convert a time like 9:30pm to an iso-conform string like T213000.
1065 ;; subroutines for icalendar-export-region 1098 ;; subroutines for icalendar-export-region
1066 (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) 1099 (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main)
1067 "Convert \"ordinary\" diary entry to icalendar format. 1100 "Convert \"ordinary\" diary entry to icalendar format.
1068 NONMARKER is a regular expression matching the start of non-marking 1101 NONMARKER is a regular expression matching the start of non-marking
1069 entries. ENTRY-MAIN is the first line of the diary entry." 1102 entries. ENTRY-MAIN is the first line of the diary entry."
1070 (if (string-match (concat nonmarker 1103 (if (string-match
1071 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-*" 1104 (concat nonmarker
1072 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" 1105 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-*" ; date
1073 "\\(" 1106 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" ; start time
1074 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1107 "\\("
1075 "\\)?" 1108 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" ; end time
1076 "\\s-*\\(.*?\\) ?$") 1109 "\\)?"
1077 entry-main) 1110 "\\s-*\\(.*?\\) ?$")
1111 entry-main)
1078 (let* ((datetime (substring entry-main (match-beginning 1) 1112 (let* ((datetime (substring entry-main (match-beginning 1)
1079 (match-end 1))) 1113 (match-end 1)))
1080 (startisostring (icalendar--datestring-to-isodate 1114 (startisostring (icalendar--datestring-to-isodate
1081 datetime)) 1115 datetime))
1082 (endisostring (icalendar--datestring-to-isodate 1116 (endisostring (icalendar--datestring-to-isodate
1227 "\nDTEND;" 1261 "\nDTEND;"
1228 (if endtimestring 1262 (if endtimestring
1229 "VALUE=DATE-TIME:" 1263 "VALUE=DATE-TIME:"
1230 "VALUE=DATE:") 1264 "VALUE=DATE:")
1231 (funcall 'format "%04d%02d%02d" 1265 (funcall 'format "%04d%02d%02d"
1232 ;; end is non-inclusive! 1266 ;; end is non-inclusive!
1233 icalendar-recurring-start-year 1 1267 icalendar-recurring-start-year 1
1234 (+ (icalendar-first-weekday-of-year 1268 (+ (icalendar-first-weekday-of-year
1235 day icalendar-recurring-start-year) 1269 day icalendar-recurring-start-year)
1236 (if endtimestring 0 1))) 1270 (if endtimestring 0 1)))
1237 (or endtimestring "") 1271 (or endtimestring "")
1244 (defun icalendar--convert-yearly-to-ical (nonmarker entry-main) 1278 (defun icalendar--convert-yearly-to-ical (nonmarker entry-main)
1245 "Convert yearly diary entry to icalendar format. 1279 "Convert yearly diary entry to icalendar format.
1246 NONMARKER is a regular expression matching the start of non-marking 1280 NONMARKER is a regular expression matching the start of non-marking
1247 entries. ENTRY-MAIN is the first line of the diary entry." 1281 entries. ENTRY-MAIN is the first line of the diary entry."
1248 (if (string-match (concat nonmarker 1282 (if (string-match (concat nonmarker
1249 (if european-calendar-style 1283 (if (eq (icalendar--date-style) 'european)
1250 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+" 1284 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+"
1251 "\\([a-z]+\\)\\s-+0?\\([1-9]+[0-9]?\\)\\s-+") 1285 "\\([a-z]+\\)\\s-+0?\\([1-9]+[0-9]?\\)\\s-+")
1252 "\\*?\\s-*" 1286 "\\*?\\s-*"
1253 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" 1287 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?"
1254 "\\(" 1288 "\\("
1255 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1289 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
1256 "\\)?" 1290 "\\)?"
1257 "\\s-*\\([^0-9]+.*?\\) ?$" ; must not match years 1291 "\\s-*\\([^0-9]+.*?\\) ?$" ; must not match years
1258 ) 1292 )
1259 entry-main) 1293 entry-main)
1260 (let* ((daypos (if european-calendar-style 1 2)) 1294 (let* ((daypos (if (eq (icalendar--date-style) 'european) 1 2))
1261 (monpos (if european-calendar-style 2 1)) 1295 (monpos (if (eq (icalendar--date-style) 'european) 2 1))
1262 (day (read (substring entry-main 1296 (day (read (substring entry-main
1263 (match-beginning daypos) 1297 (match-beginning daypos)
1264 (match-end daypos)))) 1298 (match-end daypos))))
1265 (month (icalendar--get-month-number 1299 (month (icalendar--get-month-number
1266 (substring entry-main 1300 (substring entry-main
2001 (if end-t "-" "") (or end-t ""))))))) 2035 (if end-t "-" "") (or end-t "")))))))
2002 ;; yearly 2036 ;; yearly
2003 ((string-equal frequency "YEARLY") 2037 ((string-equal frequency "YEARLY")
2004 (icalendar--dmsg "yearly") 2038 (icalendar--dmsg "yearly")
2005 (if until 2039 (if until
2006 (setq result (format 2040 (let ((day (nth 3 dtstart-dec))
2007 (concat "%%%%(and (diary-date %s %s t) " 2041 (month (nth 4 dtstart-dec)))
2008 "(diary-block %s %s)) %s%s%s") 2042 (setq result (concat "%%(and (diary-date "
2009 (if european-calendar-style (nth 3 dtstart-dec) 2043 (cond ((eq (icalendar--date-style) 'iso)
2010 (nth 4 dtstart-dec)) 2044 (format "t %d %d" month day))
2011 (if european-calendar-style (nth 4 dtstart-dec) 2045 ((eq (icalendar--date-style) 'european)
2012 (nth 3 dtstart-dec)) 2046 (format "%d %d t" day month))
2013 dtstart-conv 2047 ((eq (icalendar--date-style) 'american)
2014 until-conv 2048 (format "%d %d t" month day)))
2015 (or start-t "") 2049 ") (diary-block "
2016 (if end-t "-" "") (or end-t ""))) 2050 dtstart-conv
2051 " "
2052 until-conv
2053 ")) "
2054 (or start-t "")
2055 (if end-t "-" "")
2056 (or end-t ""))))
2017 (setq result (format 2057 (setq result (format
2018 "%%%%(and (diary-anniversary %s)) %s%s%s" 2058 "%%%%(and (diary-anniversary %s)) %s%s%s"
2019 dtstart-conv 2059 dtstart-conv
2020 (or start-t "") 2060 (or start-t "")
2021 (if end-t "-" "") (or end-t ""))))) 2061 (if end-t "-" "") (or end-t "")))))
2022 ;; monthly 2062 ;; monthly
2023 ((string-equal frequency "MONTHLY") 2063 ((string-equal frequency "MONTHLY")
2024 (icalendar--dmsg "monthly") 2064 (icalendar--dmsg "monthly")
2025 (setq result 2065 (setq result
2026 (format 2066 (format
2027 "%%%%(and (diary-date %s %s %s) (diary-block %s %s)) %s%s%s" 2067 "%%%%(and (diary-date %s) (diary-block %s %s)) %s%s%s"
2028 (if european-calendar-style (nth 3 dtstart-dec) "t") 2068 (let ((day (nth 3 dtstart-dec)))
2029 (if european-calendar-style "t" (nth 3 dtstart-dec)) 2069 (cond ((eq (icalendar--date-style) 'iso)
2030 "t" 2070 (format "t t %d" day))
2071 ((eq (icalendar--date-style) 'european)
2072 (format "%d t t" day))
2073 ((eq (icalendar--date-style) 'american)
2074 (format "t %d t" day))))
2031 dtstart-conv 2075 dtstart-conv
2032 (if until 2076 (if until
2033 until-conv 2077 until-conv
2034 "1 1 9999") ;; FIXME: should be unlimited 2078 (if (eq (icalendar--date-style) 'iso) "9999 1 1" "1 1 9999")) ;; FIXME: should be unlimited
2035 (or start-t "") 2079 (or start-t "")
2036 (if end-t "-" "") (or end-t "")))) 2080 (if end-t "-" "") (or end-t ""))))
2037 ;; daily 2081 ;; daily
2038 ((and (string-equal frequency "DAILY")) 2082 ((and (string-equal frequency "DAILY"))
2039 (if until 2083 (if until