Skip to main content

Business Days Field

The businessDays(path) field is available on both Order and TrackingEvent GraphQL types. It calculates how many business days separate a date field on the parent object from today, using the organization's configured business calendar.

Overview

  • Returns: Int — signed count of business days (positive = date is in the past, negative = date is in the future, zero = today)
  • Calendar source: The organization's business calendar, including weekly schedule and availability blocks
  • Timezone: All calculations are performed in the organization's configured timezone
  • Null safety: Returns null if the field is not found, cannot be parsed as a date, or the organization has no business calendar configured

Field Signature

Available on both Order and TrackingEvent:

businessDays(path: String!, contactId: Int): Int

Argument

ArgumentTypeRequiredDescription
pathStringYesDot-notation path to a date field on the parent object (e.g., "eta", "customValues.pickupDate")
contactIdIntNoOptional contact scope for availability blocks. When provided, only org-wide blocks plus blocks for that contact are used.

How It Works

  1. The resolver reads the field value at path from the parent object using reflection
  2. The value is coerced to a DateTime — supports DateTime, DateTimeOffset, DateOnly, or any parseable date string
  3. The organization's business calendar is loaded (cached within the request via DataLoader)
  4. Availability blocks are optionally filtered by contactId: org-wide blocks plus blocks matching that contact are used
  5. Business days are counted between the resolved date and today (organization's local date), excluding the start date and including the end date
  6. The result is signed: positive when the date is in the past, negative when it is in the future

Business Day Definition

A calendar day counts as a business day if, after combining the weekly schedule with availability blocks, at least one time window remains available on that date:

  • Weekly schedule: Defines standard business hours per day of week
  • IsAvailable=true blocks: Add extra availability windows (e.g., holiday coverage)
  • IsAvailable=false blocks: Remove windows (e.g., public holidays, closures)

Usage Examples

Business days since an order's ETA

query {
order(organizationId: 1, orderId: 123) {
orderId
eta
businessDaysSinceEta: businessDays(path: "eta")
}
}

Response:

{
"data": {
"order": {
"orderId": 123,
"eta": "2026-04-10T00:00:00Z",
"businessDaysSinceEta": 8
}
}
}

Multiple business day fields in one query

You can request businessDays for several different date fields simultaneously using aliases:

query {
order(organizationId: 1, orderId: 123) {
orderId
bdaysFromCreated: businessDays(path: "created")
bdaysFromEta: businessDays(path: "eta")
bdaysFromPickup: businessDays(path: "customValues.pickupDate")
}
}

Business days on a tracking event

The businessDays field is also available on TrackingEvent, where path is resolved relative to the tracking event — not the order:

query {
order(organizationId: 1, orderId: 123) {
orderId
lastDeliveryAttempt: lastTrackingEvent(eventDefinitionName: "DeliveryAttempt") {
trackingEventId
eventDate
bdaysSinceAttempt: businessDays(path: "eventDate")
}
}
}

Response:

{
"data": {
"order": {
"orderId": 123,
"lastDeliveryAttempt": {
"trackingEventId": 456,
"eventDate": "2026-04-15T09:30:00Z",
"bdaysSinceAttempt": 5
}
}
}
}

Contact-scoped carrier availability

Pass contactId when the business-day count should honor availability exceptions for a carrier, customer, or other contact. This keeps org-wide closures while adding contact-specific blocks.

query {
order(organizationId: 1, orderId: 123) {
eta
carrierBusinessDays: businessDays(path: "eta", contactId: 456)
}
}

For commodity grids, the backend also exposes a scalar helper on Commodity so each row can resolve its carrier from row custom values without a per-row client argument:

query {
commodities(organizationId: 1) {
items {
commodityId
customValues
lastFreeDays: lastTrackingEventBusinessDays(
path: "eventDate"
eventDefinitionName: "Yard Scan"
orderBy: "eventDate"
contactIdPropertyName: "carrierId"
)
}
}
}

contactIdPropertyName names the custom value key on the commodity row (for carrier use cases, usually carrierId).

Null Return Cases

businessDays returns null when:

ConditionReason
path does not exist on the parent objectField not found
Field value is nullNo date to measure from
Field value cannot be parsed as a dateUnsupported format
No business calendar is configured for the organizationCalendar lookup returned null

Performance Note

The business calendar is loaded via a batched DataLoader scoped to the GraphQL request. Requesting businessDays on many orders or tracking events in a single query results in at most one calendar lookup per organization, regardless of result set size. Contact-scoped filtering is in-memory against the already-loaded calendar blocks; it does not add per-row SQL queries.