Skip to Content
ConceptsSQLDate/Time Functions

Revenue Analysis with Date/Time Functions

BeginnerIntermediate

Learning Objectives

After completing this recipe, you will be able to:

  • Understand BigQuery’s date/time data types (DATE, DATETIME, TIMESTAMP)
  • Extract time units with EXTRACT and DATE_TRUNC functions
  • Perform period comparison analysis with DATE_ADD/SUB
  • Calculate periods and derive KPIs with DATE_DIFF

BigQuery Execution Environment Setup

from google.cloud import bigquery import pandas as pd # Authentication setup (when using service account key) # import os # os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/to/your-key.json" # Create BigQuery client client = bigquery.Client(project='your-project-id') # Query execution function def run_query(query): return client.query(query).to_dataframe()
ℹ️
Project ID Setup

Replace your-project-id with your GCP project ID in the code above.


1. DATE vs DATETIME vs TIMESTAMP

Theory

BigQuery provides three main time data types:

TypeFormatExampleCharacteristics
DATEYYYY-MM-DD2024-01-15Date only, no time information
DATETIMEYYYY-MM-DD HH:MM:SS2024-01-15 14:30:00Date + time, no timezone
TIMESTAMPYYYY-MM-DD HH:MM:SS UTC2024-01-15 14:30:00+00:00Date + time + timezone (UTC-based)
ℹ️
When to Use Each Type?
  • DATE: When time isn’t important, like birthdate, signup date
  • DATETIME: Local time-based events (reservation time, business hours)
  • TIMESTAMP: Recording exact moments of worldwide events (order time, logs)

Key Functions

-- Get current date/time CURRENT_DATE() -- Current date CURRENT_DATETIME() -- Current datetime CURRENT_TIMESTAMP() -- Current timestamp -- Type conversion CAST(timestamp_col AS DATE) -- TIMESTAMP → DATE CAST(timestamp_col AS DATETIME) -- TIMESTAMP → DATETIME

Practice: Comparing Date Types

SELECT CURRENT_DATE() AS current_date, CURRENT_DATETIME() AS current_datetime, CURRENT_TIMESTAMP() AS current_timestamp, -- Convert created_at to each type CAST(created_at AS DATE) AS order_date, CAST(created_at AS DATETIME) AS order_datetime, created_at AS order_timestamp FROM `your-project-id.thelook_ecommerce.orders` LIMIT 5
Execution Result
current_datecurrent_datetimecurrent_timestamporder_dateorder_datetimeorder_timestamp
2024-11-192024-11-19 10:26:432024-11-19 10:26:43+00:002023-10-112023-10-11 15:31:002023-10-11 15:31:00+00:00

2. EXTRACT Function - Extracting Year/Month/Day/Day of Week

Theory

The EXTRACT function extracts a specific part from a date/time.

EXTRACT(part FROM date_expression)
PartDescriptionReturn Value Range
YEARYeare.g., 2024
MONTHMonth1-12
DAYDay1-31
DAYOFWEEKDay of week1(Sun)~7(Sat)
DAYOFYEARDay of year1-366
WEEKWeek number0-53
QUARTERQuarter1-4
HOURHour0-23
MINUTEMinute0-59
⚠️
Day of Week Note

BigQuery’s DAYOFWEEK has Sunday as 1, Saturday as 7.

Practice: Order Analysis by Day of Week

SELECT EXTRACT(DAYOFWEEK FROM created_at) AS day_of_week, CASE EXTRACT(DAYOFWEEK FROM created_at) WHEN 1 THEN 'Sunday' WHEN 2 THEN 'Monday' WHEN 3 THEN 'Tuesday' WHEN 4 THEN 'Wednesday' WHEN 5 THEN 'Thursday' WHEN 6 THEN 'Friday' WHEN 7 THEN 'Saturday' END AS day_name, COUNT(*) AS order_count FROM `your-project-id.thelook_ecommerce.orders` GROUP BY day_of_week, day_name ORDER BY day_of_week
Execution Result
day_of_weekday_nameorder_count
1Sunday18,384
2Monday17,916
3Tuesday17,617
4Wednesday17,313
5Thursday17,526
6Friday17,725
7Saturday18,312
💡
Insight

Weekend (Sat/Sun) orders are slightly higher than weekdays. This is a common pattern in e-commerce and can be used to develop weekend promotion strategies.


3. DATE_TRUNC - Period Unit Aggregation

Theory

DATE_TRUNC truncates a date to a specific unit. Useful for monthly, weekly, and quarterly aggregations.

DATE_TRUNC(date_expression, date_part)
date_partInputResult
DAY2024-03-15 14:30:002024-03-15
WEEK2024-03-15 14:30:002024-03-11 (Monday)
MONTH2024-03-15 14:30:002024-03-01
QUARTER2024-03-15 14:30:002024-01-01
YEAR2024-03-15 14:30:002024-01-01

Practice: Monthly Revenue Trend

SELECT DATE_TRUNC(CAST(o.created_at AS DATE), MONTH) AS month, COUNT(DISTINCT o.order_id) AS order_count, COUNT(DISTINCT o.user_id) AS customer_count, SUM(oi.sale_price) AS total_revenue, ROUND(SUM(oi.sale_price) / COUNT(DISTINCT o.order_id), 2) AS avg_order_value FROM `your-project-id.thelook_ecommerce.orders` o JOIN `your-project-id.thelook_ecommerce.order_items` oi ON o.order_id = oi.order_id WHERE o.created_at >= '2024-01-01' GROUP BY month ORDER BY month
Execution Result
monthorder_countcustomer_counttotal_revenueavg_order_value
2024-01-011,9831,892156,234.5078.78
2024-02-011,9281,845148,923.7577.24
2024-03-012,2092,098172,456.3078.07

4. DATE_DIFF - Period Calculation

Theory

DATE_DIFF calculates the difference between two dates.

DATE_DIFF(end_date, start_date, date_part)
CalculationSQLResult
Days differenceDATE_DIFF('2024-03-15', '2024-03-10', DAY)5
Months differenceDATE_DIFF('2024-06-01', '2024-03-01', MONTH)3
Years differenceDATE_DIFF('2025-01-01', '2024-01-01', YEAR)1

Practice: Customer Activity Period Analysis

SELECT user_id, MIN(CAST(created_at AS DATE)) AS first_order_date, MAX(CAST(created_at AS DATE)) AS last_order_date, DATE_DIFF(MAX(CAST(created_at AS DATE)), MIN(CAST(created_at AS DATE)), DAY) AS days_active, COUNT(DISTINCT order_id) AS total_orders, ROUND( COUNT(DISTINCT order_id) * 1.0 / NULLIF(DATE_DIFF(MAX(CAST(created_at AS DATE)), MIN(CAST(created_at AS DATE)), MONTH), 0), 2 ) AS orders_per_month FROM `your-project-id.thelook_ecommerce.orders` GROUP BY user_id HAVING COUNT(DISTINCT order_id) > 1 -- Only customers with 2+ orders ORDER BY days_active DESC LIMIT 10
Execution Result
user_idfirst_order_datelast_order_datedays_activetotal_ordersorders_per_month
45232023-01-022024-11-1568280.35
78912023-01-052024-10-2866250.23
23452023-01-082024-10-2065160.28

5. Month-over-Month and Year-over-Year Analysis

Theory

The most important thing in time series analysis is period-over-period comparison. Let’s learn how to calculate month-over-month (MoM) and year-over-year (YoY) growth rates.

-- Previous month data join DATE_SUB(current_month, INTERVAL 1 MONTH) -- Same month last year data join DATE_SUB(current_month, INTERVAL 1 YEAR)

Practice: Month-over-Month Revenue Growth Rate

WITH monthly_revenue AS ( SELECT DATE_TRUNC(CAST(o.created_at AS DATE), MONTH) AS month, SUM(oi.sale_price) AS revenue FROM `your-project-id.thelook_ecommerce.orders` o JOIN `your-project-id.thelook_ecommerce.order_items` oi ON o.order_id = oi.order_id GROUP BY month ) SELECT curr.month, curr.revenue AS current_revenue, prev.revenue AS previous_revenue, ROUND((curr.revenue - prev.revenue) / prev.revenue * 100, 2) AS mom_growth_pct FROM monthly_revenue curr LEFT JOIN monthly_revenue prev ON curr.month = DATE_ADD(prev.month, INTERVAL 1 MONTH) WHERE curr.month >= '2024-01-01' ORDER BY curr.month
Execution Result
monthcurrent_revenueprevious_revenuemom_growth_pct
2024-01-01156,234.50142,567.809.58
2024-02-01148,923.75156,234.50-4.68
2024-03-01172,456.30148,923.7515.80
💡
Practical Application
  • MoM (Month over Month): Short-term trend identification, heavily influenced by seasonality
  • YoY (Year over Year): Removes seasonality, captures medium to long-term growth trends
  • QoQ (Quarter over Quarter): Measures quarterly business goal achievement

Quiz

Problem 1: Order Analysis by Hour

From the orders table:

  1. Extract the order hour and aggregate order count by hour
  2. Identify which hour has the most orders

View Answer

SELECT EXTRACT(HOUR FROM created_at) AS hour, COUNT(*) AS order_count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) AS pct FROM `your-project-id.thelook_ecommerce.orders` GROUP BY hour ORDER BY hour

Explanation:

  • Extract the hour with EXTRACT(HOUR FROM created_at)
  • Calculate the percentage of total using the window function SUM(...) OVER()
  • Typically, orders concentrate around 2-4 PM and 8-10 PM

Problem 2: Delivery Time from Order to Shipment

From the order_items table:

  1. Calculate the average delivery days for delivered orders
  2. Analyze the monthly trend of delivery days

View Answer

SELECT DATE_TRUNC(CAST(shipped_at AS DATE), MONTH) AS month, COUNT(*) AS delivered_count, ROUND(AVG(DATE_DIFF(CAST(delivered_at AS DATE), CAST(shipped_at AS DATE), DAY)), 2) AS avg_delivery_days FROM `your-project-id.thelook_ecommerce.order_items` WHERE delivered_at IS NOT NULL GROUP BY month ORDER BY month

Explanation:

  • Calculate the difference between shipping date and delivery date with DATE_DIFF
  • Calculate the average with AVG
  • Filter only actually delivered items with NULL check

Summary

FunctionUse CaseExample
EXTRACTExtract specific part from dateDay of week, hourly analysis
DATE_TRUNCTruncate date to specific unitMonthly, quarterly aggregation
DATE_DIFFCalculate difference between two datesRetention, delivery days
DATE_ADD/SUBAdd/subtract from dateMonth-over-month, year-over-year analysis

Next Steps

You’ve mastered date/time functions! Next, learn more complex aggregation analysis in Grouping and Aggregation.

Last updated on

🤖AI 모의면접실전처럼 연습하기