Reading Date from a file giving date error

HI,

I’m reading a date string from a text file but get an error converting it to an actual date and don’t know why.

This works fine

set date_string to “02.11.09”
log “Test:” & date_string
set x to date date_string

but when I read that same string from the file and try to convert it, it fails with 'Invalid date and time date 02.11.09 -30720

My Code

– Get a list of all the files
do shell script “mdfind -onlyin /Users/Barry/Downloads/Test ‘(kMDItemFSName = "*.txt")’”

repeat with aFile in (get paragraphs of result)

-- Does not work when I'm reading the date string from the file?
set TestDDD to (read (POSIX file aFile as alias) from 3 for 15)
log "Test:" & TestDDD

try
	set x to date TestDDD
	
on error error_string number error_number
	log "Error:" & error_string & " " & error_number
end try

end repeat

Output showing the error:

tell current application
do shell script “mdfind -onlyin /Users/Barry/Downloads/Test ‘(kMDItemFSName = "*.txt")’”
→ “/Users/Barry/Downloads/Test/TestFile.txt”
read alias “MacMini HD:Users:Barry:Downloads:Test:TestFile.txt” from 3 for 15
→ “02.11.09”
(Test:02.11.09)
(Error:Invalid date and time date 02.11.09. -30720)
(Test:02.11.09)
end tell

I’m guessing it’s the format of the file somehow. The date in bold seems to indicate it’s been read ok?

Thanks

Barry

Hi, Barry. Welcome to MacScripter.

It looks like it. You’re reading 15 bytes from the file and only getting 8 visible characters. I don’t know why you’ve started at the third byte, but to guess from the clues, I’d say that the text in the file is UTF-16 Unicode text and the first two bytes are a UTF-16 byte-order mark. If that’s the case, then your problem will be solved by reading the file like this:

set TestDDD to (read (POSIX file aFile as alias) as Unicode text for 18) -- 2-byte BOM + eight 2-byte characters

‘as Unicode text’ isn’t a coercion here, but a parameter of the ‘read’ command which tells it how to interpret the data in the file.

If that’s all there is in the file, you can leave out the ‘for 18’.

Hello

It seems that what you posted doesn’t match the real behavior.

I ran this script :


set aFile to (path to desktop as text) & "testfile.txt"
set TestDDD to ""
-- Does not work when I'm reading the date string from the file?
set TestDDD to (read file aFile from 3 for 15)
log "Test:" & TestDDD

try
	set x to date TestDDD
	
on error error_string number error_number
	log "Error:" & error_string & " " & error_number
end try

And got this log report :


tell current application
	path to desktop as text
		--> "Macintosh HD:Users:yvankoenig:Desktop:"
	read file "Macintosh HD:Users:yvankoenig:Desktop:testfile.txt" from 3 for 15
		--> "02.11.09. -3072"
	(*Test:02.11.09. -3072*)
end tell
Résultat :
date "lundi 2 novembre 2009 00:00:00"

As you may see, the grabbed string doesn’t end with the zero which you posted. It’s logical as you asked the app to read 15 characters. To get the zero you would read 16 ones.

Why are you reading 15 characters when you compare to the behavior of a string whose length is 8 (02.11.09) ?

In practice, AppleScript deciphers only the beginning string 02.11.09 as is demonstrated by this other report :


tell current application
	path to desktop as text
		--> "Macintosh HD:Users:yvankoenig:Desktop:"
	read file "Macintosh HD:Users:yvankoenig:Desktop:testfile.txt" from 3 for 15
		--> "02.11.09. abcde"
	(*Test:02.11.09. abcde*)
end tell
Résultat :
date "lundi 2 novembre 2009 00:00:00"

I made my tests under 10.7.4

Yvan KOENIG (VALLAURIS, France) dimanche 10 juin 2012 09:48:53

Hi, Yvan.

The “-30720” in Barry’s log was the error number from the ‘try’ block! I get exactly the same result when I save “02.11.09” as UTF-16 from TextEdit and try to read the file with your script. However, adding ‘as Unicode text’ as a parameter to the ‘read’ command, as I suggested above, produces an eight-character text which can successfully be used in a date specifier (on machines where the preferences are for a ddmmyyyy short-date format).

Barry: I forgot to explain in my own post that without an ‘as’ parameter, ‘read’ assumes that the file contains text made up of 8-bit characters, so the string you were getting actually contained fifteen characters, only eight of which were visible. That’s why AppleScript considered it an “invalid date and time”.

Thanks Nigel

It appears that I read too fast :frowning:

Yvan KOENIG (VALLAURIS, France) dimanche 10 juin 2012 23:04:48

Dear Nigel,

I have been working on a really simple script for days to make it perform faster. I have a belief that you might have the answer to help me after reading this thread. I hope I am not mistaken.

If you check my simple script you will see that I am trying to parse a log file into a list. I have successfully ached that but my main problem is to sort them according to date in Applescript studio. The problem is my list needs to have the date not as a string instead it needs to be a proper date. When a covert the proper items to date my applescript application (applescript studio) can sort it as I want. But the conversion takes a long time. Parsing till the conversion only takes 0.3 seconds but the conversion takes 12 seconds.

Please check my script and let me know your thoughts.

Thanks,
Koray Birand



set log01 to {}
set log01Ref to a reference to log01

-- you can download the log file that I am using from http://koraybirand.co.uk/temp2.txt
set aa to read POSIX file "Users/kbirand/Desktop/temp2.txt"
set bb to every paragraph of aa
set bbRef to a reference to bb
set aa to ""

set olddel to text item delimiters of AppleScript
set text item delimiters of AppleScript to ","


set totalrecs to count bb

repeat with i from 1 to totalrecs
	set a to (text items of item i of bbRef)
	set end of log01Ref to a
end repeat

repeat with k from 1 to totalrecs
	-- below line I use to convert string to date for column number 5 -- this line slows down the whole script. I am trying to finder a better solution.
	set item 5 of item k of log01Ref to date (item 5 of item k of log01Ref)
end repeat



set text item delimiters of AppleScript to olddel



Hello

You may try :


set log01 to {}
set log01Ref to a reference to log01

-- you can download the log file that I am using from http://koraybirand.co.uk/temp2.txt
set aa to read file POSIX file "Users/kbirand/Desktop/temp2.txt"
set bb to every paragraph of aa
set bbRef to a reference to bb
set aa to ""

set olddel to text item delimiters of AppleScript
set text item delimiters of AppleScript to ","

repeat with aRec in bbRef
	set a to (text items of aRec)
	set item 5 of a to date (item 5 of a)
	set end of log01Ref to a
end repeat


set text item delimiters of AppleScript to olddel

As you already have individual records available in the loop, it seems logical to apply the required task then.
So you spare most of the time required by the now dropped second loop.

Yvan KOENIG (VALLAURIS, France) vendredi 19 octobre 2012 11:05:12

Yvan,

Thanks, for your reply. Have you tried the script you have sent me , it takes exactly the same amount of time as my script. The problem is the date conversion. I am not in front of my Mac pro but I am running the script you have sent me and my initial script. It takes 35 seconds.

Thanks,
Koray Birand

Yes I ran the edited script before posting.
Here it requires 10 seconds to treat the referenced text file.

The described changes seemed to be able to drop a lot of job so I didn’t ran the original version.

Given your message, I ran your script and it required 10 seconds too.

Yvan KOENIG (VALLAURIS, France) vendredi 19 octobre 2012 12:04:42

To populate the text file to a list takes only .3 seconds a a mac pro. So There should be an other method to define the date column, converting the string to date (formatting) takes really long, and especially when this list grows it is going to take even more.

Or there should be another way when I append my list to a table ( Xcode 3.2.6 / applescript application) to define the 5th column so that it treats every data within that column as date not as string.

So I am looking for an answer to either populate the list faster (may be when parsing it not after parsed).
or when appending the list to a table to define a specific column as a date column.

Best,
Koray

With data like that, you can speed things up a bit because each entry is not a new date. Roughly like this:

set prevString to ""
set prevDate to ""
repeat with k from 1 to totalrecs
	set newString to (item 5 of item k of log01Ref)
	if newString is not prevString then
		set prevString to newString
		set prevDate to date newString
	end if
	set item 5 of item k of log01Ref to prevDate
end repeat

But that’s still going to take a bit of time.

Bingo Shane.

This redesigned script :


property bb : {}

set avant to current date
-- you can download the log file that I am using from http://koraybirand.co.uk/temp2.txt
set my bb to paragraphs of (read file POSIX file "Users/kbirand/Desktop/temp2.txt")
set partiel to (current date) - avant

set prevString to ""
set prevDate to ""
set olddel to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","
set cntRec to count my bb
repeat with k from 1 to cntRec -- in my bb
	set txtItems to text items of item k of my bb
	set newstring to (item 5 of txtItems)
	if newstring is not prevString then
		set prevString to newstring
		set prevDate to date newstring
	end if
	set item 5 of txtItems to prevDate
	set item k of my bb to txtItems
end repeat
set final to (current date) - avant
log partiel
log final
set AppleScript's text item delimiters to olddel
set my bb to {}

did the job in ONE second.

Now I feel free to ask what’s the need for this script ?
If it’s to insert the datas in a spreedsheet, there is no need to convert strings to dates.
The spreadsheet would do the job efficiently.

Yvan KOENIG (VALLAURIS, France) vendredi 19 octobre 2012 15:09:07

Hi Koray. Welcome to MacScripter.

This (incorporating Shane’s idea, which I saw when I came on line to post it!) seems a trifle faster:

on prepareList(textFilePath)
	if (textFilePath's class is text and textFilePath begins with "/") then set textFilePath to textFilePath as POSIX file as text
	tell (current date) to set {its day, its year, its month, its day, its time, templateDate} to {1, 2000, January, 1, 0, it}
	set comma to ","
	set fullstop to "."
	set prevDateText to ""
	
	script o
		property lst : missing value
	end script
	
	set o's lst to paragraphs of (read file textFilePath)
	
	set astid to AppleScript's text item delimiters
	repeat with i from 1 to (count o's lst)
		set AppleScript's text item delimiters to comma
		set item i of o's lst to text items of item i of o's lst
		set dateText to item 5 of result
		if (dateText is not prevDateText) then
			copy templateDate to ASDate
			set AppleScript's text item delimiters to fullstop
			tell ASDate to set {its day, its month, its year} to dateText's text items
			set prevDateText to dateText
		end if
		set item 5 of item i of o's lst to ASDate
	end repeat
	set AppleScript's text item delimiters to astid
	
	return o's lst
end prepareList

prepareList(POSIX path of ((path to desktop as text) & "temp2.txt"))
item 1 of result -- To save having to wait for AppleScript Editor render the entire list in its Result pane.

But if those are times in the last column, you may want to include them in the dates:

on prepareList(textFilePath)
	if (textFilePath's class is text and textFilePath begins with "/") then set textFilePath to textFilePath as POSIX file as text
	tell (current date) to set {its day, its year, its month, its day, its time, templateDate} to {1, 2000, January, 1, 0, it}
	set comma to ","
	set fullstop to "."
	set colon to ":"
	set prevDateText to ""
	
	script o
		property lst : missing value
	end script
	
	set o's lst to paragraphs of (read file textFilePath)
	
	set astid to AppleScript's text item delimiters
	repeat with i from 1 to (count o's lst)
		set thisLine to item i of o's lst
		set AppleScript's text item delimiters to comma
		set item i of o's lst to text items 1 thru 4 of thisLine
		set {dateText, timeText} to text items 5 thru 6 of thisLine
		if (dateText is prevDateText) then
			copy ASDate to ASDate
		else
			copy templateDate to ASDate
			set AppleScript's text item delimiters to fullstop
			tell ASDate to set {its day, its month, its year} to dateText's text items
			set prevDateText to dateText
		end if
		set AppleScript's text item delimiters to colon
		tell timeText's text items to set ASDate's time to beginning * hours + (item 2) * minutes + end
		set end of item i of o's lst to ASDate
	end repeat
	set AppleScript's text item delimiters to astid
	
	return o's lst
end prepareList

prepareList(POSIX path of ((path to desktop as text) & "temp2.txt"))
item 1 of result -- To save having to wait for AppleScript Editor to render the entire list in its Result pane.

Dear Nigel,

First of all I must say that i am sorry that I could not thank you sooner.
You code has been really helpful. Great solution. And also thought me a lot of other things
as well.

Again, thank you so much.

Koray Birand