In the previous chapter, you practiced calculations from the economic world. You will frequently need to do calculations with dates, too. Say you need to set the date when an invoice is due. Or say you want to calculate how many days an invoice is past due. Or, you might need to know the first and last days of a specific period like a month or a quarter. In this chapter, you’ll learn how to do calculations with dates.
Date Input
First, you will learn how to read a date from a user. I will show you some simple date arithmetic, too.
Task
In this task, you will get a DateTime object based on the user input. After that, you will calculate the next and previous days (see Figure 11-1).
Figure 11-1 Calculating the next and previous days
Solution
The point is to use the Convert. ToDateTime method. If the user enters a nonexistent day (February 29 of a nonleap year, for example), the method causes a runtime error that you can deal with using the try-catch construction.
static void Main(string[] args)
{
try
{
// Text input of date
Console.Write("Enter date: ");
string input = Console.ReadLine();
// Conversion to DateTime object
DateTime enteredDate = Convert.ToDateTime(input);
// Some calculations
DateTime followingDay = enteredDate.AddDays(1);
DateTime previousDay = enteredDate.AddDays(-1);
// Outputs
Console.WriteLine();
Console.WriteLine("Entered day : " + enteredDate.ToLongDateString());
Console.WriteLine("Following day: " + followingDay.ToLongDateString());
Console.WriteLine("Previous day : " + previousDay.ToLongDateString());
}
catch (Exception)
{
// Treating incorrect input
Console.WriteLine("Incorrect input");
}
// Waiting for Enter
Console.ReadLine();
}
Discussion
You can also call the Convert.ToDateTime method with two parameters instead of one. The second parameter is the language setting, which is the CultureInfo object you already know. This is similar to other conversion methods.
Single Month
Now you will practice working with DateTime components and creating this object using a constructor call.
Task
A user enters a date. This program displays the first and last days of the month in which the entered date falls (see Figure 11-2).
Figure 11-2 Calcuating the first and last days of the month
Solution
Here is the code:
static void Main(string[] args)
{
// Date input
Console.Write("Enter a date: ");
string input = Console.ReadLine();
DateTime enteredDate = Convert.ToDateTime(input);
// Calculations
int enteredYear = enteredDate.Year;
int enteredMonth = enteredDate.Month;
DateTime firstDayOfMonth = new DateTime(enteredYear, enteredMonth, 1);
DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
// Outputs
Console.WriteLine();
Console.WriteLine("Corresponding month: " +
"from " + firstDayOfMonth.ToShortDateString() +
" to " + lastDayOfMonth.ToShortDateString());
// Waiting for Enter
Console.ReadLine();
}
Discussion
Note the following:
According to the previous exercise, you get a DateTime object from the user using the Convert.ToDateTime method call.
You start picking the month and year numbers from the entered date. You use the Month and Year properties for that purpose.
Using these numbers, you easily assemble the first day of the month because its day number is always 1.
The last day of the month is not that easy because months differ in length. The trick is to add a month and subtract a day!
Note that I do not store AddMonth’s result anywhere. I directly call AddDays upon it instead. This is called method chaining.
For the sake of simplicity, I do not deal with the possibility of incorrect input here.
Quarter
Continuing with dates, I will show you some interesting tricks you must sometimes employ to get the correct results.
Task
For the entered day, this program will display the beginning, end, and number (from 1 to 4) of the year’s quarter that the day belongs to (see Figure 11-3 and Figure 11-4).
Figure 11-3 Showing the corresponding quarter
Figure 11-4 Showing the corresponding quarter, another example
Analysis
The key to this task is to determine the quarter’s number. From that, the quarter’s first month follows.
Quarter’s Number
You need to transform the month number into the quarter’s number like this:
Month 1, 2, or 3 = 1
Month 4, 5, or 6 = 2
Month 7, 8, or 9 = 3
Month 10, 11, or 12 = 4
This is a beautiful case of integer division use. You can see that you need to add 2 to the month number first and perform integer division by 3 after that.
int numberOfQuarter = (enteredMonth + 2) / 3;
Quarter’s First Month Number
If you already have the quarter’s number, you get the quarter’s first month like this:
1 (January) for the first quarter
4 (April) for the second quarter
7 (July) for the third quarter
10 (October) for the fourth quarter
You may realize that the quarter’s number has to be multiplied by 3. To get the correct results, you need to subtract 2 subsequently.
int monthOfQuarterStart = 3 * numberOfQuarter - 2;
First and Last Days
Having the first month available, you can proceed in steps similar to the previous exercise. To get the first day, you use the DateTime constructor with the day number set to 1. To get the last day, you add three months and subtract one day.
Solution
Here is the code:
static void Main(string[] args)
{
// Date input
Console.Write("Enter a date: ");
string input = Console.ReadLine();
DateTime enteredDate = Convert.ToDateTime(input);
// Calculations
int enteredYear = enteredDate.Year;
int enteredMonth = enteredDate.Month;
int numberOfQuarter = (enteredMonth + 2) / 3;
int monthOfQuarterStart = 3 * numberOfQuarter - 2;
DateTime firstDayOfQuarter = new DateTime(enteredYear, monthOfQuarterStart, 1);
DateTime lastDayOfQuarter = firstDayOfQuarter.AddMonths(3).AddDays(-1);
// Outputs
Console.WriteLine();
Console.WriteLine("Corresponding quarter: " +
"number-" + numberOfQuarter +
", from " + firstDayOfQuarter.ToShortDateString() +
" to " + lastDayOfQuarter.ToShortDateString());
// Waiting for Enter
Console.ReadLine();
}
Date Difference
You frequently need to calculate the time span between two specific dates, in other words, how many days or years have passed between the entered dates. This is what you will study now.
Task
A user enters the date of her birth. The program displays how many days the world is happy to have her (see Figure 11-5).
Figure 11-5 Calculating how many days alive
Solution
As you can see, you need to subtract the birth date from today’s date. When you subtract dates, the result is a TimeSpan object. With this object in hand, you can use one of its many properties. You will use the Days property in this exercise.
Here is the code:
static void Main(string[] args)
{
// Input
Console.Write("Enter your date of birth: ");
string input = Console.ReadLine();
DateTime dateOfBirth = Convert.ToDateTime(input);
// Today
DateTime today = DateTime.Today;
// Date difference
TimeSpan difference = today - dateOfBirth;
int numberOfDays = difference.Days;
// Output
Console.WriteLine();
Console.WriteLine("Today is: " + today.ToShortDateString());
Console.WriteLine("The world likes you for this number of days: " + numberOfDays.ToString("N0"));
// Waiting for Enter
Console.ReadLine();
}
Time Zones and UTC
If you want to store the moment when something happened (e.g., to log orders, issues, and so on), you may be unpleasantly surprised by daylight saving time. Or, maybe more important, say you are creating a program that will operate across the globe. You will have to work with different time zones.
To handle these cases, it is good to know how to work with Universal Time Coordinated (UTC), which is the time at the zeroth meridian free from food additives. Pardon me, I mean free from daylight saving. UTC is simply time-zone independent.
It is also good to get acquainted with DateTimeOffset objects that contain time zone information in addition to the date and time.
Task
In this exercise, I will show you how to work both with UTC and with the time zones included in a DateTimeOffset object. You will make a program that works with the current time (see Figure 11-6).
Figure 11-6 DateTimeOffset object
Solution
Here is the code:
static void Main(string[] args)
{
// Current time serves as input
DateTime now = DateTime.Now;
DateTime utcNow = DateTime.UtcNow;
DateTimeOffset completeInstant = DateTimeOffset.Now;
DateTimeOffset utcCompleteInstant = DateTimeOffset.UtcNow;
// Outputs
Console.WriteLine("Now: " + now);
Console.WriteLine("UTC now: " + utcNow);
Console.WriteLine("Now (including time zone): " + completeInstant);
Console.WriteLine("Time zone (offset against UTC): " + completeInstant.Offset.TotalHours);
Console.WriteLine("UTC now (including time zone): " + utcCompleteInstant);
// Waiting for Enter
Console.ReadLine();
}
Please note that some variables are of the DateTime type, while others are of the DateTimeOffset type.
Summary
In this chapter, you quite thoroughly learned how to do calculations with dates.
You started by getting a date from the user using the Convert.ToDateTime method and followed with getting a date from the specified year, month, and day using DateTime’s constructor call (new DateTime…).
In your calculations, you made appropriate use of various properties of DateTime objects, such as Day, Month, or Year, as well as its methods, such as AddDays, for example. Also, to calculate a quarter’s number, you used integer division to your advantage.
Further, you got acquainted with how to calculate the difference between any two given dates and what to do with the result. Specifically, you used the TimeSpan object.
Finally, we discussed UTC and time zones to facilitate programs operating across multiple zones and to handle leaps of time due to daylight saving correctly. Specifically, you learned about the DateTimeOffset object.