Skip to content

Instantly share code, notes, and snippets.

@JamoCA
Last active July 28, 2023 17:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamoCA/3e825f773d3bbb45f5c36ee85793e10e to your computer and use it in GitHub Desktop.
Save JamoCA/3e825f773d3bbb45f5c36ee85793e10e to your computer and use it in GitHub Desktop.
createIsoString - ColdFusion/CFML UDF - Converts date object/string into a UTC, ISO8601, RFC 339, ATOM or W3C string to a timezone with offset and optional millisecond precision
/* createIsoString UDF by James Moberg / SunStar Media
2023-07-16
Gist: https://gist.github.com/JamoCA/3e825f773d3bbb45f5c36ee85793e10e
Blog: https://dev.to/gamesover/createisostring-a-coldfusion-user-defined-function-udf-to-replace-datetimeformatiso-2p15
Tweet: https://twitter.com/gamesover/status/1680711586946891776
*/
public string function createIsoString(string date="", string timezone="local", string truncatedTo="MILLIS", string format="utc", boolean throwOnError=true) output=false hint="Converts date object/string into a UTC, ISO8601, RFC 339, ATOM or W3C string to a timezone with offset and optional millisecond precision" {
if (!len(arguments.date) || arguments.date eq "now"){
arguments.date = now();
};
if(!isvalid("date", arguments.date)){
if (arguments.throwOnError) {
throw(message="createIsoString: Can't convert value [#encodeforhtml(arguments.date)#] to a datetime value");
}
return "";
}
if (arguments.throwOnError && len(arguments.truncatedTo) && !listfindnocase("DAYS,HALF_DAYS,HOURS,MINUTES,SECONDS,MILLIS", arguments.truncatedTo)){
throw(message="createIsoString: Can't truncate date using value [#encodeforhtml(arguments.truncatedTo)#]");
}
// cache java classes within current request
if (!structkeyexists(request, "createIsoStringJava")){
request.createIsoStringJava = [
"offsetDateTime": createobject("java", "java.time.OffsetDateTime")
,"dateTimeFormatter": createobject("java", "java.time.format.DateTimeFormatter")
,"chronoUnit": createobject("java", "java.time.temporal.ChronoUnit")
,"zoneId": createobject("java", "java.time.ZoneId")
];
request.createIsoStringJava["zoneIdList"] = "," & request.createIsoStringJava.zoneId.getAvailableZoneIds().toString().replaceAll("[\[\] ]","") & ",";
request.createIsoStringJava["units"] = [
"DAYS": request.createIsoStringJava.ChronoUnit.DAYS
,"HALF_DAYS": request.createIsoStringJava.ChronoUnit.HALF_DAYS
,"HOURS": request.createIsoStringJava.ChronoUnit.HOURS
,"MILLIS": request.createIsoStringJava.ChronoUnit.MILLIS
,"MINUTES": request.createIsoStringJava.ChronoUnit.MINUTES
,"SECONDS": request.createIsoStringJava.ChronoUnit.SECONDS
];
}
// validate timezone
local.tzRegex = (refind("[^a-zA-Z0-9\/\_]", arguments.timezone)) ? rereplace(arguments.timezone, "(?=[\[\]\\^$.|?*+()])", "\", "all") : arguments.timezone;
local.zoneIdPos = refindnocase(",#local.tzRegex#,", request.createIsoStringJava.zoneIdList);
if (arguments.throwOnError && len(arguments.timezone) && !listfindnocase("local,server", arguments.timezone) && !local.zoneIdPos){
throw(message="createIsoString: timezone value [#encodeforhtml(arguments.truncatedTo)#] is not valid.");
}
local.isoDateRegex = "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)((-(\d{2}):(\d{2})|Z)?)$";
if (refind(local.isoDateRegex, arguments.date)){
local.date = request.createIsoStringJava.OffsetDateTime.parse(arguments.date);
} else {
local.timeString = javacast("string", datetimeformat(arguments.date, "yyyy-mm-dd'T'HH:nn:ss.lllZ"));
local.date = request.createIsoStringJava.OffsetDateTime.parse(local.timeString, request.createIsoStringJava.dateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"));
}
// timezone is valid, use the correct capitalization
if (local.zoneIdPos gt 0){
local.date = local.date.atZoneSameInstant(request.createIsoStringJava.zoneId.of( mid(request.createIsoStringJava.zoneIdList, local.zoneIdPos+1, len(arguments.timezone)) ));
}
// perform optional truncation
if (structkeyexists(request.createIsoStringJava.units, arguments.truncatedTo)){
local.date = local.date.truncatedTo( request.createIsoStringJava.units[arguments.truncatedTo] );
}
// format the date to ISO 8601 w/offset
local.isoFormat = request.createIsoStringJava.dateTimeFormatter.ISO_OFFSET_DATE_TIME;
local.formattedDate = local.isoFormat.format(local.date).toString();
if (find("8601", arguments.format) || findnocase("iso", arguments.format)){
return local.formattedDate.replaceAll("Z$", "\+0000"); // ISO-8601 = +0000
} else if (find("3339", arguments.format) || findnocase("atom", arguments.format) || findnocase("w3c", arguments.format)){
return local.formattedDate.replaceAll("Z$", "\+00\:00"); // RFC 3339, ATOM or W3C = +00:00
}
return local.formattedDate;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment