1154. Day of the Year
Problem Description
Given a date string in the format YYYY-MM-DD
representing a date in the Gregorian calendar, you need to find which day of the year it is and return that day number.
For example, if the date is 2019-01-09
, this would be the 9th day of the year, so you would return 9
. If the date is 2019-02-10
, you need to count all the days in January (31 days) plus 10 days in February, giving you 31 + 10 = 41
, so you would return 41
.
The key challenge is handling leap years correctly. In the Gregorian calendar:
- A leap year occurs when the year is divisible by
400
, OR when the year is divisible by4
but NOT divisible by100
- Leap years have 29 days in February, while non-leap years have 28 days in February
- All other months have fixed day counts: January (31), March (31), April (30), May (31), June (30), July (31), August (31), September (30), October (31), November (30), December (31)
The solution calculates the total by summing up all the days in the months before the given month, then adding the day number of the current month.
Intuition
To find which day of the year a given date represents, we need to count all the days from January 1st up to the given date.
The most straightforward way to think about this is to break it down into two parts:
- Count all the complete months before the given month
- Add the day number within the current month
For example, if the date is May 15th, we would count all days in January, February, March, and April, then add 15.
The tricky part is February - its number of days changes based on whether it's a leap year or not. So before we can count days, we need to determine if the given year is a leap year. The leap year rule in the Gregorian calendar is: a year is a leap year if it's divisible by 400
, or if it's divisible by 4
but not by 100
.
Once we know February's day count (either 28 or 29), we can create an array containing the number of days in each month: [31, 28/29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
.
Now the calculation becomes simple: if we're in month m
, we sum up the days in months 1
through m-1
(which is sum(days[:m-1])
in Python), then add the current day d
. This gives us the total number of days from the start of the year.
The elegance of this approach is that we're essentially converting a date representation problem into a simple array summation problem, where the only variable element is determining February's day count based on the leap year rule.
Learn more about Math patterns.
Solution Approach
The implementation follows a direct calculation approach by breaking down the problem into manageable steps:
Step 1: Parse the date string
Extract the year, month, and day from the input string date
which is in format YYYY-MM-DD
:
y, m, d = (int(s) for s in date.split('-'))
This splits the string by the hyphen delimiter and converts each part to an integer.
Step 2: Determine if it's a leap year Calculate the number of days in February based on the leap year rule:
v = 29 if y % 400 == 0 or (y % 4 == 0 and y % 100) else 28
According to the Gregorian calendar:
- If the year is divisible by
400
, it's a leap year (29 days in February) - If the year is divisible by
4
but NOT by100
, it's a leap year (29 days in February) - Otherwise, it's not a leap year (28 days in February)
Step 3: Create the days array Build an array containing the number of days in each month:
days = [31, v, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Here, v
represents February's day count (either 28 or 29), and the other months have their fixed day counts.
Step 4: Calculate the day of year Sum up all the days in the months before the current month and add the current day:
return sum(days[: m - 1]) + d
days[: m - 1]
gives us a slice of the array containing all months before monthm
sum(days[: m - 1])
calculates the total days in all previous months- Adding
d
gives us the final day number of the year
For example, if the date is 2019-03-15
:
- Year 2019 is not a leap year (not divisible by 400, and while divisible by 4, we need to check 100)
- February has 28 days
- Sum of days before March:
31 (Jan) + 28 (Feb) = 59
- Final result:
59 + 15 = 74
The time complexity is O(1)
since we're always summing at most 11 months, and the space complexity is also O(1)
for storing the fixed-size days array.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the date 2020-03-05
:
Step 1: Parse the date
- Input:
"2020-03-05"
- After splitting and converting:
y = 2020
,m = 3
,d = 5
Step 2: Check if 2020 is a leap year
- Is 2020 divisible by 400?
2020 % 400 = 20
(No) - Is 2020 divisible by 4?
2020 % 4 = 0
(Yes) - Is 2020 divisible by 100?
2020 % 100 = 20
(No) - Since it's divisible by 4 but NOT by 100, it's a leap year
- Therefore, February has
v = 29
days
Step 3: Build the days array
days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Step 4: Calculate day of year
- We're in month 3 (March), so we need months before March:
days[:2]
- This gives us
[31, 29]
(January and February) - Sum of previous months:
31 + 29 = 60
- Add the current day:
60 + 5 = 65
Therefore, March 5, 2020 is the 65th day of the year.
Let's verify with a simpler non-leap year example: 2019-01-15
- Parse:
y = 2019
,m = 1
,d = 15
- 2019 is not divisible by 4, so it's not a leap year (
v = 28
) - For January (month 1), there are no previous months:
days[:0] = []
- Sum of previous months:
0
- Result:
0 + 15 = 15
So January 15, 2019 is the 15th day of the year, which makes sense!
Solution Implementation
1class Solution:
2 def dayOfYear(self, date: str) -> int:
3 # Parse the date string into year, month, and day components
4 year, month, day = (int(s) for s in date.split('-'))
5
6 # Determine if it's a leap year and set February days accordingly
7 # Leap year conditions: divisible by 400 OR (divisible by 4 AND NOT divisible by 100)
8 february_days = 29 if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0) else 28
9
10 # Days in each month (index 0 = January, index 1 = February, etc.)
11 days_in_months = [31, february_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
12
13 # Calculate the day of year by summing all days in previous months plus current day
14 return sum(days_in_months[:month - 1]) + day
15
1class Solution {
2 /**
3 * Calculate the day of year for a given date string
4 * @param date - date string in format "YYYY-MM-DD"
5 * @return the day number of the year (1-365 or 1-366 for leap years)
6 */
7 public int dayOfYear(String date) {
8 // Parse year, month, and day from the date string
9 int year = Integer.parseInt(date.substring(0, 4));
10 int month = Integer.parseInt(date.substring(5, 7));
11 int day = Integer.parseInt(date.substring(8));
12
13 // Determine if it's a leap year and set February days accordingly
14 // Leap year conditions: divisible by 400 OR (divisible by 4 AND not divisible by 100)
15 int februaryDays = isLeapYear(year) ? 29 : 28;
16
17 // Days in each month (index 0 = January, index 1 = February, etc.)
18 int[] daysInMonth = {31, februaryDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
19
20 // Start with the current day of the month
21 int dayOfYear = day;
22
23 // Add all days from previous months
24 for (int i = 0; i < month - 1; i++) {
25 dayOfYear += daysInMonth[i];
26 }
27
28 return dayOfYear;
29 }
30
31 /**
32 * Helper method to check if a year is a leap year
33 * @param year - the year to check
34 * @return true if leap year, false otherwise
35 */
36 private boolean isLeapYear(int year) {
37 return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
38 }
39}
40
1class Solution {
2public:
3 int dayOfYear(string date) {
4 // Parse year, month, and day from the date string (format: YYYY-MM-DD)
5 int year, month, day;
6 sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day);
7
8 // Determine if it's a leap year and set February days accordingly
9 // Leap year: divisible by 400 OR (divisible by 4 AND NOT divisible by 100)
10 int februaryDays = (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) ? 29 : 28;
11
12 // Days in each month (index 0 = January, index 1 = February, etc.)
13 int daysInMonth[] = {31, februaryDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
14
15 // Initialize result with the day of the current month
16 int dayNumber = day;
17
18 // Add days from all previous months (months are 1-indexed, array is 0-indexed)
19 for (int i = 0; i < month - 1; ++i) {
20 dayNumber += daysInMonth[i];
21 }
22
23 return dayNumber;
24 }
25};
26
1/**
2 * Calculates the day of the year for a given date string
3 * @param date - Date string in format "YYYY-MM-DD"
4 * @returns The day number of the year (1-366)
5 */
6function dayOfYear(date: string): number {
7 // Extract year, month, and day from the date string
8 const year: number = parseInt(date.slice(0, 4));
9 const month: number = parseInt(date.slice(5, 7));
10 const day: number = parseInt(date.slice(8));
11
12 // Determine if it's a leap year and set February days accordingly
13 // Leap year: divisible by 400 OR (divisible by 4 AND NOT divisible by 100)
14 const februaryDays: number = (year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0)) ? 29 : 28;
15
16 // Array of days in each month (index 0 = January, index 11 = December)
17 const daysInMonths: number[] = [31, februaryDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
18
19 // Sum up all days in months before the current month, then add the current day
20 // slice(0, month - 1) gets all months before the current month
21 // reduce sums them up, starting with the current day as initial value
22 return daysInMonths.slice(0, month - 1).reduce((accumulator, currentDays) => accumulator + currentDays, day);
23}
24
Time and Space Complexity
The time complexity is O(1)
. The algorithm performs a fixed number of operations regardless of the input:
- Parsing the date string into three integers is
O(1)
since the date format is fixed (YYYY-MM-DD) - Checking leap year conditions involves a constant number of arithmetic operations
- Creating the
days
list with 12 elements isO(1)
- The
sum(days[: m - 1])
operation sums at most 11 elements (when m=12), which is a constant upper bound - Adding the day value is
O(1)
The space complexity is O(1)
. The algorithm uses a fixed amount of extra space:
- Three integer variables (
y
,m
,d
) - One integer variable
v
for February days - One list
days
with exactly 12 integers - The space used doesn't scale with the input size
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Leap Year Logic
The most frequent mistake is implementing the leap year condition incorrectly. Many developers write:
# WRONG - missing parentheses february_days = 29 if year % 400 == 0 or year % 4 == 0 and year % 100 != 0 else 28
Due to operator precedence, this evaluates as (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)
, which happens to be correct. However, some write:
# WRONG - incorrect logic february_days = 29 if year % 4 == 0 and year % 100 != 0 or year % 400 == 0 else 28
Without proper parentheses, this becomes (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
due to and
having higher precedence than or
, which also works. But if written as:
# WRONG - will fail for years like 2000 february_days = 29 if year % 4 == 0 and year % 100 != 0 else 28
This misses years divisible by 400 (like 2000), incorrectly marking them as non-leap years.
Solution: Always use explicit parentheses or structure the condition clearly:
february_days = 29 if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0) else 28
2. Off-by-One Error in Month Indexing
Since months in the date string are 1-indexed (January = 1) but Python lists are 0-indexed, developers might incorrectly slice:
# WRONG - includes the current month in the sum
return sum(days_in_months[:month]) + day
This would include the days of the current month in the sum, leading to incorrect results.
Solution: Use month - 1
to exclude the current month:
return sum(days_in_months[:month - 1]) + day
3. String Parsing Errors
Some developers might forget to convert string components to integers:
# WRONG - comparing strings instead of integers year, month, day = date.split('-') february_days = 29 if year % 400 == 0 else 28 # TypeError: not all arguments converted
Solution: Ensure all components are converted to integers:
year, month, day = map(int, date.split('-'))
# or
year, month, day = (int(s) for s in date.split('-'))
4. Hardcoding February as 28 Days
A simplistic approach might hardcode all month days without considering leap years:
# WRONG - always uses 28 days for February
days_in_months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
return sum(days_in_months[:month - 1]) + day
Solution: Calculate February's days dynamically based on the year:
february_days = 29 if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0) else 28 days_in_months = [31, february_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Which technique can we use to find the middle of a linked list?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!