Announcing Jactl 2.4.0
Jactl 2.4.0 is a new release with enhancements and bug fixes.
This release provides new date/time classes and also adds the ability to extend the language with new built-in types.
Enhancements
#95 Ability to add new built-in types
This enhancement makes it possible for applications embedding Jactl to provided their own classes to be
used as built-in types within the Jactl scripts and classes, adding to the existing list of built-in types
such as List, Map, String, etc.
For example, consider this Point class:
package app.jactl;
public class Point {
public double x, y;
Point(double x, double y) { this.x = x; this.y = y; }
public static Point of(double x, double y) { return new Point(x,y); }
public double distanceTo(Point other) {
return Math.sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y));
}
}
To register it as a new built-in type called Point we just need to do this:
JactlType pointType = Jactl.createClass("jactl.draw.Point")
.javaClass(app.jactl.Point.class)
.autoImport(true)
.method("of", "of", "x", double.class, "y", double.class)
.method("distanceTo", "distanceTo", "other", Point.class)
.register();
Then, this type can be used by Jactl scripts:
Point p = Point.of(1,2)
p.distanceTo(Point.of(3,4)) // result: 2.8284271247461903
See Adding New Built-In Types for more details.
#96 New date/time built-in types
The ability to add new built-in types was used to provide new date/time classes as built-in types in Jactl by
exposing the existing java.time.* classes.
The following Jactl classes now exist as built-in types in Jactl:
- jactl.time.LocalTime
- jactl.time.LocalDate
- jactl.time.LocalDateTime
- jactl.time.ZonedDateTime
- jactl.time.Instant
- jactl.time.Period
- jactl.time.Duration
- jactl.time.ZoneId
Examples:
// Creating instances — use parse(), of(), or now():
LocalTime t = LocalTime.parse('10:11:12.123456789')
LocalDate d = LocalDate.of(2026, 2, 26)
LocalDateTime dt = LocalDateTime.now()
ZonedDateTime zdt = ZonedDateTime.parse('2026-02-26T10:11:12+00:00[UTC]')
Instant i = Instant.ofEpochMilli(1772100672123L)
// Manipulating values — methods return new instances:
d.plusDays(5).plusMonths(3) // 2026-06-03
dt.minusWeeks(2) // 2026-02-15T15:00:36.536
zdt.withYear(1969) // 1969-02-26T10:11:12Z[UTC]
t.truncatedToMillis() // 10:11:12.123
// Formatting and querying:
d.format('yyyy MMM dd') // 2026 Feb 26
dt.getDayOfWeek() // 'SUNDAY'
d.isLeapYear() // false
i.getEpochSecond() // 1772100672
// Duration and Period for arithmetic:
Period p = Period.of(1, 2, 3) // P1Y2M3D
d.minus(Period.ofDays(27)) // 2026-01-30
Duration.between(dt, zdt) // PT-76H-49M-24.536S
t.until(t.plusHours(1)) == Duration.ofHours(1) // true
// Converting between types:
d.atTime(LocalTime.parse('10:11:12')) // LocalDateTime
dt.atZone(ZoneId.of('UTC')) // ZonedDateTime
zdt.toLocalDate() // LocalDate
t.atDate(d) // LocalDateTime
See Date/Type Types for more details.
