The Omni Group Forums

The Omni Group Forums (
-   OmniFocus 1 for Mac (
-   -   Import from OmniOutliner to OmniFocus (

steve 2010-09-02 09:58 AM

Import from OmniOutliner to OmniFocus
I'm sure this has been answered, but I can't find the solution.

I have changed the omnioutliner columns to be Title, Context, Start Date, Due Date.

When I copy and paste from OO to OF, the column mapper comes up and everything looks good and imports fine except for the date fields. I was hoping that I would be able to use 5d, 10d, 1m, etc for date fields because this is intelligible for anyone that doesn't use Omnifocus to understand. However, this is imported into OF as metadata. I don't want to have to manually change all of the dates.

Are there any work arounds?


RobTrew 2010-09-02 10:25 AM

Expressions like 5d, 10d, 1m are properly parsed in an oo3 column as long as the inspector shows it to be of type Duration rather than type Rich Text.

If the column is currently Rich Text, changing its type to Duration should work fine, and result in automatic type conversion, as long as the duration strings are all well-formed, conforming to the patterns known to oo3.

You can then map an oo3 duration column to the OF duration field during the drag and drop process, but you can't really map duration data to date fields ... (if that is indeed what you meant ?) Duration expressions just specify a total number of minutes - they don't correspond to particular calendar dates ...


whpalmer4 2010-09-02 10:44 AM

The fly in the ointment is that OO thinks of durations in hours, and OF in minutes.

- [ ] Build giant robot to control the world Garage 1/1/10 9/3/10 20w

with column types of RT, RT, Date, Date, Duration

gets you the right result upon paste into OF except for the duration, which shows up as 13 hours 20 minutes (13*60+20 = 800, vs. 20 * 5 * 8 = 800 for OO)

An applescript that multiplied the duration of the selected rows by 60 would probably be an easy workaround.

steve 2010-09-02 12:36 PM

Rob and WHPalmer,

Looks like I'll have to continue to be patient. Ideally, I was hoping that if you had a template in OO that looked like

Title---------------------|Start Date|Due Date|
call Bob re: giant robot|1w |4w |

and dropped it into OF on 9/2/10, it would translate into:

Title---------------------|Start Date|Due Date|
call Bob re: giant robot|Sept 9 |Sept 30|

Unfortunately, the date information goes into a metafield.

RobTrew 2010-09-02 02:10 PM

You should be able to translate your column of 2d 3w 5m strings into an adjacent column of real dates (exportable to OF) by selecting your oo3 source column (click its header to make the whole column blue), and then running an applescript like this, which will create a new column next to it, containing dates calculated as today+3w (three weeks) etc.

[CODE]set dteToday to date (short date string of (current date))

tell application id "com.omnigroup.OmniOutlinerPro3"
tell front document
set oSrcCol to first selected column
on error
display dialog "No column selected ..." & return & return & ¨
"Select column containing 1d 2w 3m etc, and run the script again"
end try
set idSrc to id of oSrcCol
set oTgtCol to make new column at after oSrcCol with properties {name:"Resulting Dates", type:date}
set idTgt to id of oTgtCol

repeat with oRow in rows
copy dteToday to dteBase
set strDelta to value of cell id idSrc of oRow
set dteResult to my DatePlus(dteBase, strDelta)
if dteResult is not missing value then set value of cell id idTgt of oRow to dteResult
end repeat
end tell
end tell

on DatePlus(dte, strNUnits)
copy dte to dteNew
if length of strNUnits < 2 then return missing value
set strUnit to last character of strNUnits
set lngDelta to (text 1 thru ((length of strNUnits) - 1) of strNUnits) as integer
on error
return missing value
end try
ignoring case
if strUnit = "d" then
return dteNew + lngDelta * days
else if strUnit = "w" then
return dteNew + lngDelta * weeks
else if strUnit = "y" then
set (year of dteNew) to (year of dteNew) + lngDelta
return dteNew
else if strUnit = "m" then
-- Get current month and year
set lngMonth to (month of dteNew) * 1
set lngYear to (year of dteNew)

-- and simply add the increment to the month,
-- negative possibly getting something negative, and/or too large
set lngNewMonth to lngMonth + lngDelta

-- get the YEAR
set lngDateMonth to lngNewMonth mod 12
set lngYearDelta to lngNewMonth div 12

-- if we have gone down to a negative month, we are already in the previous year,
-- regardless of any multiples of 12
if lngDateMonth ≤ 0 then set lngYearDelta to (lngYearDelta - 1)
if lngYearDelta is not 0 then
set lngDateYear to lngYear + lngYearDelta
set lngDateYear to lngYear
end if

-- and the MONTH
if lngDateMonth is 0 then
set lngDateMonth to 12
else if lngDateMonth < 0 then
set lngDateMonth to (12 + lngDateMonth)
end if

-- and update the date variable
if lngYear is not lngDateYear then set (year of dteNew) to lngDateYear
if lngMonth is not lngDateMonth then set (month of dteNew) to lngDateMonth
return missing value
end if
end ignoring
end DatePlus

whpalmer4 2010-09-02 03:01 PM

That still leaves the mismatched duration problem, though.

I was thinking of a script that just took a row from OO, put it in the form [i]action @context #start date #due date $duration[/i] and then used the parse tasks verb to turn it into inbox fodder...but I bet you can code it faster than I can :-)

RobTrew 2010-09-02 03:13 PM

:-) The current snippet assumes (possibly incorrectly) that Steve has has been typing into a Rich Text Field, so it's just processing strings rather than duration numbers.

If his data is in fact already numeric, then it would certainly be interesting to try your parse tasks route :-)

steve 2010-09-02 03:22 PM

I just tested this out and I am SO grateful Rob for your script. This has been a nagging issue for me for such a long time. Yippee! I can now define project templates for my team and share them in a format that people can understandó i.e. I can create a PDF from OmniOutliner that they can hang on their bulletin board or a CSV file that they can add to a spreadsheet, or whatever. I can encourage them to import the template into OmniFocus as it is better, but it creates options. Awesome job.

FWIW, I personally don't need the duration fieldó just title, context, start, due.

steve 2010-09-02 03:27 PM

I had played with changing the column type to duration, but it is easier to just use the rich text field and write 1m, 2d, 5w, etc.

Thanks Rob and WH!

whpalmer4 2010-09-02 04:29 PM

Couldn't leave well enough alone, so I cobbled a very rough script together :-)


tell front document of application "OmniOutliner Professional"
set theCount to (count of selected rows)
set theTasksStr to ""

repeat with i from 1 to theCount
-- convert Action Context StartDate DueDate Duration to
-- action @context #start date #due date $duration
set theTasksStr to text of cell 2 of (item i of selected rows) & " @" & text of cell 3 of (item i of selected rows) & " #" & text of cell 4 of (item i of selected rows) & " #" & text of cell 5 of (item i of selected rows) & " $" & text of cell 6 of (item i of selected rows)
-- parse tasks as single task appears to be broken, always get a single multi-line task, so do it one row at a time
tell application "OmniFocus"
tell front document
parse tasks with transport text theTasksStr
end tell
end tell

end repeat

end tell


Did turn up what looks to be a bug, though! parse tasks takes an optional argument to control whether a multi-line input generates multiple rows or a single row, but in actual practice, you always get one row, it seems.

All times are GMT -8. The time now is 10:36 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2021, vBulletin Solutions, Inc.