No Clean Feed - Stop Internet Censorship in Australia

Entries Tagged as 'ColdFusion'

Apply a date mask to an Epoch timestamp (UDF)

What is Epoch time?

Not the 1970 Epoch"The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). Literally speaking the epoch is Unix time 0 (midnight 1/1/1970), but 'epoch' is often used as a synonym for 'Unix time'. Many Unix systems store epoch dates as a signed 32-bit integer, which might cause problems on January 19, 2038 (known as the Year 2038 problem or Y2038)."
- epochconverter.com

What am I talking about?

In recent work I came across a database table that was storing Epoch timestamp values. I'm sure there are other UDFs out there to convert Epoch timestamps to a readable disply format, but I thought I'd give it ago anyway.

I came across a ColdFusion Cookbook sample that fit the scenario perfectly, written by Rob Brooks-Bilson. It explains the process of converting an Epoch seconds timestamp to a Date object. This was my base.

With a few additions, my UDF became (apologies for the formatting):

<cffunction name="applyMaskToEpoch"
returntype="string"
output="no">


<cfargument name="epochTimestamp"
type="numeric"
required="true"
hint="Epoch timestamp (10-13 digit numeric string)." >


<cfargument name="dateMask"
type="string"
required="false"
default="dd mmmm yyyy"
hint="Date mask pattern (Eg. dd mmmm yyyy)." >


<cfargument name="timeMask"
type="string"
required="false"
default="h:mm:ss tt"
hint="Time mask pattern (Eg. hh:mm:ss tt)." >


<cfargument name="delimeter"
type="string"
required="false"
default=", "
hint="Delimeter to be placed between date and time output." >


<cfset var sEpochTimestamp = left(arguments.epochTimestamp,10) >
<cfset var sDateMask = arguments.dateMask >
<cfset var sTimeMask = arguments.timeMask >
<cfset var objDateTime = "" >
<cfset var sFormattedDate = "" >
<cfset var sFormattedTime = "" >
<cfset var sDelimeter = arguments.delimeter >
<cfset var sResult = "" >

<cfset objDateTime = DateAdd("s",sEpochTimestamp,DateConvert("utc2Local", "January 1 1970 00:00")) >
<cfset sFormattedDate = DateFormat( objDateTime, sDateMask ) >
<cfset sFormattedTime = TimeFormat( objDateTime, sTimeMask ) >
<cfset sResult = sFormattedDate & sDelimeter & sFormattedTime >

<cfreturn sResult />
</cffunction>

Example usage:

<cfset iEpochTimestamp = getTickCount() >
<cfoutput>
#applyMaskToEpoch(iEpochTimestamp,'d-mmm-yy','h:mm:ss tt',', ')#
</cfoutput>

Example output:

7-Apr-11, 3:51:25 PM
(where the Epoch seconds value from getTickCount() was 1302155485932)

UPDATE:

Thanks Damon for your comments below regarding an alternative approach that will allow you to display a date/time including milliseconds, by utilitsing Java's Date class directly. Applying the changes Damon has suggested, we end up with the following version of the UDF:

<cffunction name="applyMaskToEpoch"
returntype="string"
output="no">


<cfargument name="epochTimestamp"
type="numeric"
required="true"
hint="Epoch timestamp (13 digit numeric string)." >


<cfargument name="dateMask"
type="string"
required="false"
default="dd mmmm yyyy"
hint="Date mask pattern (Eg. dd mmmm yyyy)." >


<cfargument name="timeMask"
type="string"
required="false"
default="h:mm:ss:L tt"
hint="Time mask pattern (Eg. hh:mm:ss:L tt)." >


<cfargument name="delimeter"
type="string"
required="false"
default=", "
hint="Delimeter to be placed between date and time output." >


<cfset var sEpochTimestamp = arguments.epochTimestamp >
<cfset var sDateMask = arguments.dateMask >
<cfset var sTimeMask = arguments.timeMask >
<cfset var objDateTime = "" >
<cfset var sFormattedDate = "" >
<cfset var sFormattedTime = "" >
<cfset var sDelimeter = arguments.delimeter >
<cfset var sResult = "" >

<cfset objDateTime = createObject('java', 'java.util.Date').init(javaCast('long', sEpochTimestamp)) >
<cfset sFormattedDate = DateFormat( objDateTime, sDateMask ) >
<cfset sFormattedTime = TimeFormat( objDateTime, sTimeMask ) >
<cfset sResult = sFormattedDate & sDelimeter & sFormattedTime >

<cfreturn sResult />
</cffunction>

Example usage (added millisecond mask 'L'):

<cfset iEpochTimestamp = getTickCount() >
<cfoutput>
#applyMaskToEpoch(iEpochTimestamp,'d-mmm-yy','h:mm:ss:L tt',', ')#
</cfoutput>

Example output:

11-Apr-11, 2:11:58:714 PM
(where the Epoch seconds value from getTickCount() was 1302495118714)

Download (.zip): demo & source (includes three variations of the UDF)

A few notes:

  • As far as I know, since ColdFusion MX getTickCount() has been returning an Epoch seconds timestamp value. The length of this value is 13 digits. In this UDF and the ColdFusion Cookbook example (in the comments regarding Java Epoch) you should note that Left(str,10) is used to trim the Epoch numeric string value to the required 10 digits in length.
  • I'm not sure if getTickCount() returned am Epoch seconds value before ColdFusion MX.
  • Thanks to Damon's comments (below) it has been pointed out that Java's Date class can be utilised instead, to get the same result. Taking this route also means trimming of the Epoch value down to 10 digits is not required - allowing you to use the full 13 digit Epoch millisecond value. This will of course also now allow you to display milliseconds if you wish.
  • If you are running your site on a shared host that disables the use of CreateObject('Java') (ie. GoDaddy, Net24, and many others unfortunately), the second UDF is not for you. The first one should work though.
  • The image in the post obviously has nothing to do with Epoch. Although, when I say "Epoch" in my head it always reminds me of Ewok.
Further reading:

Bookmark and ShareSubscribe

Vague CFSpreadsheet POIFSFileSystem error message

For what it's worth, the inclusion of CFSpreadsheet and all the associated functions in ColdFusion 9 is a very welcome update. It's enabled me to generate some very complex and impressively formatted documents with relative ease.

One thing I'm working on requires my client to send me import data spreadsheets that I run through the new application (in development) and pull into the database. One particular file happened to have a password associated with reading it - total brain fart that I missed this. I even opened it previously when first receiving it with the password and it didn't twig. So duh to me.

Anyway, using CFSpreadsheet to read this file in quickly ends with the error response:

An error occurred while reading the Excel: java.lang.IllegalArgumentException: The supplied POIFSFileSystem does not contain a BIFF8 'Workbook' entry. Is it really an excel file?.

Oh as a side note, I love how the error message actually asks me a question. It's like it has a sense of humour. I even attempted opening the file in WinRar and got an error message that was just as vague.

As you can see it's not really the most helpful of error messages but to cut a long story short it is the result of the file have password protection. I would have assumed that a password protected file would come back with an authentication error message, but maybe the POI libraries are vague on this when throwing the error. I imagine maybe the data is encrypted which is not recognised                  until Excel loads the contents of the file, hence prompting you to enter a password. Who knows.

Oddly, it seems that write and update actions for CFSpreadsheet have attributes for using a password, but not read. Anyone please let me know otherwise as it would be helpful (CF9 Docs http://goo.gl/QDwM).

So, the lesson learnt. Yes, always check "Is it really an excel file?" and of course keep in mind that password protected files might also cause vague misleading error response messages. It does make sense of course than error would be thrown and I should have checked first to see if the file had a password first. That would have solved my problem right off the bat!

Bookmark and ShareSubscribe

cfajaxproxy exposing CFC path in page source

[Edit: The following post has been edited/re-worded in an attempt to clear up it's meaning]

I've been playing around with ColdFusion's cfaxajproxy and loving it. I was interested however to find that when the page is rendered in the browser, cfajaxproxy outputs (in the source code) the full path [Edit: literal relative path] to the CFC I'm having it call.

Example:

Source output (Javascript):
var _cf_Expertise=ColdFusion.AjaxProxy.init('/x/y/z/Expertise.cfc','expertiseCFC');

I tried using a Mapping in the CF Admin to the directory (under my webroot) containing my CFCs but still the full path [Edit: literal relative path] from root to my CFC is exposed.

Example:
Mapping made in CF Admin
"/mapping" -> "c:/.../x/y/z/"

Source output (Javascript):
var _cf_Expertise=ColdFusion.AjaxProxy.init('/x/y/z/Expertise.cfc','expertiseCFC');

When I created a Mapping to a folder *above* the webroot containing my CFC the source output changed to include the mapping reference (this is the behaviour/output I wanted, just without having to have the folder containing the CFC above the webroot).

Example:
Mapping made in CF Admin
"/mapping" -> "c:/.../{folder above web root}/"

Source output (Javascript):
var _cf_Expertise=ColdFusion.AjaxProxy.init('/mapping/Expertise.cfc','expertiseCFC');

Why is it that (using the CF Admin mapped path) when the CFC folder is above the webroot cfaxajproxy outputs the shorter mapped reference to the Javascript source code but when the CFC folder is under the webroot the full relative path from the webroot to the CFC is exposed in the Javascript source code? Is there a way around this so that the mapping is always output (I need my CFCs within the webroot, not above)?

[Edit: Additional Info]

This is how I am calling cfajaxproxy:

<cfajaxproxy
cfc = "mapping.Expertise"
jsclassname = "expertiseCFC" />

Where "mapping" is the virtual Mapping reference set within CF Admin.

Bookmark and ShareSubscribe