From 138615942fe12b40f8fbb1de5ead5ae5960032f3 Mon Sep 17 00:00:00 2001
From: Carsten Dominik <carsten.dominik@gmail.com>
Date: Sun, 13 Mar 2011 08:06:22 +0100
Subject: [PATCH] Improve handling of years with limitations on representable dates

* lisp/org.el (org-read-date-force-compatible-dates): New option.
(org-read-date, org-read-date-analyze): Check representable date range.
* doc/org.texi (The date/time prompt): Document date range protection.

New variable `org-read-date-force-compatible-dates' to control
handling of dates.
---
 doc/org.texi |   12 ++++++++++--
 lisp/org.el  |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index e13af4b..dd6d945 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -5394,9 +5394,17 @@ The function understands English month and weekday abbreviations.  If
 you want to use unabbreviated names and/or other languages, configure
 the variables @code{parse-time-months} and @code{parse-time-weekdays}.
 
+@vindex org-read-date-force-compatible-dates
+Not all dates can be represented in a given Emacs implementation.  By default
+Org mode forces dates into the compatibility range 1970--2037 which works on
+all Emacs implementations.  If you want to use dates outside of this range,
+read the docstring of the variable
+@code{org-read-date-force-compatible-dates}.
+
 You can specify a time range by giving start and end times or by giving a
-start time and a duration (in HH:MM format). Use `-' or `-@{@}-' as the separator
-in the former case and use '+' as the separator in the latter case. E.g.@:
+start time and a duration (in HH:MM format). Use `-' or `-@{@}-' as the
+separator in the former case and use '+' as the separator in the latter
+case. E.g.@:
 
 @example
 11am-1:15pm    @result{} 11:00-13:15
diff --git a/lisp/org.el b/lisp/org.el
index 96ad8ff..a145de6 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -2651,6 +2651,36 @@ This may t or nil, or the symbol `org-read-date-prefer-future'."
 	  (const :tag "Never" nil)
 	  (const :tag "Always" t)))
 
+(defcustom org-read-date-force-compatible-dates t
+  "Should date/time prompt force dates that are guaranteed to work in Emacs?
+
+Depending on the system Emacs is running on, certain dates cannot
+be represented with the type used internally to represent time.
+Dates between 1970-1-1 and 2038-1-1 can always be represented
+correctly.  Some systems allow for earlier dates, some for later,
+some for both.  One way to find out it to insert any date into an
+Org buffer, putting the cursor on the year and hitting S-up and
+S-down to test the range.
+
+When this variable is set to t, the date/time prompt will not let
+you specify dates outside the 1970-2037 range, so it is certain that
+these dates will work in whatever version of Emacs you are
+running, and also that you can move a file from one Emacs implementation
+to another.  WHenever Org is forcing the year for you, it will display
+a message and beep.
+
+When this variable is nil, Org will check if the date is
+representable in the specific Emacs implementation you are using.
+If not, it will force a year, usually the current year, and beep
+to remind you.  Currently this setting is not recommended because
+the likelihood that you will open your Org files in an Emacs that
+has limited date range is not negligible.
+
+A workaround for this problem is to use diary sexp dates for time
+stamps outside of this range."
+  :group 'org-time
+  :type 'boolean)
+
 (defcustom org-read-date-display-live t
   "Non-nil means display current interpretation of date prompt live.
 This display will be in an overlay, in the minibuffer."
@@ -14503,6 +14533,13 @@ user."
 
     (setq final (org-read-date-analyze ans def defdecode))
 
+    (when org-read-date-analyze-forced-year
+      (message "Year was forced into %s"
+	       (if org-read-date-force-compatible-dates
+		   "compatible range (1970-2037)"
+		 "range representable on this machine"))
+      (ding))
+
     ;; One round trip to get rid of 34th of August and stuff like that....
     (setq final (decode-time (apply 'encode-time final)))
 
@@ -14520,6 +14557,7 @@ user."
 (defvar defdecode)
 (defvar with-time)
 (defvar org-read-date-analyze-futurep nil)
+(defvar org-read-date-analyze-forced-year nil)
 (defun org-read-date-display ()
   "Display the current date prompt interpretation in the minibuffer."
   (when org-read-date-display-live
@@ -14562,7 +14600,8 @@ user."
 	delta deltan deltaw deltadef year month day
 	hour minute second wday pm h2 m2 tl wday1
 	iso-year iso-weekday iso-week iso-year iso-date futurep kill-year)
-    (setq org-read-date-analyze-futurep nil)
+    (setq org-read-date-analyze-futurep nil
+	  org-read-date-analyze-forced-year nil)
     (when (string-match "\\`[ \t]*\\.[ \t]*\\'" ans)
       (setq ans "+0"))
 
@@ -14720,7 +14759,18 @@ user."
 	     (nth 2 tl))
 	(setq org-time-was-given t))
     (if (< year 100) (setq year (+ 2000 year)))
-    (if (< year 1970) (setq year (nth 5 defdecode))) ; not representable
+    ;; Check of the date is representable
+    (if org-read-date-force-compatible-dates
+	(progn
+	  (if (< year 1970)
+	      (setq year 1970 org-read-date-analyze-forced-year t))
+	  (if (> year 2037)
+	      (setq year 2037  org-read-date-analyze-forced-year t)))
+      (condition-case nil
+	  (encode-time second minute hour day month year)
+	(error
+	 (setq year (nth 5 defdecode))
+	 (setq org-read-date-analyze-forced-year t))))
     (setq org-read-date-analyze-futurep futurep)
     (list second minute hour day month year)))
 
-- 
1.7.1.575.gf526

