Last active
July 28, 2023 17:10
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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