emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* TIMEZONE property for ical export
@ 2017-08-18 16:53 Eric Abrahamsen
  2017-08-19  8:34 ` Nicolas Goaziou
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Abrahamsen @ 2017-08-18 16:53 UTC (permalink / raw)
  To: emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Hello,
>
> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> Hey, now's the time to bring up something I've wanted to do for
>> a while:
>
> I think this deserves its own thread.

Here we go!

>> adding support for per-entry timezones to the ical export. 
>
> It sounds good.
>
>> I've attached a draft patch that shows what I mean. Basically you give
>> an entry a TIMEZONE property in the tz database format (eg
>> "Europe/London") and it will pass that on to the DTSTART/DTEND
>> properties.
>>
>> I suppose it would also be possible to have separate properties for
>> start and end timezones, then we could do plane trips!
>
> Right. But since Org doesn't support time zones, the usefulness may be
> limited.

Yeah, I'm not convinced it's worthwhile. It's really only the one
use-case, though it would be handy.

Out of curiosity, what's your stance on supporting time zones in Org's
timestamps? It would be an enormous amount of work, obviously, but in
principle?

>> +When optional argument TZ is non-nil, timezone data time will be
>> +added to the timestamp.  It can be the string \"UTC\", to use UTC
>> +time, or a string in the IANA TZ database
>> +format (e.g. \"Europe/London\").  In either case, the value of
>> +`org-icalendar-date-time-format' will be ignored."
>
> I suggest to have symbol t as an equivalent to "UTC", for compatibility
> with, e.g., ZONE in `format-time-string'.

That's pretty much what it was before I messed with it, and I was a
little confused because no callers of `org-icalendar-convert-timestamp'
ever used the optional fourth argument at all. My thinking was that
users might want to explicitly set the timezone to "UTC". To be honest
I'm not sure why they would, but I also don't know why we'd accept t
when nothing uses it. I found the whole handling of utc-or-not a bit
confusing. What do you think?

Thanks,
Eric

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-18 16:53 TIMEZONE property for ical export Eric Abrahamsen
@ 2017-08-19  8:34 ` Nicolas Goaziou
  2017-08-19 17:13   ` Eric Abrahamsen
  0 siblings, 1 reply; 8+ messages in thread
From: Nicolas Goaziou @ 2017-08-19  8:34 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: emacs-orgmode

Hello,

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Out of curiosity, what's your stance on supporting time zones in Org's
> timestamps? It would be an enormous amount of work, obviously, but in
> principle?

In principle I agree this would be a very good thing, if possible at
all.

> That's pretty much what it was before I messed with it, and I was a
> little confused because no callers of `org-icalendar-convert-timestamp'
> ever used the optional fourth argument at all. My thinking was that
> users might want to explicitly set the timezone to "UTC". To be honest
> I'm not sure why they would, but I also don't know why we'd accept t
> when nothing uses it. I found the whole handling of utc-or-not a bit
> confusing. What do you think?

I have no strong opinion about this. I was merely concerned about
consistency. E.g., when using `format-time-string', I never think about
"UTC" for the last optional argument.

BTW, as long as Org doesn't support time zones, the "ox-icalendar"
property may be prefixed with "ICALENDAR_" (e.g., ICALENDAR_TZ).

Regards,

-- 
Nicolas Goaziou

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19  8:34 ` Nicolas Goaziou
@ 2017-08-19 17:13   ` Eric Abrahamsen
  2017-08-19 19:25     ` Nicolas Goaziou
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Abrahamsen @ 2017-08-19 17:13 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 1529 bytes --]

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Hello,
>
> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> Out of curiosity, what's your stance on supporting time zones in Org's
>> timestamps? It would be an enormous amount of work, obviously, but in
>> principle?
>
> In principle I agree this would be a very good thing, if possible at
> all.
>
>> That's pretty much what it was before I messed with it, and I was a
>> little confused because no callers of `org-icalendar-convert-timestamp'
>> ever used the optional fourth argument at all. My thinking was that
>> users might want to explicitly set the timezone to "UTC". To be honest
>> I'm not sure why they would, but I also don't know why we'd accept t
>> when nothing uses it. I found the whole handling of utc-or-not a bit
>> confusing. What do you think?
>
> I have no strong opinion about this. I was merely concerned about
> consistency. E.g., when using `format-time-string', I never think about
> "UTC" for the last optional argument.

As it is now, a program can call `org-icalendar-convert-timestamp' and
pass in t for the "tz" argument, and that will go to
`format-time-string' correctly. If a user sets the property to "UTC",
that will also get converted to t. Again, I'm not sure this is actually
useful, but the call to `format-time-string' should be consistent.

> BTW, as long as Org doesn't support time zones, the "ox-icalendar"
> property may be prefixed with "ICALENDAR_" (e.g., ICALENDAR_TZ).

Done! How does the attached patch look?

Eric


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-per-entry-timezone-support-for-icalendar-export.patch --]
[-- Type: text/x-diff, Size: 9504 bytes --]

From 16e86dbdde1e0accfa7d882adfc173d60df15fe4 Mon Sep 17 00:00:00 2001
From: Eric Abrahamsen <eric@ericabrahamsen.net>
Date: Sat, 19 Aug 2017 10:09:00 -0700
Subject: [PATCH] Add per-entry timezone support for icalendar export

* lisp/ox-icalendar.el (org-icalendar-entry): Look for an
  "ICALENDAR_TZ" property.
  (org-icalendar--vevent, org-icalendar--vtodo): Accept additional
  timezone argument.
  (org-icalendar-convert-timestamp): Change
  paramenter name to "tz", and accept a wider variety of values.
---
 doc/org.texi         | 13 ++++++++++---
 lisp/ox-icalendar.el | 44 +++++++++++++++++++++++++++-----------------
 2 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index 032087fc2..88c979982 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -14159,9 +14159,10 @@ and write it to @code{org-icalendar-combined-agenda-file} file name.
 @cindex property, SUMMARY
 @cindex property, DESCRIPTION
 @cindex property, LOCATION
-The iCalendar export back-end includes SUMMARY, DESCRIPTION and LOCATION
-properties from the Org entries when exporting.  To force the back-end to
-inherit the LOCATION property, configure the
+@cindex property, ICALENDAR_TZ
+The iCalendar export back-end includes SUMMARY, DESCRIPTION, LOCATION and
+ICALENDAR_TZ properties from the Org entries when exporting.  To force the
+back-end to inherit the LOCATION property, configure the
 @code{org-use-property-inheritance} variable.
 
 When Org entries do not have SUMMARY, DESCRIPTION and LOCATION properties,
@@ -14170,6 +14171,12 @@ derives the description from the body of the Org item.  The
 @code{org-icalendar-include-body} variable limits the maximum number of
 characters of the content are turned into its description.
 
+The ICALENDAR_TZ property can be used to specify a per-entry time zone, and
+will be applied to any entry with timestamp information.  Time zones should
+be specified as per the IANA time zone database format, e.g.@:
+``Asia/Almaty''.  Alternately, the property value can be ``UTC'', to force
+UTC time for this entry only.
+
 Exporting to iCalendar format depends in large part on the capabilities of
 the destination application.  Some are more lenient than others.  Consult the
 Org mode FAQ for advice on specific applications.
diff --git a/lisp/ox-icalendar.el b/lisp/ox-icalendar.el
index ba7a62f8b..eb8491f7e 100644
--- a/lisp/ox-icalendar.el
+++ b/lisp/ox-icalendar.el
@@ -341,7 +341,7 @@ A headline is blocked when either
 		   (1- (length org-icalendar-date-time-format))) ?Z))
 
 (defvar org-agenda-default-appointment-duration) ; From org-agenda.el.
-(defun org-icalendar-convert-timestamp (timestamp keyword &optional end utc)
+(defun org-icalendar-convert-timestamp (timestamp keyword &optional end tz)
   "Convert TIMESTAMP to iCalendar format.
 
 TIMESTAMP is a timestamp object.  KEYWORD is added in front of
@@ -352,8 +352,11 @@ Also increase the hour by two (if time string contains a time),
 or the day by one (if it does not contain a time) when no
 explicit ending time is specified.
 
-When optional argument UTC is non-nil, time will be expressed in
-Universal Time, ignoring `org-icalendar-date-time-format'."
+When optional argument TZ is non-nil, timezone data time will be
+added to the timestamp.  It can be the string \"UTC\", to use UTC
+time, or a string in the IANA TZ database
+format (e.g. \"Europe/London\").  In either case, the value of
+`org-icalendar-date-time-format' will be ignored."
   (let* ((year-start (org-element-property :year-start timestamp))
 	 (year-end (org-element-property :year-end timestamp))
 	 (month-start (org-element-property :month-start timestamp))
@@ -387,8 +390,9 @@ Universal Time, ignoring `org-icalendar-date-time-format'."
     (concat
      keyword
      (format-time-string
-      (cond (utc ":%Y%m%dT%H%M%SZ")
+      (cond ((string-equal tz "UTC") ":%Y%m%dT%H%M%SZ")
 	    ((not with-time-p) ";VALUE=DATE:%Y%m%d")
+	    ((stringp tz) (concat ";TZID=" tz ":%Y%m%dT%H%M%S"))
 	    (t (replace-regexp-in-string "%Z"
 					 org-icalendar-timezone
 					 org-icalendar-date-time-format
@@ -396,7 +400,10 @@ Universal Time, ignoring `org-icalendar-date-time-format'."
       ;; Convert timestamp into internal time in order to use
       ;; `format-time-string' and fix any mistake (i.e. MI >= 60).
       (encode-time 0 mi h d m y)
-      (and (or utc (and with-time-p (org-icalendar-use-UTC-date-time-p)))
+      (and (or (string-equal tz "UTC")
+	       (and (null tz)
+		    with-time-p
+		    (org-icalendar-use-UTC-date-time-p)))
 	   t)))))
 
 (defun org-icalendar-dtstamp ()
@@ -545,7 +552,8 @@ inlinetask within the section."
 			  contents 0 (min (length contents)
 					  org-icalendar-include-body))))
 		      (org-icalendar-include-body (org-trim contents)))))))
-	     (cat (org-icalendar-get-categories entry info)))
+	     (cat (org-icalendar-get-categories entry info))
+	     (tz (org-element-property :ICALENDAR_TZ entry)))
 	 (concat
 	  ;; Events: Delegate to `org-icalendar--vevent' to generate
 	  ;; "VEVENT" component from scheduled, deadline, or any
@@ -556,14 +564,14 @@ inlinetask within the section."
 		       org-icalendar-use-deadline)
 		 (org-icalendar--vevent
 		  entry deadline (concat "DL-" uid)
-		  (concat "DL: " summary) loc desc cat)))
+		  (concat "DL: " summary) loc desc cat tz)))
 	  (let ((scheduled (org-element-property :scheduled entry)))
 	    (and scheduled
 		 (memq (if todo-type 'event-if-todo 'event-if-not-todo)
 		       org-icalendar-use-scheduled)
 		 (org-icalendar--vevent
 		  entry scheduled (concat "SC-" uid)
-		  (concat "S: " summary) loc desc cat)))
+		  (concat "S: " summary) loc desc cat tz)))
 	  ;; When collecting plain timestamps from a headline and its
 	  ;; title, skip inlinetasks since collection will happen once
 	  ;; ENTRY is one of them.
@@ -581,7 +589,7 @@ inlinetask within the section."
 			   ((t) t)))
 		   (let ((uid (format "TS%d-%s" (cl-incf counter) uid)))
 		     (org-icalendar--vevent
-		      entry ts uid summary loc desc cat))))
+		      entry ts uid summary loc desc cat tz))))
 	       info nil (and (eq type 'headline) 'inlinetask))
 	     ""))
 	  ;; Task: First check if it is appropriate to export it.  If
@@ -595,7 +603,7 @@ inlinetask within the section."
 			     (not (org-icalendar-blocked-headline-p
 				   entry info))))
 		       ((t) (eq todo-type 'todo))))
-	    (org-icalendar--vtodo entry uid summary loc desc cat))
+	    (org-icalendar--vtodo entry uid summary loc desc cat tz))
 	  ;; Diary-sexp: Collect every diary-sexp element within ENTRY
 	  ;; and its title, and transcode them.  If ENTRY is
 	  ;; a headline, skip inlinetasks: they will be handled
@@ -626,7 +634,7 @@ inlinetask within the section."
        contents))))
 
 (defun org-icalendar--vevent
-    (entry timestamp uid summary location description categories)
+    (entry timestamp uid summary location description categories timezone)
   "Create a VEVENT component.
 
 ENTRY is either a headline or an inlinetask element.  TIMESTAMP
@@ -635,7 +643,8 @@ is the unique identifier for the event.  SUMMARY defines a short
 summary or subject for the event.  LOCATION defines the intended
 venue for the event.  DESCRIPTION provides the complete
 description of the event.  CATEGORIES defines the categories the
-event belongs to.
+event belongs to. TIMEZONE specifies a time zone for this event
+only.
 
 Return VEVENT component as a string."
   (org-icalendar-fold-string
@@ -645,8 +654,8 @@ Return VEVENT component as a string."
      (concat "BEGIN:VEVENT\n"
 	     (org-icalendar-dtstamp) "\n"
 	     "UID:" uid "\n"
-	     (org-icalendar-convert-timestamp timestamp "DTSTART") "\n"
-	     (org-icalendar-convert-timestamp timestamp "DTEND" t) "\n"
+	     (org-icalendar-convert-timestamp timestamp "DTSTART" nil timezone) "\n"
+	     (org-icalendar-convert-timestamp timestamp "DTEND" t timezone) "\n"
 	     ;; RRULE.
 	     (when (org-element-property :repeater-type timestamp)
 	       (format "RRULE:FREQ=%s;INTERVAL=%d\n"
@@ -664,7 +673,7 @@ Return VEVENT component as a string."
 	     "END:VEVENT"))))
 
 (defun org-icalendar--vtodo
-  (entry uid summary location description categories)
+  (entry uid summary location description categories timezone)
   "Create a VTODO component.
 
 ENTRY is either a headline or an inlinetask element.  UID is the
@@ -672,6 +681,7 @@ unique identifier for the task.  SUMMARY defines a short summary
 or subject for the task.  LOCATION defines the intended venue for
 the task.  DESCRIPTION provides the complete description of the
 task.  CATEGORIES defines the categories the task belongs to.
+TIMEZONE specifies a time zone for this TODO only.
 
 Return VTODO component as a string."
   (let ((start (or (and (memq 'todo-start org-icalendar-use-scheduled)
@@ -690,11 +700,11 @@ Return VTODO component as a string."
      (concat "BEGIN:VTODO\n"
 	     "UID:TODO-" uid "\n"
 	     (org-icalendar-dtstamp) "\n"
-	     (org-icalendar-convert-timestamp start "DTSTART") "\n"
+	     (org-icalendar-convert-timestamp start "DTSTART" nil timezone) "\n"
 	     (and (memq 'todo-due org-icalendar-use-deadline)
 		  (org-element-property :deadline entry)
 		  (concat (org-icalendar-convert-timestamp
-			   (org-element-property :deadline entry) "DUE")
+			   (org-element-property :deadline entry) "DUE" nil timezone)
 			  "\n"))
 	     "SUMMARY:" summary "\n"
 	     (and (org-string-nw-p location) (format "LOCATION:%s\n" location))
-- 
2.14.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19 17:13   ` Eric Abrahamsen
@ 2017-08-19 19:25     ` Nicolas Goaziou
  2017-08-19 19:56       ` Eric Abrahamsen
  0 siblings, 1 reply; 8+ messages in thread
From: Nicolas Goaziou @ 2017-08-19 19:25 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: emacs-orgmode

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

>> BTW, as long as Org doesn't support time zones, the "ox-icalendar"
>> property may be prefixed with "ICALENDAR_" (e.g., ICALENDAR_TZ).
>
> Done!

I realize this is not a great idea since other properties do not have
"ICALENDAR_" prefix. Sorry about that. I suggest to go back to TIMEZONE.

> How does the attached patch look?

> -	     (cat (org-icalendar-get-categories entry info)))
> +	     (cat (org-icalendar-get-categories entry info))
> +	     (tz (org-element-property :ICALENDAR_TZ entry)))

Note that "ICALENDAR_TZ" is not inherited in this case. Neither are
LOCATION and so on, tho. You would need to use
`org-export-get-node-property' in conjunction with
`org-property-inherit-p'.

> -event belongs to.
> +event belongs to. TIMEZONE specifies a time zone for this event
> +only.

Missing space.

Could you add a commit message and an ORG-NEWS entry?

Regards,

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19 19:25     ` Nicolas Goaziou
@ 2017-08-19 19:56       ` Eric Abrahamsen
  2017-08-19 21:20         ` Nicolas Goaziou
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Abrahamsen @ 2017-08-19 19:56 UTC (permalink / raw)
  To: emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>>> BTW, as long as Org doesn't support time zones, the "ox-icalendar"
>>> property may be prefixed with "ICALENDAR_" (e.g., ICALENDAR_TZ).
>>
>> Done!
>
> I realize this is not a great idea since other properties do not have
> "ICALENDAR_" prefix. Sorry about that. I suggest to go back to TIMEZONE.

No problem.

>> How does the attached patch look?
>
>> -	     (cat (org-icalendar-get-categories entry info)))
>> +	     (cat (org-icalendar-get-categories entry info))
>> +	     (tz (org-element-property :ICALENDAR_TZ entry)))
>
> Note that "ICALENDAR_TZ" is not inherited in this case. Neither are
> LOCATION and so on, tho. You would need to use
> `org-export-get-node-property' in conjunction with
> `org-property-inherit-p'.

It's a little strange, because the manual section for this specifically
mentions the inheritance of the LOCATION property, but the code doesn't
do it. Shall I add it in? It makes sense for LOCATION and TIMEZONE to be
inheritable, but not SUMMARY and DESCRIPTION, of course.

If I add inheritance, that will look like this, right?

(tz (org-export-get-node-property :LOCATION entry
                                  (org-property-inherit-p :LOCATION)))

That could also be a separate, second commit.

>> -event belongs to.
>> +event belongs to. TIMEZONE specifies a time zone for this event
>> +only.
>
> Missing space.
>
> Could you add a commit message and an ORG-NEWS entry?

I've added an ORG-NEWS entry. The patch in my last message was done with
git format-patch, isn't that commit message okay?

Eric

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19 19:56       ` Eric Abrahamsen
@ 2017-08-19 21:20         ` Nicolas Goaziou
  2017-08-19 21:54           ` Eric Abrahamsen
  0 siblings, 1 reply; 8+ messages in thread
From: Nicolas Goaziou @ 2017-08-19 21:20 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: emacs-orgmode

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> It's a little strange, because the manual section for this specifically
> mentions the inheritance of the LOCATION property, but the code doesn't
> do it. Shall I add it in? It makes sense for LOCATION and TIMEZONE to be
> inheritable, but not SUMMARY and DESCRIPTION, of course.
>
> If I add inheritance, that will look like this, right?
>
> (tz (org-export-get-node-property :LOCATION entry
>                                   (org-property-inherit-p :LOCATION)))

It should be:

  (org-property-inherit-p "LOCATION")

> That could also be a separate, second commit.

I think that would be better.

> I've added an ORG-NEWS entry. The patch in my last message was done with
> git format-patch, isn't that commit message okay?

It is. I just need to read better.

Regards,

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19 21:20         ` Nicolas Goaziou
@ 2017-08-19 21:54           ` Eric Abrahamsen
  2017-08-19 22:14             ` Nicolas Goaziou
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Abrahamsen @ 2017-08-19 21:54 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 932 bytes --]

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> It's a little strange, because the manual section for this specifically
>> mentions the inheritance of the LOCATION property, but the code doesn't
>> do it. Shall I add it in? It makes sense for LOCATION and TIMEZONE to be
>> inheritable, but not SUMMARY and DESCRIPTION, of course.
>>
>> If I add inheritance, that will look like this, right?
>>
>> (tz (org-export-get-node-property :LOCATION entry
>>                                   (org-property-inherit-p :LOCATION)))
>
> It should be:
>
>   (org-property-inherit-p "LOCATION")
>
>> That could also be a separate, second commit.
>
> I think that would be better.
>
>> I've added an ORG-NEWS entry. The patch in my last message was done with
>> git format-patch, isn't that commit message okay?
>
> It is. I just need to read better.

Okay, hopefully this is it!

Eric


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Inherit-TIMEZONE-and-LOCATION-properties-in-iCalenda.patch --]
[-- Type: text/x-diff, Size: 2962 bytes --]

From edecd8c97961b759c3aa608d6e05daeb09989c3d Mon Sep 17 00:00:00 2001
From: Eric Abrahamsen <eric@ericabrahamsen.net>
Date: Sat, 19 Aug 2017 14:51:44 -0700
Subject: [PATCH 2/2] Inherit TIMEZONE and LOCATION properties in iCalendar
 export

* lisp/ox-icalendar.el (org-icalendar-entry): Both properties now
  optionally inherit, depending on value of
  `org-use-property-inheritance'.
* doc/org.texi: Mention change.
* etc/ORG-NEWS: Mention change.
---
 doc/org.texi         | 2 +-
 etc/ORG-NEWS         | 3 +++
 lisp/ox-icalendar.el | 8 ++++++--
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index d8a8a8e81..8bb6fa7f4 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -14162,7 +14162,7 @@ and write it to @code{org-icalendar-combined-agenda-file} file name.
 @cindex property, TIMEZONE
 The iCalendar export back-end includes SUMMARY, DESCRIPTION, LOCATION and
 TIMEZONE properties from the Org entries when exporting.  To force the
-back-end to inherit the LOCATION property, configure the
+back-end to inherit the LOCATION and TIMEZONE properties, configure the
 @code{org-use-property-inheritance} variable.
 
 When Org entries do not have SUMMARY, DESCRIPTION and LOCATION properties,
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index f53a70837..cf7502ace 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -99,6 +99,9 @@ Use "/!" markup when filtering TODO keywords to get only not-done TODO
 keywords.
 
 ** New features
+*** iCalendar export uses inheritance for TIMEZONE and LOCATION properties
+Both these properties can be inherited during iCalendar export,
+depending on the value of ~org-use-property-inheritance~.
 *** iCalendar export respects a TIMEZONE property
 Set the TIMEZONE property on an entry to specify a time zone for that
 entry only during iCalendar export.  The property value should be
diff --git a/lisp/ox-icalendar.el b/lisp/ox-icalendar.el
index d445c7b8d..b27c30c31 100644
--- a/lisp/ox-icalendar.el
+++ b/lisp/ox-icalendar.el
@@ -537,7 +537,9 @@ inlinetask within the section."
 			   (org-export-data
 			    (org-element-property :title entry) info))))
 	     (loc (org-icalendar-cleanup-string
-		   (org-element-property :LOCATION entry)))
+		   (org-export-get-node-property
+		    :LOCATION entry
+		    (org-property-inherit-p "LOCATION"))))
 	     ;; Build description of the entry from associated section
 	     ;; (headline) or contents (inlinetask).
 	     (desc
@@ -553,7 +555,9 @@ inlinetask within the section."
 					  org-icalendar-include-body))))
 		      (org-icalendar-include-body (org-trim contents)))))))
 	     (cat (org-icalendar-get-categories entry info))
-	     (tz (org-element-property :TIMEZONE entry)))
+	     (tz (org-export-get-node-property
+		  :TIMEZONE entry
+		  (org-property-inherit-p "TIMEZONE"))))
 	 (concat
 	  ;; Events: Delegate to `org-icalendar--vevent' to generate
 	  ;; "VEVENT" component from scheduled, deadline, or any
-- 
2.14.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Add-per-entry-timezone-support-for-icalendar-export.patch --]
[-- Type: text/x-diff, Size: 10426 bytes --]

From d237d0460eb504fc560459b9039b57a70677b90b Mon Sep 17 00:00:00 2001
From: Eric Abrahamsen <eric@ericabrahamsen.net>
Date: Sat, 19 Aug 2017 10:09:00 -0700
Subject: [PATCH 1/2] Add per-entry timezone support for icalendar export

* lisp/ox-icalendar.el (org-icalendar-entry): Look for an
  "ICALENDAR_TZ" property.
  (org-icalendar--vevent, org-icalendar--vtodo): Accept additional
  timezone argument.
  (org-icalendar-convert-timestamp): Change
  paramenter name to "tz", and accept a wider variety of values.
* doc/org.texi: Mention in manual.
* etc/ORG-NEWS: Mention in NEWS.
---
 doc/org.texi         | 13 ++++++++++---
 etc/ORG-NEWS         |  5 ++++-
 lisp/ox-icalendar.el | 44 +++++++++++++++++++++++++++-----------------
 3 files changed, 41 insertions(+), 21 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index 032087fc2..d8a8a8e81 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -14159,9 +14159,10 @@ and write it to @code{org-icalendar-combined-agenda-file} file name.
 @cindex property, SUMMARY
 @cindex property, DESCRIPTION
 @cindex property, LOCATION
-The iCalendar export back-end includes SUMMARY, DESCRIPTION and LOCATION
-properties from the Org entries when exporting.  To force the back-end to
-inherit the LOCATION property, configure the
+@cindex property, TIMEZONE
+The iCalendar export back-end includes SUMMARY, DESCRIPTION, LOCATION and
+TIMEZONE properties from the Org entries when exporting.  To force the
+back-end to inherit the LOCATION property, configure the
 @code{org-use-property-inheritance} variable.
 
 When Org entries do not have SUMMARY, DESCRIPTION and LOCATION properties,
@@ -14170,6 +14171,12 @@ derives the description from the body of the Org item.  The
 @code{org-icalendar-include-body} variable limits the maximum number of
 characters of the content are turned into its description.
 
+The TIMEZONE property can be used to specify a per-entry time zone, and will
+be applied to any entry with timestamp information.  Time zones should be
+specified as per the IANA time zone database format, e.g.@: ``Asia/Almaty''.
+Alternately, the property value can be ``UTC'', to force UTC time for this
+entry only.
+
 Exporting to iCalendar format depends in large part on the capabilities of
 the destination application.  Some are more lenient than others.  Consult the
 Org mode FAQ for advice on specific applications.
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index a7deb3cf8..f53a70837 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -99,11 +99,14 @@ Use "/!" markup when filtering TODO keywords to get only not-done TODO
 keywords.
 
 ** New features
+*** iCalendar export respects a TIMEZONE property
+Set the TIMEZONE property on an entry to specify a time zone for that
+entry only during iCalendar export.  The property value should be
+specified as in "Europe/London".
 *** ~org-attach~ can move directory contents
 When setting a new directory for an entry, org-attach offers to move
 files over from the old directory.  Using a prefix arg will reset the
 directory to old, ID based one.
-
 *** New Org duration library
 This new library implements tools to read and print time durations in
 various formats (e.g., "H:MM", or "1d 2h 3min"...).
diff --git a/lisp/ox-icalendar.el b/lisp/ox-icalendar.el
index ba7a62f8b..d445c7b8d 100644
--- a/lisp/ox-icalendar.el
+++ b/lisp/ox-icalendar.el
@@ -341,7 +341,7 @@ A headline is blocked when either
 		   (1- (length org-icalendar-date-time-format))) ?Z))
 
 (defvar org-agenda-default-appointment-duration) ; From org-agenda.el.
-(defun org-icalendar-convert-timestamp (timestamp keyword &optional end utc)
+(defun org-icalendar-convert-timestamp (timestamp keyword &optional end tz)
   "Convert TIMESTAMP to iCalendar format.
 
 TIMESTAMP is a timestamp object.  KEYWORD is added in front of
@@ -352,8 +352,11 @@ Also increase the hour by two (if time string contains a time),
 or the day by one (if it does not contain a time) when no
 explicit ending time is specified.
 
-When optional argument UTC is non-nil, time will be expressed in
-Universal Time, ignoring `org-icalendar-date-time-format'."
+When optional argument TZ is non-nil, timezone data time will be
+added to the timestamp.  It can be the string \"UTC\", to use UTC
+time, or a string in the IANA TZ database
+format (e.g. \"Europe/London\").  In either case, the value of
+`org-icalendar-date-time-format' will be ignored."
   (let* ((year-start (org-element-property :year-start timestamp))
 	 (year-end (org-element-property :year-end timestamp))
 	 (month-start (org-element-property :month-start timestamp))
@@ -387,8 +390,9 @@ Universal Time, ignoring `org-icalendar-date-time-format'."
     (concat
      keyword
      (format-time-string
-      (cond (utc ":%Y%m%dT%H%M%SZ")
+      (cond ((string-equal tz "UTC") ":%Y%m%dT%H%M%SZ")
 	    ((not with-time-p) ";VALUE=DATE:%Y%m%d")
+	    ((stringp tz) (concat ";TZID=" tz ":%Y%m%dT%H%M%S"))
 	    (t (replace-regexp-in-string "%Z"
 					 org-icalendar-timezone
 					 org-icalendar-date-time-format
@@ -396,7 +400,10 @@ Universal Time, ignoring `org-icalendar-date-time-format'."
       ;; Convert timestamp into internal time in order to use
       ;; `format-time-string' and fix any mistake (i.e. MI >= 60).
       (encode-time 0 mi h d m y)
-      (and (or utc (and with-time-p (org-icalendar-use-UTC-date-time-p)))
+      (and (or (string-equal tz "UTC")
+	       (and (null tz)
+		    with-time-p
+		    (org-icalendar-use-UTC-date-time-p)))
 	   t)))))
 
 (defun org-icalendar-dtstamp ()
@@ -545,7 +552,8 @@ inlinetask within the section."
 			  contents 0 (min (length contents)
 					  org-icalendar-include-body))))
 		      (org-icalendar-include-body (org-trim contents)))))))
-	     (cat (org-icalendar-get-categories entry info)))
+	     (cat (org-icalendar-get-categories entry info))
+	     (tz (org-element-property :TIMEZONE entry)))
 	 (concat
 	  ;; Events: Delegate to `org-icalendar--vevent' to generate
 	  ;; "VEVENT" component from scheduled, deadline, or any
@@ -556,14 +564,14 @@ inlinetask within the section."
 		       org-icalendar-use-deadline)
 		 (org-icalendar--vevent
 		  entry deadline (concat "DL-" uid)
-		  (concat "DL: " summary) loc desc cat)))
+		  (concat "DL: " summary) loc desc cat tz)))
 	  (let ((scheduled (org-element-property :scheduled entry)))
 	    (and scheduled
 		 (memq (if todo-type 'event-if-todo 'event-if-not-todo)
 		       org-icalendar-use-scheduled)
 		 (org-icalendar--vevent
 		  entry scheduled (concat "SC-" uid)
-		  (concat "S: " summary) loc desc cat)))
+		  (concat "S: " summary) loc desc cat tz)))
 	  ;; When collecting plain timestamps from a headline and its
 	  ;; title, skip inlinetasks since collection will happen once
 	  ;; ENTRY is one of them.
@@ -581,7 +589,7 @@ inlinetask within the section."
 			   ((t) t)))
 		   (let ((uid (format "TS%d-%s" (cl-incf counter) uid)))
 		     (org-icalendar--vevent
-		      entry ts uid summary loc desc cat))))
+		      entry ts uid summary loc desc cat tz))))
 	       info nil (and (eq type 'headline) 'inlinetask))
 	     ""))
 	  ;; Task: First check if it is appropriate to export it.  If
@@ -595,7 +603,7 @@ inlinetask within the section."
 			     (not (org-icalendar-blocked-headline-p
 				   entry info))))
 		       ((t) (eq todo-type 'todo))))
-	    (org-icalendar--vtodo entry uid summary loc desc cat))
+	    (org-icalendar--vtodo entry uid summary loc desc cat tz))
 	  ;; Diary-sexp: Collect every diary-sexp element within ENTRY
 	  ;; and its title, and transcode them.  If ENTRY is
 	  ;; a headline, skip inlinetasks: they will be handled
@@ -626,7 +634,7 @@ inlinetask within the section."
        contents))))
 
 (defun org-icalendar--vevent
-    (entry timestamp uid summary location description categories)
+    (entry timestamp uid summary location description categories timezone)
   "Create a VEVENT component.
 
 ENTRY is either a headline or an inlinetask element.  TIMESTAMP
@@ -635,7 +643,8 @@ is the unique identifier for the event.  SUMMARY defines a short
 summary or subject for the event.  LOCATION defines the intended
 venue for the event.  DESCRIPTION provides the complete
 description of the event.  CATEGORIES defines the categories the
-event belongs to.
+event belongs to.  TIMEZONE specifies a time zone for this event
+only.
 
 Return VEVENT component as a string."
   (org-icalendar-fold-string
@@ -645,8 +654,8 @@ Return VEVENT component as a string."
      (concat "BEGIN:VEVENT\n"
 	     (org-icalendar-dtstamp) "\n"
 	     "UID:" uid "\n"
-	     (org-icalendar-convert-timestamp timestamp "DTSTART") "\n"
-	     (org-icalendar-convert-timestamp timestamp "DTEND" t) "\n"
+	     (org-icalendar-convert-timestamp timestamp "DTSTART" nil timezone) "\n"
+	     (org-icalendar-convert-timestamp timestamp "DTEND" t timezone) "\n"
 	     ;; RRULE.
 	     (when (org-element-property :repeater-type timestamp)
 	       (format "RRULE:FREQ=%s;INTERVAL=%d\n"
@@ -664,7 +673,7 @@ Return VEVENT component as a string."
 	     "END:VEVENT"))))
 
 (defun org-icalendar--vtodo
-  (entry uid summary location description categories)
+  (entry uid summary location description categories timezone)
   "Create a VTODO component.
 
 ENTRY is either a headline or an inlinetask element.  UID is the
@@ -672,6 +681,7 @@ unique identifier for the task.  SUMMARY defines a short summary
 or subject for the task.  LOCATION defines the intended venue for
 the task.  DESCRIPTION provides the complete description of the
 task.  CATEGORIES defines the categories the task belongs to.
+TIMEZONE specifies a time zone for this TODO only.
 
 Return VTODO component as a string."
   (let ((start (or (and (memq 'todo-start org-icalendar-use-scheduled)
@@ -690,11 +700,11 @@ Return VTODO component as a string."
      (concat "BEGIN:VTODO\n"
 	     "UID:TODO-" uid "\n"
 	     (org-icalendar-dtstamp) "\n"
-	     (org-icalendar-convert-timestamp start "DTSTART") "\n"
+	     (org-icalendar-convert-timestamp start "DTSTART" nil timezone) "\n"
 	     (and (memq 'todo-due org-icalendar-use-deadline)
 		  (org-element-property :deadline entry)
 		  (concat (org-icalendar-convert-timestamp
-			   (org-element-property :deadline entry) "DUE")
+			   (org-element-property :deadline entry) "DUE" nil timezone)
 			  "\n"))
 	     "SUMMARY:" summary "\n"
 	     (and (org-string-nw-p location) (format "LOCATION:%s\n" location))
-- 
2.14.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: TIMEZONE property for ical export
  2017-08-19 21:54           ` Eric Abrahamsen
@ 2017-08-19 22:14             ` Nicolas Goaziou
  0 siblings, 0 replies; 8+ messages in thread
From: Nicolas Goaziou @ 2017-08-19 22:14 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: emacs-orgmode

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Subject: [PATCH 2/2] Inherit TIMEZONE and LOCATION properties in iCalendar
>  export
>
> * lisp/ox-icalendar.el (org-icalendar-entry): Both properties now
>   optionally inherit, depending on value of
>   `org-use-property-inheritance'.
> * doc/org.texi: Mention change.

Applied.

> Subject: [PATCH 1/2] Add per-entry timezone support for icalendar export
>
> * lisp/ox-icalendar.el (org-icalendar-entry): Look for an
>   "ICALENDAR_TZ" property.
>   (org-icalendar--vevent, org-icalendar--vtodo): Accept additional
>   timezone argument.
>   (org-icalendar-convert-timestamp): Change
>   paramenter name to "tz", and accept a wider variety of values.
> * doc/org.texi: Mention in manual.

Applied.

Thank you!

Regards,

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-08-19 22:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-18 16:53 TIMEZONE property for ical export Eric Abrahamsen
2017-08-19  8:34 ` Nicolas Goaziou
2017-08-19 17:13   ` Eric Abrahamsen
2017-08-19 19:25     ` Nicolas Goaziou
2017-08-19 19:56       ` Eric Abrahamsen
2017-08-19 21:20         ` Nicolas Goaziou
2017-08-19 21:54           ` Eric Abrahamsen
2017-08-19 22:14             ` Nicolas Goaziou

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).