{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Working with Dates, Times, and Time Zones\n", "\n", "We've worked with numbers and now text but we haven't worked with dates yet. This is a really important set of data types for folks that are working in accounting, or finance and other industries that need to be able to track when various business events occur. Let's talk about all the different types of date data types and how to work with them in C#\n", "\n", "## In the beginning... there was DateTime\n", "The original date data type that was available for net is the `DateTime` data type. This data type allows you to store both a date and a time and interact with those values in the date and time. There's a minimum value and a maximum value property that you can work with and all kinds of formatting capabilities of a date time variable. We create a new `DateTime` variable by using the `new` keyword and specifying the year month, day, year, and optionally the time information including hour (in 24 hour format), minute, and second.\n", "\n", "Let's take a look at some samples where we're going to schedule our next game night." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var gameNight = new DateTime(2024, 5, 1, 19, 0, 0);\n", "display(gameNight);\n", "\n", "display(gameNight.Hour);\n", "display(gameNight.Minute);\n", "display(gameNight.Second);\n", "\n", "var dateOfNextGame = new DateTime(2024, 5, 8);\n", "display(dateOfNextGame);\n", "\n", "var firstDate = DateTime.MinValue;\n", "display(firstDate);\n", "\n", "var lastDate = DateTime.MaxValue;\n", "display(lastDate);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the display of the date is returned in a standard format of year-2 digit month-2 digit day and 24 hour-based time with a Z at the end. Additionally the `dateOfNextGame` is returned with a time of midnight on the 8th of May because no time was specified. The `firstDate` value points to midnight on January 1st of the year 1 on the Gregorian Calendar that most of the world uses. There are [other calendars available](https://learn.microsoft.com/en-us/dotnet/standard/datetime/working-with-calendars) for use in C#, and you can specify which calendar to use as an optional argument when creating a `DateTime`\n", "\n", "This type of structure is pretty good when working with dates and times in a single time zone or you need to do some date and time arithmetic but don't need to be concerned about things like daylight savings time.\n", "\n", "Many people don't carry around date and time values in this very discrete format that we created a `DateTime` value with, but rather something more humanly readable like `May 1, 2024 7:00pm` In C#, we can `Parse` those values to create a `DateTime` that we can then work with.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var myTime = DateTime.Parse(\"May 1, 2024 7:00 PM\");\n", "display(myTime);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "C# will do its best to parse the value passed in, and you can also specify the exact format of the string value using the `ParseExact` method as well:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var exactTime = DateTime.ParseExact(\"5/1/2024 7:00 PM\", \"M/d/yyyy h:mm tt\", null);\n", "display(exactTime);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Documentation for the custom format specified in this sample can be found on [Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).\n", "\n", "### DateOnly and TimeOnly\n", "However, many folks work with just a date or just a time. We can now work with just these parts that describe dates and times using the `DateOnly` and `TimeOnly` variable types.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var gameDay = new DateOnly(2024, 5, 1);\n", "display(gameDay);\n", "\n", "var startTime = new TimeOnly(19, 0, 0);\n", "display(startTime);\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Time zones, Daylight Savings Time and DateTimeOffset\n", "For more complex operations that need to include and handle information across time zones and daylight savings time, its recommended that you use the `DateTimeOffset` date type. This type includes time zone information and can properly handle the transition of date information across daylight savings regulations. This type is significantly more accurate for specifying an exact point in time and reflecting that in different time zones.\n", "\n", "The easiest way to work with `DateTimeOffset` is to create one from a `DateTime` and specify the time zone information or the type of `DateTime` that was intended using a `DateTimeKind` value. The `DateTimeKind` allows you to specify if the `DateTime` is in UTC time, Local time to a specific time zone, or doesn't reference a specific time zone.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "// let's specify that our gameNight is a local time\n", "DateTime.SpecifyKind(gameNight, DateTimeKind.Local);\n", "var gameNightOffset = new DateTimeOffset(gameNight);\n", "display(gameNight);\n", "display(gameNightOffset);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can see that the `gameNight` value points to 7pm as we originally specified, and in my local time zone (EST which is 4 hours behind UTC), the `gameNightOffset` is 23:00 UTC. We can also force the creation of a `DateTimeOffset` with a specific time zone offset by passing in a `TimeSpan` value that specifies the number of hours of the offset:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "DateTime.SpecifyKind(gameNight, DateTimeKind.Local);\n", "\n", "// -5 for Central Daylight Time, used in Chicago, St. Louis, and Austin, Texas\n", "var gameNightOffset = new DateTimeOffset(gameNight, TimeSpan.FromHours(-5)); \n", "\n", "display(gameNight);\n", "display(gameNightOffset);\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now everyone will see that the `gameNightOffset` is stored with the value of May 2nd at midnight UTC. We can convert that back to local time or any other time zone using the `TimeZoneInfo` object. For example, if I wanted to convert this to Eastern European Time for my friends in Sofia, Bulgaria to know when my game night is planned, I can reference the **FLE Standard Time** timezone on Windows like this:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var easternEuropeanTimeZone = TimeZoneInfo.FindSystemTimeZoneById(\"FLE Standard Time\");\n", "var eetGameNight = TimeZoneInfo.ConvertTime(gameNightOffset, easternEuropeanTimeZone);\n", "display(eetGameNight);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Your system's time zone names might be different, and you can see a list of the time zones available with this command:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "\n", "display(TimeZoneInfo.GetSystemTimeZones());\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## TimeSpans - Referencing a Duration of Time\n", "We saw above the use of the time span object to create a block of five hours. A `TimeSpan` in C# allows you to define or reference a duration of time. We can use a `TimeSpan` to reference the time of day as a duration from midnight to that specific time of day and we can also use time spans to help with arithmetic around dates and times.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var timeOurGameStarts = gameNight.TimeOfDay;\n", "display(timeOurGameStarts);\n", "\n", "var gameDuration = new TimeSpan(2, 0, 0); // 2 hours for our game night\n", "display(gameDuration);\n", "\n", "var timeToNextGameNight = new TimeSpan(14, 0, 0, 0); // 14 days until our next game night\n", "display(timeToNextGameNight);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "You can use this syntax to define a `TimeSpan` from days, hours, minutes, and seconds. You can also use some shortcut methods to create a `TimeSpan` for a duration:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "\n", "var fiveDays = TimeSpan.FromDays(5);\n", "var threeHours = TimeSpan.FromHours(3);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Arithmetic and Dates\n", "Importantly, there are times when developers want to perform calculations between two dates, determine the end time for a duration, and other operations. The `DateTime` and `DateTimeOffset` objects provide the ability to `Add` and `Subtract` durations and date values.\n", "\n", "Notice in the following sample that we also use the value `DateTime.Now` to reference the current time in the computer's current timezone. We can also use the value `DateTime.UtcNow` to reference the current time in the UTC time zone" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "var gameEndingTime = gameNight.Add(TimeSpan.FromHours(3));\n", "display(gameEndingTime);\n", "\n", "var timeToGameNight = gameNight.Subtract(DateTime.Now);\n", "display(timeToGameNight);" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (C#)", "language": "C#", "name": ".net-csharp" }, "language_info": { "name": "polyglot-notebook" }, "polyglot_notebook": { "kernelInfo": { "defaultKernelName": "csharp", "items": [ { "aliases": [], "languageName": "csharp", "name": "csharp" } ] } } }, "nbformat": 4, "nbformat_minor": 2 }