EDA and Feature Engineeringpandas 3.0 · scikit-learn 1.9 · seaborn 0.13 · Python 3.12+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
72 small wins to finish your pathNext lesson →

Turning a time into hours and minutes

A clock time such as 22:20 becomes two numeric features, the hour and the minute, because the text itself cannot be compared or added.

Last updated: 12 Oct, 2026 · pandas 3.0 · scikit-learn 1.9 · openpyxl 3.1

Splitting a date into columns turned one date into three numbers. The two time columns need the same treatment and one extra step, because some of the arrival times carry a date on the end: 01:10 22 Mar means the flight landed the next day.

Splitting a time into hour and minute · from the EDA and Feature Engineering video · 2:09:33 to 2:14:30

Working on fields of the same kind together

Dep_Time and Arrival_Time hold the same kind of value and need the same recipe, so they are handled one after the other rather than in the order the columns happen to sit in. That habit is what keeps a long feature pass readable.

python
import pandas as pd

BASE = ("https://raw.githubusercontent.com/krishnaik06/5-Days-Live-EDA-and-Featur"
        "e-Engineering/main/Flight%20Prediction/")
train = pd.read_excel(BASE + "Data_Train.xlsx")   # 10683 rows, Price included
test = pd.read_excel(BASE + "Test_set.xlsx")      # 2671 rows, no Price
flights = pd.concat([train, test], ignore_index=True)

Cutting the trailing date off an arrival time

Splitting on a space and keeping the first piece leaves 01:10 from 01:10 22 Mar, and leaves 13:15 untouched, because a value with no space splits into a list of one.

python
flights['Arrival_Time'] = flights['Arrival_Time'].str.split(' ').str[0]
Casting the pieces and repeating the recipe · from the EDA and Feature Engineering video · 2:14:31 to 2:17:54

Splitting the clock time on the colon

The hour is before the colon and the minute is after it. Both pieces are cast, because '05' and '5' are different strings and the same number.

python
clock = flights['Arrival_Time'].str.split(':')
flights['Arrival_hour'] = clock.str[0].astype(int)
flights['Arrival_min'] = clock.str[1].astype(int)
flights = flights.drop(columns='Arrival_Time')

Building four columns out of two time columns

ExampleBoth time columns, split and cast, on pandas 3.0.6
print("raw arrival times:", flights['Arrival_Time'].head(4).tolist())
carry_a_date = flights['Arrival_Time'].str.contains(' ')
print("rows carrying a date:", int(carry_a_date.sum()), "of", len(flights))

flights['Arrival_Time'] = flights['Arrival_Time'].str.split(' ').str[0]
for source, prefix in [('Arrival_Time', 'Arrival'), ('Dep_Time', 'Dept')]:
    clock = flights[source].str.split(':')
    flights[prefix + '_hour'] = clock.str[0].astype(int)
    flights[prefix + '_min'] = clock.str[1].astype(int)
    flights = flights.drop(columns=source)

print(flights[['Arrival_hour', 'Arrival_min', 'Dept_hour', 'Dept_min']].head(4).to_string())
print("\nhour range:", flights["Dept_hour"].min(), "to", flights["Dept_hour"].max())
print("minute values:", sorted(flights["Dept_min"].unique().tolist()))
  • 5401 of the 13354 arrival times carry a date. Those are the overnight flights. Without the first split, '01:10 22 Mar'.split(':') would hand '10 22 Mar' to the cast and it would raise.
  • The loop does the same four lines twice. Two columns of the same kind get one recipe, which is the habit the chapter is built on.
  • Hours run 0 to 23 and minutes take twelve values, all multiples of five. Airlines publish times on a five minute grid, and a model sees that as twelve levels rather than sixty.

The same split with to_datetime

A clock time is a time, so pandas can parse it and hand back the parts. The result is identical, and the parse also refuses a value that is not a time instead of producing a wrong number in silence.

python
clock = pd.to_datetime(flights['Dep_Time'], format='%H:%M')
flights['Dept_hour'] = clock.dt.hour
flights['Dept_min'] = clock.dt.minute
ExampleDeparture hours counted and plotted
import matplotlib.pyplot as plt

clock = pd.to_datetime(flights['Dep_Time'], format='%H:%M')
by_split = flights['Dep_Time'].str.split(':').str[0].astype(int)
print("the two routes agree:", bool((clock.dt.hour == by_split).all()))

per_hour = clock.dt.hour.value_counts().sort_index()
print("busiest hour:", int(per_hour.idxmax()), "with", int(per_hour.max()), "departures")
print("quietest hour:", int(per_hour.idxmin()), "with", int(per_hour.min()), "departures")

fig, ax = plt.subplots(figsize=(7.5, 3.4))
ax.bar(per_hour.index, per_hour.values, color='#3a6fd8')
ax.set_xticks(range(0, 24, 2))
ax.set_xlabel('departure hour'); ax.set_ylabel('flights')
ax.set_title('Departures by hour of the day')
fig.tight_layout()
A bar chart of flights by departure hour: very few departures between midnight and four in the morning, a sharp rise at five, the tallest bar at nine with about 1150 flights, a broad spread through the afternoon and evening, and a fall away after ten at night.
  • The hour from the split and the hour from the parse match on every row.
  • The counts carry a pattern. The quietest hour, three in the morning, has 30 departures and the busiest, nine, has 1152, so the hour is information a model can use.
  • The chart also shows why the next lesson exists. Hour 23 and hour 0 are next to each other on a clock and at opposite ends of this axis.

Splitting the string compared with parsing the time

.str.split(':')pd.to_datetime(format='%H:%M')
Handles 01:10 22 Maronly after the trailing date is cut offonly after the trailing date is cut off
A value that is not a timecasts to a wrong number or raises on astyperaises, naming the value
Givesthe pieces you index.dt.hour, .dt.minute, .dt.second
Speed on 13354 rowstwo passes over the textone parse, then attribute reads
Use it foran odd pattern a parser does not knowanything that is a real clock time

Where hour and minute features are used

  • Fare and demand models. A six in the morning departure and a six in the evening departure sell at different prices.
  • Server and traffic logs, where the hour of the request is often the strongest single feature in the table.
  • Shift and staffing data, where the minute rarely matters and the hour always does.
Watch out. astype(int) raises IntCastingNaNError the moment one value is NaN, because there is no integer that means missing. Fill the column first, or cast to the nullable 'Int64' type, which holds pd.NA alongside whole numbers.
Try it yourself
  • Remove the .str.split(' ').str[0] line and run the rest. The cast raises, and the message names the value it choked on.
  • Build Dept_minutes_from_midnight = Dept_hour * 60 + Dept_min, one column instead of two, and compare how many values each version has.
  • Count how many arrival times carry a date for each airline with groupby('Airline').

This is what real progress feels like.