This sample demonstrates the use of the queryFeatures() method to retrieve count statistics on accidents data from a FeatureLayer based on timestamp-offset field values, grouping the counts by hour of day, days of the week, or months.
Three new date and time fields were added at version 4.28:
| Field type | Description | Example | Use cases |
|---|---|---|---|
| The date-only | Date-only fields support date values with no time values. | 2018-09-01 | Data that was captured in the granularity of days or attribute values that apply to, or represent, the entire day. Start or end date of a school semester, Aggregating total number of hurricanes based on the year they occur |
| The time-only | Time-only fields support time values with no date value. | 15:35:23 | Data that repeats daily or content for which only the time component matters. Business or store opening and closing hours. Bus or train schedule. |
| The timestamp-offset | Timestamp offset fields support a date, time, and time zone offset from the Coordinated Universal Time (UTC) zone. | 2015-09-24T21:58:00-09:00 | Time values for which the local time value is important and the dates can cross multiple time zones. Crimes, earthquake, traffic incidents, airline managing departure and arrival schedules worldwide, while also understanding the local time for passengers. |
The map displays fatal accidents of 2021 with different colors depending on which time of the day accident happened. The data was downloaded from Fatality Analysis Reporting System and hosted on ArcGIS Online. The FeatureLayer portal item uses a unique value renderer to symbolize accident data based on the time of day each incident occurred. An Arcade expression extracts the hour from the timestamp-offset field type and categorizes each record into four time periods: night, morning, afternoon, and evening. Each category is then visualized with a distinct color. The expression used in the renderer is shown below:
var d = $feature.TSODate;
var h = Hour(d);
When(
h <= 6, "night",
h <= 12, "morning",
h <= 18, "afternoon",
"evening"
);How it works
When the application starts, the UI features the Total Accidents by Time of Day chart in the upper right corner. Users can toggle between daily, weekly, and monthly accident charts by clicking the corresponding buttons. Clicking on a specific bar in any chart filters the map to show only accidents that occurred during the selected time period. For the weekly or monthly charts, clicking a bar also opens an additional chart that provides a daily breakdown of accidents within that selected time frame.
The application runs three statistical queries at startup to generate chart data. For example, the Total accidents by time of day chart data is efficiently prepared using timestamp-offset values, which are stored with their respective UTC offsets. This approach allows for seamless time-based analysis across multiple time zones—ensuring that 8 AM represents the same local time regardless of location.
// Query the layer for total accidents, grouped by hour of day
const hourResult = await runQuery("1=1", "extract(hour from tsodate)");
const hourData = hourResult.features?.map(f => f.attributes["count"]) ?? [];
const hourLabels = hourResult.features?.map(f => f.attributes["EXPR_1"]) ?? [];
// run stats query to return total number of accidents by time of day
// stats results will be grouped by the time of day
const hourResult = await runQuery("extract(hour from tsodate)");
hourResult.features.forEach((feature) => {
hourData.push(feature.attributes["count"]);
hourLabels.push(feature.attributes["EXPR_1"]);
});
// Called at startup to query and group accidents by hour, weekday, and month
async function runQuery(where, groupStats) {
// Create a query object that honors the layer settings
const query = layer.createQuery();
query.where = where;
// Define statistics to calculate count of accidents
query.outStatistics = [
{
statisticType: "count",
onStatisticField: "*",
outStatisticFieldName: "count",
},
];
query.groupByFieldsForStatistics = [groupStats];
query.orderByFields = [groupStats];
const result = await layer.queryFeatures(query);
return result;
}