f/code Edited 13 days ago

A CF function to mimic moment.js fromNow() functionality

A function to mimic moment.js fromNow() functionality

	/**
	 * momentFrom( target, reference=now(), withoutSuffix=false )
	 * Mimics moment(a).from(b) - assumes all dates are in UTC.
	 */
	function momentFrom( required any target, any reference=now(), boolean withoutSuffix=false ){
		// Java time classes
		var ZoneId        = createObject("java","java.time.ZoneId");
		var Instant       = createObject("java","java.time.Instant");
		var ZonedDateTime = createObject("java","java.time.ZonedDateTime");
		var Duration      = createObject("java","java.time.Duration");
		// Force UTC zone
		var zone = ZoneId.of("UTC");
		// Normalize to ZonedDateTime in UTC
		var toZDT = function(any x){
			if (isNumeric(x)) {
				var n = javacast("long", x);
				var ms = (n GT 9999999999) ? n : n * 1000; // seconds -> ms
				return Instant.ofEpochMilli( javacast("long", ms) ).atZone( zone );
			}
			var d = x;
			if ( !isInstanceOf(d, "java.util.Date") ) {
				d = parseDateTime( javacast("string", x) );
			}
			// CF date is a java.util.Date (implicitly UTC here)
			return Instant.ofEpochMilli( javacast("long", d.getTime()) ).atZone( zone );
		};
		var t   = toZDT( arguments.target );
		var ref = toZDT( arguments.reference );
		var seconds = Duration.between( ref, t ).getSeconds(); // >0 = future
		var future  = (seconds GT 0);
		var absSec  = abs( seconds );
		var days    = absSec / 86400;
		var value = 0;
		var unit  = "";
		var phrase = "";
		// Moment.js thresholds (rounded to largest unit)
		if (absSec < 45) {
			phrase = "a few seconds";
		} else if (absSec < 90) {
			phrase = "a minute";
		} else if (absSec < 45*60) {
			value  = round(absSec/60);
			unit   = (value EQ 1 ? "minute" : "minutes");
			phrase = "#value# #unit#";
		} else if (absSec < 90*60) {
			phrase = "an hour";
		} else if (absSec < 22*3600) {
			value  = round(absSec/3600);
			unit   = (value EQ 1 ? "hour" : "hours");
			phrase = "#value# #unit#";
		} else if (absSec < 36*3600) {
			phrase = "a day";
		} else if (days < 26) {
			value  = round(days);
			unit   = (value EQ 1 ? "day" : "days");
			phrase = "#value# #unit#";
		} else if (days < 45) {
			phrase = "a month";
		} else if (days < 320) {
			value  = round(days/30);
			unit   = (value EQ 1 ? "month" : "months");
			phrase = "#value# #unit#";
		} else if (days < 548) {
			phrase = "a year";
		} else {
			value  = round(days/365);
			unit   = (value EQ 1 ? "year" : "years");
			phrase = "#value# #unit#";
		}
		if (arguments.withoutSuffix) {
			return phrase;
		}
		return future ? "in #phrase#" : "#phrase# ago";
	}

Comments

No comments yet. Log in to start the conversation.

f/code

Code and anything code related

Created Dec 12, 2025

2
Members

Moderators
u/rob u/admin