EV charging station utilisation: time-based vs energy-based measures
In this article (9 sections)
Related programme: the Data Analytics with Generative AI course (3–4 months; ₹90,000 (inclusive of GST) · EMI from ₹4,000/month).
EV charger utilisation has two honest definitions, and you need both. Time utilisation is plugged-in minutes ÷ available minutes. Energy utilisation is kWh delivered ÷ (rated kW × available hours). Time tells you whether the bay is occupied; energy tells you whether the expensive power hardware is earning. In the synthetic day below, a 60 kW mall connector is occupied 21.5% of the day but delivers only 7.0% of its energy capacity, because 42% of its plugged time is cars sitting fully charged.
A charge point operator's decision
Operators in NCR decide three things from these numbers: where to add connectors, where to add a charger of a different power rating, and whether to introduce idle fees or time limits. Each decision reads a different measure. A site with high time utilisation and low energy utilisation does not need more power; it needs cars to move. A site with high energy utilisation is a candidate for another charger. A single "utilisation %" on a dashboard hides which case you are in.
The data a CPMS gives you
A charge point management system usually exports sessions built from the chargers' transaction messages, plus a status log:
| Table | Columns | Notes |
|---|---|---|
| connector | connector_id, site, rated_kw | Rated power of the connector, not what vehicles accept |
| session | session_id, connector_id, plug_in, plug_out, charge_end, energy_kwh | charge_end is when power flow stopped; often derived from meter values |
| downtime | connector_id, down_from, down_to | Faults, maintenance, power cuts; from status notifications |
| tariff (not used here) | site, rate, idle_fee_after_min | Needed for revenue, not utilisation |
Timestamps must share one time zone. Chargers left on UTC while the dashboard runs in IST shift every session by five and a half hours.
Four formulas
- Available minutes = window minutes − downtime minutes inside the window
- Time utilisation % = Σ clipped plugged minutes ÷ available minutes × 100
- Energy utilisation % = Σ kWh inside window ÷ (rated kW × available minutes ÷ 60) × 100
- Idle-while-plugged % = (plugged minutes − charging minutes) ÷ plugged minutes × 100
Clipping means each session contributes only the part between the window's start and end: MAX(start, window_start) to MIN(end, window_end).
The worked query
Synthetic data for 10 September 2026: three connectors at two hypothetical sites. S01 began the evening before, S09 runs past midnight, S04 was exported twice, and C2 was down until 8 AM.
CREATE TABLE connector (connector_id TEXT, site TEXT, rated_kw REAL);
CREATE TABLE session (session_id TEXT, connector_id TEXT, plug_in TEXT, plug_out TEXT,
charge_end TEXT, energy_kwh REAL);
CREATE TABLE downtime (connector_id TEXT, down_from TEXT, down_to TEXT);
INSERT INTO connector VALUES ('C1','Sector 18 mall',60),('C2','Sector 18 mall',60),('C3','Expressway plaza',30);
INSERT INTO session VALUES
('S01','C1','2026-09-09 23:10','2026-09-10 00:40','2026-09-10 00:30',38),
('S02','C1','2026-09-10 09:00','2026-09-10 10:00','2026-09-10 09:50',30),
('S03','C1','2026-09-10 13:00','2026-09-10 15:30','2026-09-10 13:45',22),
('S04','C1','2026-09-10 18:00','2026-09-10 19:00','2026-09-10 18:55',35),
('S04','C1','2026-09-10 18:00','2026-09-10 19:00','2026-09-10 18:55',35),
('S05','C2','2026-09-10 10:00','2026-09-10 11:00','2026-09-10 11:00',18),
('S06','C2','2026-09-10 20:00','2026-09-10 21:30','2026-09-10 21:00',24),
('S07','C3','2026-09-10 07:00','2026-09-10 09:00','2026-09-10 09:00',40),
('S08','C3','2026-09-10 17:00','2026-09-10 20:00','2026-09-10 19:00',48),
('S09','C3','2026-09-10 23:30','2026-09-11 01:00','2026-09-11 00:45',30);
INSERT INTO downtime VALUES ('C2','2026-09-10 00:00','2026-09-10 08:00');
WITH s AS (
SELECT DISTINCT * FROM session
),
w AS (
SELECT s.*, c.rated_kw,
MAX(julianday(plug_in), julianday('2026-09-10 00:00')) AS a,
MIN(julianday(plug_out), julianday('2026-09-11 00:00')) AS b,
MAX(julianday(plug_in), julianday('2026-09-10 00:00')) AS ca,
MIN(julianday(charge_end), julianday('2026-09-11 00:00')) AS cb,
(julianday(charge_end) - julianday(plug_in)) AS charge_span
FROM s JOIN connector c USING (connector_id)
WHERE plug_in < '2026-09-11 00:00' AND plug_out > '2026-09-10 00:00'
),
per AS (
SELECT connector_id, rated_kw,
SUM((b - a) * 1440) AS plugged_min,
SUM(MAX(cb - ca, 0) * 1440) AS charging_min,
SUM(energy_kwh * MAX(cb - ca, 0) / charge_span) AS kwh_in_day
FROM w GROUP BY connector_id, rated_kw
),
avail AS (
SELECT c.connector_id,
1440 - COALESCE(SUM((MIN(julianday(down_to), julianday('2026-09-11 00:00'))
- MAX(julianday(down_from), julianday('2026-09-10 00:00'))) * 1440), 0) AS avail_min
FROM connector c LEFT JOIN downtime d USING (connector_id)
GROUP BY c.connector_id
)
SELECT p.connector_id,
ROUND(a.avail_min, 0) AS avail_min,
ROUND(p.plugged_min, 0) AS plugged_min,
ROUND(100.0 * p.plugged_min / a.avail_min, 1) AS time_util_pct,
ROUND(100.0 * p.plugged_min / 1440, 1) AS time_util_24h_pct,
ROUND(p.kwh_in_day, 1) AS kwh,
ROUND(100.0 * p.kwh_in_day / (p.rated_kw * a.avail_min / 60), 1) AS energy_util_pct,
ROUND(100.0 * (p.plugged_min - p.charging_min) / p.plugged_min, 0) AS idle_plugged_pct
FROM per p JOIN avail a USING (connector_id)
ORDER BY p.connector_id;| connector_id | avail_min | plugged_min | time_util_pct | time_util_24h_pct | kwh | energy_util_pct | idle_plugged_pct |
|---|---|---|---|---|---|---|---|
| C1 | 1440.0 | 310.0 | 21.5 | 21.5 | 101.3 | 7.0 | 42.0 |
| C2 | 960.0 | 150.0 | 15.6 | 10.4 | 42.0 | 4.4 | 20.0 |
| C3 | 1440.0 | 330.0 | 22.9 | 22.9 | 100.0 | 13.9 | 18.0 |
Energy for a session that crosses a boundary is split in proportion to its charging minutes inside the window, which is an approximation. If your system stores interval meter values, sum those instead.
What the shortcut reports
The common shortcut filters sessions by start date and subtracts plug-in from plug-out, with no clipping and no deduplication:
SELECT connector_id,
ROUND(SUM(julianday(plug_out) - julianday(plug_in)) * 1440, 0) AS naive_plugged_min,
ROUND(100.0 * SUM(julianday(plug_out) - julianday(plug_in)) * 1440 / 1440, 1) AS naive_util_pct
FROM session
WHERE date(plug_in) = '2026-09-10'
GROUP BY connector_id ORDER BY connector_id;| connector_id | naive_plugged_min | naive_util_pct |
|---|---|---|
| C1 | 330.0 | 22.9 |
| C2 | 150.0 | 10.4 |
| C3 | 390.0 | 27.1 |
C1 loses the 40 minutes after midnight from S01 and gains 60 minutes from the duplicate S04. C3 counts all 90 minutes of S09, though only 30 fell on 10 September. C2's figure ignores its eight hours of downtime, so it looks like the weakest connector at 10.4% when, on the time it could actually serve, it managed 15.6%.
Reading the three connectors
C1 and C3 have similar time utilisation, yet C3, at half the rated power, delivers nearly twice the energy utilisation. C1's problem is dwell: shoppers plug in, finish charging within the hour and leave the car for the rest of the visit. That argues for an idle fee or a parking-time rule at the mall, not another fast charger. C3's highway customers charge and leave, which is what a busy, low-idle connector looks like.
Other traps in charging data
- Rated kW is a ceiling, not an expectation. Many vehicles accept less than the connector's rating, and charging tapers as the battery fills. Energy utilisation will never approach 100% on a real site. Compare sites with each other and with their own history, not with the rating.
- Zero-energy sessions. Failed authorisation or a cable that never locked creates sessions with 0 kWh. Count them separately as a reliability measure; they should not add plugged minutes.
- Open sessions. A session with no plug_out, from a lost network message, can run for days. Cap or exclude it, and log how many.
- Shared power cabinets. Where two connectors share one power module, their combined energy cannot exceed the cabinet's rating. Measure energy utilisation at the cabinet level too.
- Downtime definition. Decide whether a charger that is online but faulted on one connector counts as down, and write the rule down.
For the operations or network-planning head
A two-by-two works well: time utilisation on one axis, energy utilisation on the other, one dot per connector, sized by sessions. High-time, low-energy connectors are an idle-management conversation; high-energy connectors are expansion candidates; low on both is a location or visibility question. Put each site's downtime minutes beside the chart, because a reliability problem looks exactly like a demand problem on a utilisation dashboard.
Where to learn it
Interval clipping, deduplication and denominators that exclude unavailable time are SQL skills the Data Analyst programme covers across 3–4 months, live online with optional in-person labs at our Noida centre. For another case where the physics and the reporting unit must agree, see solar plant performance ratio.
Frequently asked questions
How do you calculate EV charger utilisation?
Time utilisation is the minutes a connector had a vehicle plugged in divided by the minutes it was available in the period. Energy utilisation is the kWh delivered divided by the connector's rated kW multiplied by available hours. Report both, since a connector can be occupied for hours while delivering little energy.
What is idle-while-plugged time?
It is the share of plugged-in time when the vehicle had finished charging but stayed connected. It shows lost capacity at busy sites and is the usual basis for an idle fee or a parking-time rule.
How should sessions that cross midnight be counted?
Clip each session to the reporting window, counting only the minutes inside that day, and split its energy in proportion to the charging minutes inside the window.
Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.
This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.
Explore Data Analytics with Generative AI