ggplot2 scale_x_date() in R: Format Date Axis

The scale_x_date() function in ggplot2 customizes the X axis when x is a Date. It controls break intervals (every month, every quarter) and label formats (year, month name, etc.).

⚡ Quick Answer
+ scale_x_date(date_breaks = "1 month", date_labels = "%b %Y")
+ scale_x_date(date_breaks = "quarter")
+ scale_x_date(date_labels = "%Y")
+ scale_x_date(limits = as.Date(c("2020-01-01","2024-12-31")))
+ scale_x_datetime()                       # POSIXct version

Need explanation? Read on for examples and pitfalls.

📊 Is scale_x_date() the right tool?
STARTx is Date classscale_x_date()x is POSIXct (datetime)scale_x_datetime()numeric xscale_x_continuous()format datesdate_labels = "%b %Y"interval breaksdate_breaks = "1 month"

What scale_x_date() does in one sentence

scale_x_date() controls a Date X axis with shortcut arguments date_breaks (interval) and date_labels (strftime format). Used for time-series plots.

Syntax

**scale_x_date(date_breaks = NULL, date_labels = NULL, date_minor_breaks = NULL, ...). Standard scale__continuous args also apply.*

Run live
Run live, no install needed. Every R block on this page runs in your browser. Click Run, edit the code, re-run instantly. No setup.
RMonthly breaks with abbreviated month-year labels
library(ggplot2) ggplot(economics, aes(date, unemploy)) + geom_line() + scale_x_date(date_breaks = "5 years", date_labels = "%Y")

  
Tip
date_breaks = "1 month" is the cleanest way to control interval; manual breaks = works but is verbose for date data.

Five common patterns

1. Yearly labels

RYear only
+ scale_x_date(date_labels = "%Y")

  

2. Month-year

RJan 2024
+ scale_x_date(date_breaks = "3 months", date_labels = "%b %Y")

  

3. Day-month

R01-Jan
+ scale_x_date(date_labels = "%d-%b")

  

4. Limit to a range

RZoom to 2020 onward
+ scale_x_date(limits = as.Date(c("2020-01-01","2024-12-31")))

  

5. Quarterly breaks

REvery 3 months
+ scale_x_date(date_breaks = "quarter", date_labels = "Q%q %Y")

  
Key Insight
date_labels uses strftime format codes. Common: %Y (4-digit year), %y (2-digit), %b (abbreviated month), %B (full month), %m (number), %d (day).

scale_x_date() vs scale_x_datetime() vs scale_x_continuous

Function x class
scale_x_date() Date
scale_x_datetime() POSIXct
scale_x_time() hms
scale_x_continuous() numeric

When to use which: pick by the class of your x variable. class(df$date) tells you which.

A practical workflow

For time-series, set sensible breaks and labels per data span.

RInteractive R
events |> ggplot(aes(date, value)) + geom_line() + scale_x_date( date_breaks = "1 year", date_minor_breaks = "1 month", date_labels = "%Y" )

  

Major ticks yearly, minor every month.

Common pitfalls

Pitfall 1: x is character, not Date. scale_x_date expects Date class. Convert first: mutate(date = as.Date(date_str)).

Pitfall 2: timezone surprises. For POSIXct, use scale_x_datetime. Date-only (no time) uses scale_x_date.

Warning
scale_x_date will fail silently if x is numeric or character. Always check class(df$x) returns "Date".

Try it yourself

Try it: Plot economics$unemploy by date with yearly labels. Save to ex_plot.

RYour turn: yearly date axis
ex_plot <- ggplot(economics, aes(date, unemploy)) + geom_line() + # your code here

  
Click to reveal solution
RSolution
ex_plot <- ggplot(economics, aes(date, unemploy)) + geom_line() + scale_x_date(date_breaks = "5 years", date_labels = "%Y")

  

Explanation: Major ticks every 5 years; year-only labels.

After mastering scale_x_date, look at:

  • scale_x_datetime(): POSIXct
  • scale_x_continuous(): numeric
  • scale_x_discrete(): factor / character
  • scales::date_breaks() / date_format(): lower-level helpers

FAQ

What does scale_x_date do in ggplot2?

scale_x_date() formats the X axis when x is a Date. Controls breaks and labels with date-specific shortcuts.

What is the difference between scale_x_date and scale_x_datetime?

scale_x_date for Date class (no time). scale_x_datetime for POSIXct (with time). Pick by class of your x.

How do I show only the year on x?

scale_x_date(date_labels = "%Y"). Use strftime codes for any format.

How do I make ticks every quarter?

scale_x_date(date_breaks = "3 months") or date_breaks = "quarter".

What if my dates are character?

Convert first: mutate(date = as.Date(date_str)). scale_x_date requires Date class.