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

Apply a date mask to an Epoch timestamp (UDF)

Comments

Damon

Damon wrote on 04/07/11 8:20 AM

The Java Date object takes the Epoch milliseconds value. Why not just use createObject("java", "java.util.Date").init(epochMS) instead? You would never have to trim the MS off like you are doing in your example. The CF Date object inherits from java.util.Date so you can still pass it to CF date functions.
Steve

Steve wrote on 04/07/11 4:29 PM

Thanks Damon. That's what I love about putting a post up; I can always rely on someone quickly showing me a better way to do something :). I'll update the post later with your suggestion.
Damon

Damon wrote on 04/07/11 7:02 PM

I forgot to mention, you may need to javaCast() the epochMS you pass to the init:
createObject('java', 'java.util.Date').init(javaCast('long', epochMS));
Steve

Steve wrote on 04/10/11 10:25 PM

Thanks Damon again! I've updated the post with an alternative version of the UDF using the approach you suggested. I've left the post showing both options in case anyone has a shared hosting package that disables the ability to use CreateObject('Java') (ie. GoDaddy, Net24, etc.)

Leave a comment

Tell us about yourself
(required field)
(required field)
Comment and preferences
Leave this field empty: