MongoDB $dayOfYear Operator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $dayOfYear?

$dayOfYear is a MongoDB aggregation expression that returns the day number within the year for a date as an integer from 1 to 366. January 1 is 1; December 31 is 365 or 366 in a leap year.

Remember
$dayOfYear = day number inside the year

{ $dayOfYear: <dateExpression> }
{ $dayOfYear: { date: <date>, timezone: <tz> } }

Jan 1      → 1
Feb 29     → 60   (leap years only)
Dec 31     → 365 or 366

default timezone → UTC
string date → error
null / missing → null
UsePrefer
Day number in the year (1–366)$dayOfYear
Day number in the month (1–31)$dayOfMonth
Weekday number (Sun=1)$dayOfWeek

How to Use $dayOfYear in MongoDB

Pass a date field (or date + timezone), then filter or group on the day number if needed.

  1. Choose an expression stage ($project or $addFields).
  2. Ensure the argument is a Date / Timestamp / ObjectId (not a plain string).
  3. Pass that expression to $dayOfYear (add timezone when you need a local calendar day).
  4. Optionally filter ranges with $match (for example late-year days).
PieceRequired?Role
$dayOfYearYesDay-of-year → integer 1–366
Date expressionYesField, ISODate, Timestamp, or ObjectId
timezoneNoLocal day-of-year instead of UTC

Pseudocode

Pseudocode
for each document:
    d = evaluate(dateExpression)   // Date / Timestamp / ObjectId
    if d is null or missing:
        result = null
    else if d is a string:
        error
    else:
        // optional timezone shifts the calendar day first
        result = dayNumberInYear(d)   // 1 … 366
    emit { ..., field: result }

Cheat Sheet

Keep these facts handy while extracting day-of-year values.

TopicDetail
TypeAggregation expression (not a find filter alone)
Syntax{ $dayOfYear: "$when" }
With timezone{ $dayOfYear: { date: "$when", timezone: "America/New_York" } }
Range1 … 366
Default TZUTC
Leap year Dec 31366
Sample check2024-02-29 (UTC) → 60

Live Preview

Watch $dayOfYear turn a UTC date into a day number inside the year.

Simulates { $dayOfYear: ISODate("…") } in UTC (same idea as the mongosh examples below).

Result
when = 2024-02-29T12:00:00.000Z
$dayOfYear → 60

{ title: "Leap Day", dayOfYear: 60 }

Worked Walkthrough — Why Leap Day Is 60

In 2024 (a leap year), February 29 is the 60th day. March 1 becomes day 61—one later than in a non-leap year.

Calculation
UTC date: 2024-02-29T12:00:00Z

Days before Feb 29 in a leap year:
  Jan (31) + Feb 1–28 (28) = 59
  Feb 29 is the next day → 60

$dayOfYear(...) → 60

Compare:
  2023-03-01 → day 60   (no Feb 29)
  2024-03-01 → day 61   (leap day pushed March forward)
  2024-12-31 → day 366

MongoDB Examples

We store three 2024 dates (New Year, leap day, year end), extract the day-of-year, then keep late-year events. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine a tiny milestones collection with three UTC dates in the leap year 2024.

mongosh
db.milestones.insertMany([
  { _id: 1, title: "New Year", when: ISODate("2024-01-01T12:00:00Z") },
  { _id: 2, title: "Leap Day", when: ISODate("2024-02-29T12:00:00Z") },
  { _id: 3, title: "Year End", when: ISODate("2024-12-31T12:00:00Z") }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps three documents in milestones. Run find() to see them:

mongosh
db.milestones.find()

Read those documents like this:

Field in MongoDBValuePlain English
_id1 … 3Document id for this lesson
title"New Year", "Leap Day", "Year End"Milestone name
whenUTC ISODate valuesDate we will turn into a day-of-year
Picture
Expected $dayOfYear (UTC, leap year 2024):

  New Year  2024-01-01 → 1
  Leap Day  2024-02-29 → 60
  Year End  2024-12-31 → 366

How It Works

  1. Insert once. insertMany adds three milestone documents with real BSON dates.
  2. Dates span the year. You get the first day, leap day, and last day of 2024.
  3. find() shows the same shape. Ready for $dayOfYear next.

Example 2 — Extract Day-of-Year

Goal: project each title with its $dayOfYear number.

mongosh
db.milestones.aggregate([
  {
    $project: {
      title: 1,
      dayOfYear: { $dayOfYear: "$when" },
      _id: 0
    }
  }
]);

How It Works

  1. Read the date field. "$when" is a BSON Date from Example 1.
  2. Count from Jan 1. $dayOfYear returns 1, 60, and 366 in UTC.
  3. Keep a short report. $project keeps title and adds dayOfYear.
  4. Need local time? Use { $dayOfYear: { date: "$when", timezone: "Asia/Kolkata" } }.

Example 3 — Filter Late Year

Same collection: keep only milestones on day 300 or later (roughly November onward).

mongosh
db.milestones.aggregate([
  {
    $addFields: {
      dayOfYear: { $dayOfYear: "$when" }
    }
  },
  {
    $match: {
      dayOfYear: { $gte: 300 }
    }
  },
  {
    $project: {
      title: 1,
      dayOfYear: 1,
      _id: 0
    }
  }
]);

How It Works

  1. Add the day number first. $addFields computes dayOfYear for every milestone.
  2. Keep late days only. $match with $gte: 300 drops Jan 1 and leap day.
  3. Trim the output. $project keeps title and dayOfYear.
  4. Easy check. Only Year End (366) is at or after day 300.

Edge Cases & Pitfalls

Check these before using $dayOfYear in production pipelines.

leap

366 only in leap years

Do not assume December 31 is always 366. In 2023 it is 365. Leap day itself is day 60.

timezone

UTC by default

A late local evening can be the next UTC day and bump the day-of-year. Pass timezone when the local calendar day matters.

types

Strings are not dates

"2024-01-01" as a string errors. Store BSON dates, or convert with $dateFromString first.

null

Null and missing become null

Missing date fields return null, not an error. Filter them before range checks if nulls are invalid.

Performance Notes

ApproachCostBest for
$dayOfYear alonePer-document date mathReports and season buckets
+ $match on day numberStill scans after computeEarly/late year filters
Date-range $match firstCan use indexes on the date fieldNarrowing to one year before extracting

Date extraction is cheap compared with large joins. Prefer an early date-range $match when you only need one year of data.

Key Takeaways

  • Role: day number in the year → 1–366.
  • Leap years: Feb 29 = 60, Dec 31 = 366.
  • Timezone: UTC by default; pass timezone for local days.
  • Siblings: $dayOfMonth / $dayOfWeek for other day scales.

One line: $dayOfYear answers “which day of the year is this date?”—from 1 on Jan 1 up to 365 or 366.

Frequently Asked Questions

$dayOfYear returns an integer from 1 to 366 for the day number within the year. January 1 is 1. December 31 is 365 in a common year and 366 in a leap year. Use it inside aggregation expression stages such as $project and $addFields.
Short form: { $dayOfYear: <dateExpression> }. Document form: { $dayOfYear: { date: <dateExpression>, timezone: <tz> } }. The date must resolve to a Date, Timestamp, or ObjectId—not a string.
Yes by default. Pass timezone (Olson id like "America/New_York" or an offset like "-0400") in the document form when you need a local day-of-year.
In a leap year, February 29 is day 60 and December 31 is 366. In a non-leap year, December 31 is 365 and there is no day 60 for Feb 29.
$dayOfYear counts from the start of the year (1–366). $dayOfMonth counts from the start of the month (1–31).
$dayOfYear returns null when the input is null or the field is missing. A plain string date causes an aggregation error.

Next: $degreesToRadians

Convert an angle in degrees to radians in an aggregation pipeline.

$degreesToRadians tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful