# Nepali Date Arithmetic in .NET: AddDays, AddMonths, and Date Ranges

AddDays, AddMonths, AddYears, and NepaliDateRange - the complete date arithmetic and interval API in NepDate for .NET, with verified C# code examples.

URL: https://rajuprasai.com.np/blog/nepali-date-arithmetic-ranges.html
Published: 2026-06-02
Tags: Bikram Sambat, nepali calendar, nepali date converter, NepDate, .NET, C#
Read time: 8 min

**Author:** Raju Prasai - Project Manager & Senior .NET Engineer, Jhapa, Nepal
**Portfolio:** https://rajuprasai.com.np/

---

## The Next Problem After Conversion

Most Nepali .NET developers reach for a date library when they first need to display a date in BS. They convert, it works, and they move on. The harder problem arrives later: building a report for the current fiscal year, computing a 30-day deadline, or checking whether a submitted date falls within an allowed range.

BS date arithmetic has the same constraint as BS conversion: month lengths vary by year and cannot be derived from a formula. "Add 3 months to Ashadh 15" requires knowing the actual day count of Shrawan, Bhadra, and Ashwin for that year. There is no arithmetic shortcut.

NepDate handles this through three arithmetic methods on `NepaliDate` and the `NepaliDateRange` struct, which provides factory methods for the most common interval types.

```
dotnet add package NepDate
```

---

## AddDays

`AddDays` delegates to the Gregorian calendar: the date is converted to a `DateTime`, the specified number of days is added, and the result is converted back. It is always correct across all month and year boundaries with no special cases.

```csharp
using NepDate;

var today        = NepaliDate.Today;  // 2083/02/19 on 2026-06-02
var probationEnd = today.AddDays(30);
// probationEnd → 2083/03/18  (AD: 2026-07-02)
```

Negative values move backward. Fractional values are accepted but since `NepaliDate` has no time component, only the integer portion matters.

---

## AddMonths and AddYears

`AddMonths` and `AddYears` operate in month and year space and still respect variable month lengths. Both methods take an `awayFromMonthEnd` parameter that controls what happens when the target month is shorter than the current day number.

When `false` (the default), the day is clamped to the last valid day of the target month. When `true`, the overflow days carry forward into the following month.

```csharp
// Ashadh 2082 has 32 days. Shrawan 2082 has 31 days.
var lastOfAshadh = new NepaliDate(2082, 3, 32);

// Default (awayFromMonthEnd: false): clamp to last valid day
var clamped  = lastOfAshadh.AddMonths(1);
// clamped → 2082/04/31

// awayFromMonthEnd: true - carry the 1 extra day into Bhadra
var overflow = lastOfAshadh.AddMonths(1, awayFromMonthEnd: true);
// overflow → 2082/05/01
```

The clamped default is correct for most HR and payroll use cases. An employee hired on Ashadh 32 whose review falls in a 30-day month should land on the last day of that month.

```csharp
var hireDate   = new NepaliDate(2082, 3, 32);
var reviewDate = hireDate.AddMonths(6);  // awayFromMonthEnd: false (default)
// Poush 2082 has 30 days - day 32 is clamped
// reviewDate → 2082/09/30
```

`AddYears` follows the same semantics:

```csharp
var today    = new NepaliDate(2083, 2, 19);
var nextYear = today.AddYears(1);
// nextYear → 2084/02/19  (AD: 2027-06-02)
```

---

## Subtraction and Comparison

The `-` operator between two `NepaliDate` values returns a `TimeSpan`:

```csharp
var y2083Start = new NepaliDate(2083, 1, 1);
var y2082Start = new NepaliDate(2082, 1, 1);
TimeSpan span  = y2083Start - y2082Start;
// span.Days → 365
```

Comparison operators work as expected. `NepaliDate` implements `IComparable<NepaliDate>`, so LINQ `OrderBy`, sorted sets, and min/max work without a custom comparer:

```csharp
var d1 = new NepaliDate(2083, 2, 19);
var d2 = new NepaliDate(2083, 2, 20);

bool earlier = d1 < d2;                            // true
bool same    = d1 == new NepaliDate(2083, 2, 19);  // true
bool after   = d2 > d1;                            // true
```

---

## Working with NepaliDateRange

`NepaliDateRange` is an inclusive `[start, end]` interval with factory methods that construct the most common ranges correctly without any manual calculation.

```csharp
// Jestha 2083 as a month range (31 days)
var jestha  = NepaliDateRange.ForMonth(2083, 2);
// jestha.Start  → 2083/02/01
// jestha.End    → 2083/02/31
// jestha.Length → 31

// BS 2082 calendar year
var calYear = NepaliDateRange.ForCalendarYear(2082);
// calYear.Start  → 2082/01/01  (AD: 2025-04-14)
// calYear.End    → 2082/12/30  (AD: 2026-04-13)
// calYear.Length → 365

// FY 2082/83: Shrawan 1, 2082 through last day of Ashadh 2083
var fy2082  = NepaliDateRange.ForFiscalYear(2082);
// fy2082.Start  → 2082/04/01  (AD: 2025-07-17)
// fy2082.End    → 2083/03/32  (AD: 2026-07-16)
// fy2082.Length → 365
```

Note: end of FY 2082/83 is Ashadh **32**, 2083 - not 31. `ForFiscalYear` calls `MonthEndDate()` internally to get the actual last day. A query that hardcodes 31 silently drops one day of data.

The `Current*` variants derive the range from today's date:

```csharp
// As of Jestha 19, 2083 - month 2 is before Shrawan (month 4),
// so the current fiscal year is still FY 2082/83
var currentFY    = NepaliDateRange.CurrentFiscalYear();
// Start → 2082/04/01, End → 2083/03/32, Length → 365

var currentMonth = NepaliDateRange.CurrentMonth();
// Start → 2083/02/01, End → 2083/02/31

var currentYear  = NepaliDateRange.CurrentCalendarYear();
// Start → 2083/01/01, End → 2083/12/30
```

You can also construct a range manually:

```csharp
var custom = new NepaliDateRange(
    new NepaliDate(2082, 6, 1),
    new NepaliDate(2082, 9, 30)
);
```

`NepaliDateRange` implements `IEnumerable<NepaliDate>` so you can enumerate every date in the range for calendar grids or daily summaries.

---

## Contains and Overlaps

`Contains` checks whether a specific date falls within the range, inclusive on both ends:

```csharp
var fy = NepaliDateRange.ForFiscalYear(2082);

// Chaitra 15, 2082 - month 12, calendar year 2082, but Q3 of FY 2082/83
bool a = fy.Contains(new NepaliDate(2082, 12, 15));  // true

// Jestha 15, 2083 - calendar year 2083, but still in FY 2082/83
bool b = fy.Contains(new NepaliDate(2083, 2, 15));   // true
```

FY 2082/83 runs through Ashadh end 2083. Dates in Baishakh, Jestha, and Ashadh of calendar year 2083 belong to FY 2082/83, not FY 2083/84.

For database queries, convert range bounds to Gregorian and use an exclusive upper bound:

```csharp
var fy       = NepaliDateRange.ForFiscalYear(2082);
DateTime adStart = fy.Start.EnglishDate;          // 2025-07-17 (inclusive)
DateTime adEnd   = fy.End.EnglishDate.AddDays(1); // 2026-07-17 (exclusive upper bound)

var rows = dbContext.Transactions
    .Where(t => t.Date >= adStart && t.Date < adEnd)
    .ToList();
```

---

## Parsing Mixed Input with SmartDateParser

`SmartDateParser` accepts over 100 spellings of Nepali month names - English transliterations, Devanagari names, common abbreviations - as well as Devanagari digit strings and numeric formats with any common separator.

```csharp
using NepDate;

NepaliDate d1 = SmartDateParser.Parse("15 Jestha 2083");   // 2083/02/15
NepaliDate d2 = SmartDateParser.Parse("२०८३/०२/१९");        // 2083/02/19 - Devanagari digits
NepaliDate d3 = SmartDateParser.Parse("15 Jeth 2083");     // 2083/02/15 - alternate spelling
NepaliDate d4 = SmartDateParser.Parse("15 जेठ 2083");      // 2083/02/15 - Devanagari month name
```

For controlled input where the format is known, use `NepaliDate.Parse` or `TryParse` at system boundaries:

```csharp
// Strict - throws on invalid input
NepaliDate parsed = NepaliDate.Parse("2083-02-19");

// Safe - returns false instead of throwing
if (NepaliDate.TryParse(userInput, out NepaliDate result))
{
    // result is a valid NepaliDate
}
```

---

## Conclusion

The full date arithmetic surface in NepDate: `AddDays` always delegates to Gregorian space for correctness; `AddMonths` and `AddYears` operate in BS month space with a configurable overflow policy; the `-` operator returns a `TimeSpan`; `NepaliDateRange` factory methods produce correct interval bounds including variable Ashadh end days; and `SmartDateParser` handles the full range of real-world BS date string formats.

- NuGet: https://www.nuget.org/packages/NepDate/
- GitHub: https://github.com/RajuPrasai/NepDate
- API docs: https://nepdate.rajuprasai.com.np/
- Previous post: https://rajuprasai.com.np/blog/bikram-sambat-calendar-math.html

---

## Related

- NepDate .NET Library: https://nepdate.rajuprasai.com.np/
- NepDate Widget: https://nepdatewidget.rajuprasai.com.np/
- Portfolio: https://rajuprasai.com.np/
