How to Add or Subtract Days, Months, or Years from a Date in C#

Manipulating dates is a common task in C# applications, whether for scheduling, logging, or calculations.

The DateTime and DateOnly structures provide built-in methods to add or subtract days, months, years, hours, and minutes efficiently.

Adding and Subtracting Days

Use the AddDays method to modify a DateTime instance:

using System;

class Program
{
    static void Main()
    {
        DateTime today = DateTime.Now;
        DateTime nextWeek = today.AddDays(7);
        DateTime lastWeek = today.AddDays(-7);

        Console.WriteLine($"Today: {today:yyyy-MM-dd HH:mm}");
        Console.WriteLine($"Next Week: {nextWeek:yyyy-MM-dd HH:mm}");
        Console.WriteLine($"Last Week: {lastWeek:yyyy-MM-dd HH:mm}");
    }
}

Adding and Subtracting Months

Use the AddMonths method to adjust the month while automatically handling month-end variations:

DateTime currentDate = new DateTime(2025, 3, 31);
DateTime nextMonth = currentDate.AddMonths(1);
DateTime previousMonth = currentDate.AddMonths(-1);

Console.WriteLine($"Current Date: {currentDate:yyyy-MM-dd HH:mm}");
Console.WriteLine($"Next Month: {nextMonth:yyyy-MM-dd HH:mm}");
Console.WriteLine($"Previous Month: {previousMonth:yyyy-MM-dd HH:mm}");

Adding and Subtracting Years

Use the AddYears method to adjust the year, handling leap years automatically:

DateTime date = new DateTime(2024, 2, 29);
DateTime nextYear = date.AddYears(1);
DateTime previousYear = date.AddYears(-1);

Console.WriteLine($"Original Date: {date:yyyy-MM-dd HH:mm}");
Console.WriteLine($"Next Year: {nextYear:yyyy-MM-dd HH:mm}");
Console.WriteLine($"Previous Year: {previousYear:yyyy-MM-dd HH:mm}");

Adding and Subtracting Hours

Use the AddHours method to modify the hour component:

DateTime now = DateTime.Now;
DateTime inFiveHours = now.AddHours(5);
DateTime fiveHoursAgo = now.AddHours(-5);

Console.WriteLine($"Current Time: {now:yyyy-MM-dd HH:mm}");
Console.WriteLine($"In 5 Hours: {inFiveHours:yyyy-MM-dd HH:mm}");
Console.WriteLine($"5 Hours Ago: {fiveHoursAgo:yyyy-MM-dd HH:mm}");

Adding and Subtracting Minutes

Use the AddMinutes method to modify the minute component:

DateTime currentTime = DateTime.Now;
DateTime inThirtyMinutes = currentTime.AddMinutes(30);
DateTime thirtyMinutesAgo = currentTime.AddMinutes(-30);

Console.WriteLine($"Current Time: {currentTime:yyyy-MM-dd HH:mm}");
Console.WriteLine($"In 30 Minutes: {inThirtyMinutes:yyyy-MM-dd HH:mm}");
Console.WriteLine($"30 Minutes Ago: {thirtyMinutesAgo:yyyy-MM-dd HH:mm}");

Using DateOnly for Simpler Date Manipulation

For applications that don't require time components, DateOnly (introduced in .NET 6) provides a cleaner approach:

DateOnly today = DateOnly.FromDateTime(DateTime.Now);
DateOnly futureDate = today.AddDays(30);

Console.WriteLine($"Today: {today}");
Console.WriteLine($"30 Days Later: {futureDate}");

Conclusion

C# provides built-in methods for adjusting dates effortlessly. Whether working with DateTime or DateOnly, these functions ensure accurate date calculations, even when dealing with leap years, month-end scenarios, hours, and minutes.

1
520

Related

Primary constructors, introduced in C# 12, offer a more concise way to define class parameters and initialize fields.

This feature reduces boilerplate code and makes classes more readable.

Traditional Approach vs Primary Constructor

Before primary constructors, you would likely write something like the following:

public class UserService
{
    private readonly ILogger _logger;
    private readonly IUserRepository _repository;

    public UserService(ILogger logger, IUserRepository repository)
    {
        _logger = logger;
        _repository = repository;
    }

    public async Task<User> GetUserById(int id)
    {
        _logger.LogInformation("Fetching user {Id}", id);
        return await _repository.GetByIdAsync(id);
    }
}

With primary constructors, this becomes:

public class UserService(ILogger logger, IUserRepository repository)
{
    public async Task<User> GetUserById(int id)
    {
        logger.LogInformation("Fetching user {Id}", id);
        return await repository.GetByIdAsync(id);
    }
}

Key Benefits

  1. Reduced Boilerplate: No need to declare private fields and write constructor assignments
  2. Parameters Available Throughout: Constructor parameters are accessible in all instance methods
  3. Immutability by Default: Parameters are effectively readonly without explicit declaration

Real-World Example

Here's a practical example using primary constructors with dependency injection:

public class OrderProcessor(
    IOrderRepository orderRepo,
    IPaymentService paymentService,
    ILogger<OrderProcessor> logger)
{
    public async Task<OrderResult> ProcessOrder(Order order)
    {
        try
        {
            logger.LogInformation("Processing order {OrderId}", order.Id);
            
            var paymentResult = await paymentService.ProcessPayment(order.Payment);
            if (!paymentResult.Success)
            {
                return new OrderResult(false, "Payment failed");
            }

            await orderRepo.SaveOrder(order);
            return new OrderResult(true, "Order processed successfully");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to process order {OrderId}", order.Id);
            throw;
        }
    }
}

Tips and Best Practices

  1. Use primary constructors when the class primarily needs dependencies for its methods
  2. Combine with records for immutable data types:
public record Customer(string Name, string Email)
{
    public string FormattedEmail => $"{Name} <{Email}>";
}
  1. Consider traditional constructors for complex initialization logic

Primary constructors provide a cleaner, more maintainable way to write C# classes, especially when working with dependency injection and simple data objects.

1
69

When working with SQL Server, you may often need to count the number of unique values in a specific column. This is useful for analyzing data, detecting duplicates, and understanding dataset distributions.

Using COUNT(DISTINCT column_name)

To count the number of unique values in a column, SQL Server provides the COUNT(DISTINCT column_name) function. Here’s a simple example:

SELECT COUNT(DISTINCT column_name) AS distinct_count
FROM table_name;

This query will return the number of unique values in column_name.

Counting Distinct Values Across Multiple Columns

If you need to count distinct combinations of multiple columns, you can use a subquery:

SELECT COUNT(*) AS distinct_count
FROM (SELECT DISTINCT column1, column2 FROM table_name) AS subquery;

This approach ensures that only unique pairs of column1 and column2 are counted.

Why Use COUNT DISTINCT?

  • Helps in identifying unique entries in a dataset.
  • Useful for reporting and analytics.
  • Efficient way to check for duplicates.

By leveraging COUNT(DISTINCT column_name), you can efficiently analyze your database and extract meaningful insights. Happy querying!

1
115

String interpolation, introduced in C# 6.0, provides a more readable and concise way to format strings compared to traditional concatenation (+) or string.Format(). Instead of manually inserting variables or placeholders, you can use the $ symbol before a string to directly embed expressions inside brackets.

string name = "Walt";
string job = 'Software Engineer';

string message = $"Hello, my name is {name} and I am a {job}";
Console.WriteLine(message);

This would produce the final output of:

Hello, my name is Walt and I am a Software Engineer

String interpolation can also be chained together into a multiline string (@) for even cleaner more concise results:

string name = "Walt";
string html = $@"
    <div>
        <h1>Welcome, {name}!</h1>
    </div>";
37
148