BoxLang provides comprehensive date and time functionality through its DateTime object and extensive collection of temporal Built-in Functions (BIFs). All date and time operations in BoxLang work with the unified DateTime type, which internally wraps Java's ZonedDateTime to provide robust timezone and formatting support.
The DateTime Object
The DateTime object is the cornerstone of all temporal operations in BoxLang. It represents a specific moment in time with timezone information and provides methods for formatting, manipulation, and comparison. DateTime objects are created using BoxLang's temporal BIFs and provide member methods for advanced operations.
Creating DateTime Objects
BoxLang provides several Built-in Functions (BIFs) for creating DateTime objects:
Current Date and Time
// Get current date and time in system timezone
now = now()
From String Representations
// Parse from various string formats
dt = parseDateTime("December 25, 2023")
dt = parseDateTime("2023-12-25T15:30:00Z")
dt = parseDateTime("25-Dec-2023 3:30 PM")
// Parse with specific locale and timezone
dt = parseDateTime("25/12/2023", "en_US", "America/New_York")
From Numeric Components
// Create specific date (year, month, day)
dt = createDate(2023, 12, 25)
// Create date with time (year, month, day, hour, minute, second)
dt = createDateTime(2023, 12, 25, 15, 30, 45)
// Create time only (hour, minute, second)
timeObj = createTime(15, 30, 45)
BoxLang supports extensive formatting options through format masks:
Basic Date and Time Components
Mask
Description
Example
d
Day of month, no leading zero
5, 25
dd
Day of month, leading zero
05, 25
EEE
Day of week, three-letter abbreviation
Mon, Tue
EEEE
Day of week, full name
Monday, Tuesday
m
Month, no leading zero
1, 12
mm
Month, leading zero
01, 12
mmm
Month, three-letter abbreviation
Jan, Dec
mmmm
Month, full name
January, December
M
Month in year
1, 12
D
Day in year
1, 365
yy
Year, last two digits
23
yyyy
Year, four digits
2023
YYYY
Week year, four digits
2023
Y
Week year
2023
YY
Week year, last two digits
23
G
Period/era string
BC, AD
Time Components
Mask
Description
Example
h
Hours (12-hour), no leading zero
3, 11
hh
Hours (12-hour), leading zero
03, 11
H
Hours (24-hour), no leading zero
15, 23
HH
Hours (24-hour), leading zero
15, 23
n
Minutes, no leading zero
5, 30
nn
Minutes, leading zero
05, 30
s
Seconds, no leading zero
5, 45
ss
Seconds, leading zero
05, 45
l or L
Milliseconds, no leading zeros
123
t
One-character time marker
A, P
tt
Time marker string
AM, PM
Week Components
Mask
Description
Example
w
Week of year, single digit
1, 52
ww
Week of year, leading zero
01, 52
W
Week of month, single digit
1, 5
WW
Week of month, leading zero
01, 05
Predefined Full Date/Time Formats
These masks format the complete date and time and cannot be combined with other masks:
Mask
Equivalent Format
Example
short
"m/d/y h:nn tt"
12/25/23 3:30 PM
medium
"mmm d, yyyy h:nn:ss tt"
Dec 25, 2023 3:30:45 PM
long
Medium with full month and timezone
December 25, 2023 3:30:45 PM EST
full
"EEEE, mmmm d, yyyy h:mm:ss tt EST"
Monday, December 25, 2023 3:30:45 PM EST
iso
ISO8601 format
2023-12-25T15:30:45-05:00
Formatting Dates
Using Built-in Functions
dt = now()
// Combined date and time formatting
formatted = dateTimeFormat(dt, "yyyy-mm-dd HH:nn:ss")
formatted = dateTimeFormat(dt, "medium") // Dec 25, 2023 3:30:45 PM
formatted = dateTimeFormat(dt, "iso") // 2023-12-25T15:30:45-05:00
// Date only formatting
dateString = dateFormat(dt, "mm/dd/yyyy")
dateString = dateFormat(dt, "mmmm d, yyyy") // December 25, 2023
// Time only formatting
timeString = timeFormat(dt, "HH:nn:ss")
timeString = timeFormat(dt, "h:nn tt") // 3:30 PM
// With timezone specification
formatted = dateTimeFormat(dt, "yyyy-mm-dd HH:nn:ss", "UTC")
formatted = dateTimeFormat(dt, "medium", "America/New_York")
Timezone Support
BoxLang supports timezone specification using:
3-letter codes: "EST", "UTC", "PST"
Full timezone names: "America/New_York", "Europe/London", "Asia/Tokyo"
dt = now()
// Format with specific timezone
utcFormatted = dateTimeFormat(dt, "yyyy-mm-dd HH:nn:ss", "UTC")
nyFormatted = dateTimeFormat(dt, "full", "America/New_York")
Working with Timezones
BoxLang provides timezone support at two levels: request-level and formatting-level.
Request-Level Timezone Management
These BIFs set the timezone for the current request only. If not set, BoxLang uses the runtime configuration timezone.
// Set timezone for current request
setTimezone("America/New_York")
setTimezone("EST")
// Get current request timezone
currentTZ = getTimezone()
// Clear request timezone (reverts to runtime default)
clearTimezone()
// Get timezone information
info = getTimezoneInfo()
Formatting with Timezones
When formatting dates, you can specify a timezone without affecting the request timezone:
dt = now()
// Format with specific timezone (doesn't change request timezone)
utcFormatted = dateTimeFormat(dt, "yyyy-mm-dd HH:nn:ss", "UTC")
nyFormatted = dateTimeFormat(dt, "full", "America/New_York")
// Convert between timezones for calculations
utcTime = dateConvert("local2utc", dt)
localTime = dateConvert("utc2local", utcTime)
// Get timezone offset using member methods
offsetObj = dt.getOffset() // ZoneOffset object
offsetHours = offset(dt) // Offset in hours (using BIF)
Supported Timezone Formats
3-letter codes: "EST", "UTC", "PST", "CST"
Full timezone names: "America/New_York", "Europe/London", "Asia/Tokyo"
DateTime Member Methods
DateTime objects provide numerous member methods for manipulation, formatting, and information retrieval. These methods can be called directly on DateTime instances using dot notation.
dt = createDate(2023, 12, 25)
// Add/subtract time units
futureDate = dt.plusDays(5) // Add 5 days
pastDate = dt.minusDays(10) // Subtract 10 days
nextMonth = dt.plusMonths(1) // Add 1 month
nextYear = dt.plusYears(1) // Add 1 year
// Time additions
laterTime = dt.plusHours(3) // Add 3 hours
earlierTime = dt.minusMinutes(30) // Subtract 30 minutes
futureTime = dt.plusSeconds(45) // Add 45 seconds
// Set specific components
newYear = dt.withYear(2024) // Change year to 2024
newMonth = dt.withMonth(6) // Change month to June
newDay = dt.withDayOfMonth(15) // Change day to 15th
newHour = dt.withHour(9) // Change hour to 9 AM
// Using modify method (similar to dateAdd BIF)
modified = dt.modify("d", 5) // Add 5 days
modified = dt.modify("h", -3) // Subtract 3 hours
modified = dt.modify("m", 2) // Add 2 months
modified = dt.modify("yyyy", 1) // Add 1 year
Timezone Operations
dt = now()
// Convert to different timezone
utcTime = dt.convertToZone("UTC")
nyTime = dt.convertToZone("America/New_York")
// Set timezone (changes zone, keeps local time)
withTZ = dt.setTimezone("Europe/London")
// Check if leap year
isLeap = dt.isLeapYear() // true/false
Formatting Methods
dt = now()
// Custom formatting
formatted = dt.format("yyyy-mm-dd HH:nn:ss")
localized = dt.format("medium")
// Set default format for the DateTime object
dt.setFormat("yyyy-mm-dd HH:nn:ss")
defaultFormatted = dt.toString() // Uses the set format
// With specific locale
import java.util.Locale
spanishFormat = dt.format(Locale.of("es", "ES"), "EEEE, mmmm d, yyyy")
Advanced Member Method Usage
dt = createDateTime(2023, 12, 25, 15, 30, 45)
// Chain operations
result = dt.plusDays(5)
.withHour(9)
.withMinute(0)
.withSecond(0)
// Get first day of month
firstDay = dt.withDayOfMonth(1)
// Get last day of month
lastDay = dt.withDayOfMonth(dt.getMonth().length(dt.isLeapYear()))
// Beginning of day
startOfDay = dt.withHour(0).withMinute(0).withSecond(0).withNano(0)
// End of day
endOfDay = dt.withHour(23).withMinute(59).withSecond(59).withNano(999999999)
dt = now()
// Check if date supports certain operations
supportsNanos = dt.isSupported(ChronoField.NANO_OF_SECOND) // true
supportsDay = dt.isSupported(ChronoUnit.DAYS) // true
// Get valid range for a field
yearRange = dt.range(ChronoField.YEAR) // ValueRange object
monthRange = dt.range(ChronoField.MONTH_OF_YEAR) // 1-12
These member methods provide direct access to the rich functionality of BoxLang's DateTime objects, allowing for fluent and expressive date manipulation code. Most operations return new DateTime instances, supporting method chaining for complex transformations.
Date Arithmetic and Mathematical Operations
timeNow = now();
// Addition casts the date to a numeric day value
// ( example: 20241.89415408551756893278841047638 )
originalEpochDays = timeNow + 0;
// Add 2.5 days to the decimal days value
updatedEpochDays = timeNow + 2.5;
Addition and Subtraction
dt1 = createDate(2023, 12, 25)
dt2 = createDate(2023, 12, 30)
// Subtract dates to get difference in days
daysDiff = dt2 - dt1 // Returns 5.0
// Add days to a date
futureDate = dt1 + 10 // Adds 10 days
// Add fractional days (hours, minutes)
halfDay = dt1 + 0.5 // Adds 12 hours
quarterDay = dt1 + 0.25 // Adds 6 hours
// Check if year is leap year
isLeap = dt.isLeapYear()
// Get numeric date (days since epoch)
numericDate = getNumericDate(dt)
// Get time in milliseconds since epoch
timeMillis = getTime(dt)
epochMillis = dt.toEpochMillis()
epochSeconds = dt.toEpoch()
function addBusinessDays(date, days) {
result = date
remaining = days
while (remaining > 0) {
result = dateAdd("d", 1, result)
// Skip weekends (Saturday=7, Sunday=1)
if (dayOfWeek(result) != 1 && dayOfWeek(result) != 7) {
remaining--
}
}
return result
}
Date Range Generation
function getDateRange(startDate, endDate) {
dates = []
current = startDate
while (dateCompare(current, endDate) <= 0) {
arrayAppend(dates, current)
current = dateAdd("d", 1, current)
}
return dates
}
Age Calculation
function calculateAge(birthDate) {
today = now()
age = dateDiff("yyyy", birthDate, today)
// Adjust if birthday hasn't occurred this year
birthdayThisYear = createDate(year(today), month(birthDate), day(birthDate))
if (dateCompare(today, birthdayThisYear) < 0) {
age--
}
return age
}
Timezone Conversion Utility
function convertTimezone(dt, fromTZ, toTZ) {
// Use member methods for timezone conversion
return dt.convertToZone(toTZ)
}
function formatInTimezone(dt, mask, timezone) {
// Format date in specific timezone without changing request timezone
return dateTimeFormat(dt, mask, timezone)
}
Performance Considerations
DateTime objects are immutable; operations return new instances
Use BIFs like dateAdd(), dateDiff(), dateFormat() for most operations
Cache formatted strings if formatting the same date multiple times with dateTimeFormat()
Be mindful of timezone conversions in loops
Use createTimeSpan() for duration calculations rather than manual arithmetic
BoxLang supports mathematical operations on dates, converting them to fractional days for calculations. For basic arithmetic operations (addition, subtraction, multiplication, and division), dates and timespans can be cast as numeric values. In BoxLang, the numeric value of a object represents the decimal days since the Unix epoch time.
A or Java object is represented as decimal days for the purpose of mathematical operations.