All About Dates
2021-04-24
Note
Slides can be downloaded from here
LINQPad queries can be downloaded from here
Agenda
-
Date Components
-
Common Date Operations (C#)
-
Best Practice
-
Wrap up
1. Date Components
What day is it today?
What time is it now?
Which timezone are we using?
What is the current time zone offset?
1. Date Components
What day is it today?
2021.04.23
What time is it now?
3:15 pm
Which timezone are we using?
AEST
What is the current time zone offset?
+10:00
Depending on your current location, the answer may vary.
Your laptop probably is using your local time zone.
1.1 Date Terminologies
2021.04.16 - Date
2021-04-16 15:15:00 - DateTime
3:15 pm - Time
00:00:00 - Midnight
AEST - Time Zone
+10:00 - Offset
GMT, UTC, Universal Time - Offset = 00:00
3 hours 20 minutes - Elapsed Time (Duration, can be more than 24 hours)
Standards
ISO-8601 standard is commonly used nowadays.
1970.01.01 is the date of the Unix Epoch, anything from 1970 onward is much more reliable.
ISO-8601 standard Simple Format (YYYY-MM-DD) is recommended for Date Format (Avoid Ambiguity)
How Date and Time is stored in Computers
-
usually integer
12:45:53 =>
(12*3600)+(45*60)+53=45953
-
precision can differ in languages
- second
- millisecond (JS) -> 1 second = 1,000 milliseconds
- microsecond -> 1 second = 1,000,000 microseconds
- tick (.NET) -> 1 second = 10,000,000 ticks
- nanosecond -> 1 tick = 100ns = 1/100,000,000 second
1.2 Time Zone & Offset
Time Zone != Offset
1 Time Zone can have different offsets.
- Daylight Saving Time (DST) has its role to play
1 offset can have multiple time zones
-
+10:00 is shared by more than 1 time zone.
Essentially, Time Zone and Offset has a Many-to-Many Relationship.
Note: Time Zone names are not standardized, IANA time zone database ) might be the most commonly used one (not supported in native .NET).
1.3 Daylight Saving Time
- DST is not always +/-1 hour
- DST doesn’t happen at the same time every year
- DST can happen more than once a year…
- DST is VERY UNPREDICTABLE!
- So don’t try to remember/hard code any DST in your application!
Spring Forward Transition
- usually 1 hour forward, the transition day miss 1 hour (total 23 hours)
- e.g., transition happens at 2021.10.03 2am, we will experience 1:59:59 + 1 tick = 3:00:00.
Fall Back Transition
- usually 1 hour backward, the transition day repeat 1 hour (total 25 hours)
- e.g., transition happens at 2021.04.04 3am, we will experience 2:59:59 + 1 tick = 2:00:00
1.4 Midnight is not reliable
We tend to use Date + Midnight time (00:00:00) to represent a Local DateTime, but midnight is not always available in every time zone on every day.
Hint: DST transition time
Solution 1: Consider the scope (Date only? Date and Time? Duration?)
Solution 2: UTC midnight is always available
1.5 Whose Time Should We Use?
We need to consider this whenever we read, save, convert, calculate and compare date in our application.
User Time
- Globalization means your users can live in any time zone in the world.
- Users only understand their local time zone.
Server Time
- Your local server is probably using your local time (during development & debugging)
- Your cloud server should be using UTC time but sometimes people might change it accidentally
Solution
- Use local time for display purposes
- Use UTC time for date comparison, calculation, timestamp
- Always be explicit about timezone and offset info (Avoid assumptions)
There’s nothing worse than a computer making assumptions on behalf of you.
Especially for Dates…
Speicial considerations
- Leap Year (366 days)
- February Date (29 in leap years)
- Financial Year (not always 01-01)
- ….
2. Common Date Operations (C#)
2.1 Date Related Types in C#
Structs in System
namespace
- DateTime (Date + Time)
- DateTimeOffset (Date + Time + Offset)
- TimeSpan (represent time interval or a time of the day)
Related Classes
- System.TimeZoneInfo
- System.Globalization.Calendar
- System.Diagnostics.Stopwatch
Nonexistent Types
- Date Only (we can ignore time portion in the DateTime object)
- Time Only
- use DateTime object and ignore date, or
- use TimeSpan object (not recommended, need to handle >24 hours and negative cases)
2.2 Which Now are you talking about?
Local Now
DateTime dtnow = DateTime.Now; // 2021-04-17 13:53:49
DateTimeOffset dto = DateTimeOffset.Now; // 2021-04-17 13:53:49 +10:00
Utc Now
DateTime dtUTCnow = DateTime.UtcNow; // 2021-04-17 03:54:22
DateTimeOffset dtoUTC = DateTimeOffset.UtcNow; // 2021-04-17 03:54:22 +00:00
Note: Printed DateTime format changes based on your system settings.
2.2 Which Now are you talking about?
Local Now
DateTime dtnow = DateTime.Now; // 2021-04-17 13:53:49
DateTimeOffset dto = DateTimeOffset.Now; // 2021-04-17 13:53:49 +10:00
Utc Now
DateTime dtUTCnow = DateTime.UtcNow; // 2021-04-17 03:54:22
DateTimeOffset dtoUTC = DateTimeOffset.UtcNow; // 2021-04-17 03:54:22 +00:00
Is this a Local now or a Utc Now?
2021-04-18 03:54:22
Note: DateTimeOffset always have the converted time
E.g., 2021-04-17 13:53:49 +10:00 means local time is 2021-04-17 13:53:49, UTC time needs be calculated by substracting the timezoneoffset.
2.3 Date Creation
DateTime (has Kind)
DateTime dtDefault = new DateTime(2000, 2, 3, 10, 20, 30).Dump(); // Unspecified
DateTime dtLocal = new DateTime(2000, 2, 3, 10, 20, 30, DateTimeKind.Local).Dump(); // Local
DateTime dtUtc = new DateTime(2000, 2, 3, 10, 20, 30, DateTimeKind.Utc).Dump(); // Utc
DateTimeOffset
TimeSpan ts = TimeSpan.FromMinutes(90).Dump(); // offset +01:30
DateTimeOffset dto = new DateTimeOffset(2000, 2, 3, 10, 20, 30, ts).Dump();
Question:
- Does DateTimeOffset have Kind?
- Why or why not?
DateTimeKind
- Unspecified (default for date creation)
- Local (DateTime.Now)
- Utc (DateTime.UtcNow)
Update Kind
DateTime dtDefault = new DateTime(2000, 2, 3, 10, 20, 30).Dump(); // Unspecified
dtDefault = DateTime.SpecifyKind(dtDefault, DateTimeKind.Utc);
dtDefault.Kind.Dump(); // Utc
Get DateTime from DateTimeOffset with Kind
DateTimeOffset dtoUTC = DateTimeOffset.UtcNow.Dump();
dtoUTC.UtcDateTime.Kind.Dump(); // Utc
dtoUTC.DateTime.Kind.Dump(); // Unspecified (AVOID using this for UTC time)
Question
Given a DateTime object without knowing its created timezone, you want to convert it to a DateTimeOffset object with timezone = Utc, what would you do?
DateTime timezoneUnknown = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
// Todo: Create a DateTimeOffset object with timezoneoffset = 0
Question
Given a DateTime object without knowing its created timezone, you want to convert it to a DateTimeOffset object with timezone = Utc, what would you do?
// Convert DateTime to DateTimeOffset with timezone = utc
// orginal date: 2000-02-03 10:20:30
DateTime timezoneUnknown = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
// 1. set Kind to utc
timezoneUnknown = DateTime.SpecifyKind(timezoneUnknown, DateTimeKind.Utc);
// 2. cast it to a DateTimeOffset object
DateTimeOffset dtoUtcTime = (DateTimeOffset)timezoneUnknown;
dtoUtcTime.Dump(); // 2000-02-03 10:20:30 +00:00
Another way of doing this is to use a method ToUniversalTime()
, but we still need to consider the kind.
DateTime timezoneUnknown2 = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
timezoneUnknown2.ToUniversalTime().Dump(); // 2000-02-02 23:20:30
timezoneUnknown2 = DateTime.SpecifyKind(timezoneUnknown2, DateTimeKind.Utc);
timezoneUnknown2.ToUniversalTime().Dump(); // 2000-02-03 10:20:30
DateTimeOffset dtoUtcTime2 = (DateTimeOffset)timezoneUnknown2;
dtoUtcTime2.Dump(); // 2000-02-03 10:20:30 +00:00
Question
Given a DateTime object, you know its created timezone is UTC+8, you want to convert it to a DateTimeOffset object with its correct timezone, what would you do?
DateTime timezoneUnknown = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
// Todo: Create a DateTimeOffset object with timezoneoffset = 8
Question
Given a DateTime object, you know its created timezone is UTC+8, you want to convert it to a DateTimeOffset object with its correct timezone, what would you do?
DateTime timezoneAny = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
try
{
DateTimeOffset dtoAny = new DateTimeOffset(timezoneAny,
TimeZoneInfo.FindSystemTimeZoneById("China Standard Time").GetUtcOffset(timezoneAny));
dtoAny.Dump();
}
// Handle exception if time zone is not defined in registry
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to identify target time zone for conversion.");
}
Question
Given a DateTime object, you know its created timezone is UTC+8, you want to convert it to a DateTimeOffset object with its correct timezone, what would you do?
DateTime timezoneAny = new DateTime(2000, 2, 3, 10, 20, 30).Dump();
try
{
DateTimeOffset dtoAny = new DateTimeOffset(timezoneAny,
TimeZoneInfo.FindSystemTimeZoneById("China Standard Time").GetUtcOffset(timezoneAny));
dtoAny.Dump();
}
// Handle exception if time zone is not defined in registry
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to identify target time zone for conversion.");
}
But….Is this really correct?
TimeZone and TimeZoneOffset
Recall: There’s a many-to-many relationship between them.
- When we say UTC+8, does it refer to TimeZone or TimeZoneOffset?
- When we do the conversion, are we searching for TimeZone or TimeZoneOffset?
- What if that day in the TimeZone we used is a DST day and the offset is not +8?
What we’ve learnt
- There’s a risk that your conversion somehow went wrong and you’ve messed up with the offset.
- So always try to create dates with an explicit timezoneoffset.
- Avoid ambiguity is the key to avoid mistakes.
2.4 TimeZone Conversion
Common Scenarios:
- Convert a DateTime to a DateTimeOffset (mentioned above);
- Convert a DateTimeOffset to a DateTime;
Convert a DateTimeOffset to a DateTime
Solution 1: Directly get DateTime from DateTimeOffset
DateTimeOffset dtoLocal = DateTimeOffset.Now.Dump("Local DateTimeOffset");
DateTime convertedDateTime = dtoLocal.DateTime.Dump("Local DateTime");
convertedDateTime.Kind.Dump("Kind"); // Unspecified
DateTimeOffset dtoUtc = DateTimeOffset.UtcNow.Dump("Utc DateTimeOffset");
DateTime convertedDateTime2 = dtoUtc.DateTime.Dump("Utc DateTime");
convertedDateTime2.Kind.Dump("Kind"); // Unspecified
DateTime timezoneAny = new DateTime(2000, 2, 3, 10, 20, 30).Dump("Any TimeZone DateTime");
DateTimeOffset dtoAny = new DateTimeOffset(timezoneAny,
TimeZoneInfo.FindSystemTimeZoneById("China Standard Time").GetUtcOffset(timezoneAny)).Dump("Any TimeZone DateTimeOffset");
DateTime convertedDateTime3 = dtoAny.DateTime.Dump("Any TimeZone DateTime");
convertedDateTime3.Kind.Dump("Kind"); // Unspecified
Convert a DateTimeOffset to a DateTime
Solution 1: Directly get DateTime from DateTimeOffset
Problem:
We will lose the Kind information during conversion from DateTimeOffset to DateTime.
- Meaning if we want to use the conversion result to get the original DateTimeOffset, it will be difficult.
Convert a DateTimeOffset to a DateTime
Solution 2: Convert to UtcDateTime and then get Local DateTime
// Convert to UtcDateTime first
DateTimeOffset dtoLocal2 = DateTimeOffset.Now.Dump("Local DateTimeOffset");
DateTime convertedDateTimeUtc = dtoLocal2.ToUniversalTime().UtcDateTime.Dump("Utc DateTime");
convertedDateTimeUtc.Kind.Dump("Kind"); // Utc
// Local DateTime, don't forget to change kind!!!
DateTime convertedDateTimeLocal = convertedDateTimeUtc.AddHours(8).Dump();
convertedDateTimeLocal.Kind.Dump("Kind"); // Utc
convertedDateTimeLocal = DateTime.SpecifyKind(convertedDateTimeLocal, DateTimeKind.Local).Dump();
convertedDateTimeLocal.Kind.Dump("Kind"); // Local
// another way, convert to a different timezone
DateTime anyLocalDateTime = TimeZoneInfo.ConvertTime(convertedDateTimeUtc, TimeZoneInfo.FindSystemTimeZoneById("China Standard Time")).Dump("Another TimeZone DateTime");
anyLocalDateTime.Kind.Dump("Kind"); // Unspecified
anyLocalDateTime = DateTime.SpecifyKind(convertedDateTimeLocal, DateTimeKind.Local).Dump();
anyLocalDateTime.Kind.Dump("Kind"); // Local
Convert a DateTimeOffset to a DateTime
Solution 2: Convert to UtcDateTime and then get Local DateTime
This is a much better way of doing conversion because we get back a DateTime with Kind.
- If you need a certain TimeZoneOffset, you can do it by adding/substracting hours
Problem:
- You must change the Kind to be Local (and this may cause issue if your local timezoneoffset != the one you are adding)
What does local mean? Does it mean your current machine time or the timezoneoffset you are adding?
// Don't use these 2 methods
convertedDateTimeLocal.ToUniversalTime().Dump("To UTC (Local kind)");
convertedDateTimeLocal.ToLocalTime().Dump("To Local (Local kind)");
anyLocalDateTime.ToUniversalTime().Dump("To UTC (Local kind)");
anyLocalDateTime.ToLocalTime().Dump("To Local (Local kind)");
Convert a DateTimeOffset to a DateTime
Solution 3 (Perferred): get local DateTimeOffset object, then get local DateTime
-
We’ve found that since DateTime only have 3 Kinds and neither of them can be used to tell a specific timezone other than UTC.
-
To fix the previous solution, we can get a LocalDateTimeOffset object instead.
-
And its also recommended to use
DateTimeOffset.UtcNow
, notDateTimeOffset.Now
to avoid ambiguity. -
We should avoid using any DateTime object to represent a local time, we should always get it from DateTimeOffset.
-
And you should always use
TimeZoneInfo.ConvertTime
to convert timezone, don’t try to create a new DateTimeOffset by yourself!- Still remember TimeZone and TimeZoneOffset are not the same thing?
Convert a DateTimeOffset to a DateTime
Solution 3 (Perferred): get local DateTimeOffset object, then get local DateTime
// UtcDateTime first
DateTimeOffset dtoUtcNow = DateTimeOffset.UtcNow.Dump("Utc DateTimeOffset");
DateTime dtoUtcDateTime = dtoUtcNow.UtcDateTime.Dump("Utc DateTime");
dtoUtcDateTime.Kind.Dump("Kind"); // Utc
// convert to local DateTimeOffset
DateTimeOffset localDateTimeOffset = TimeZoneInfo.ConvertTime(dtoUtcNow, TimeZoneInfo.FindSystemTimeZoneById("China Standard Time")).Dump("Another TimeZone DateTime");
localDateTimeOffset.DateTime.Dump("The best way to get Local DateTime!!!");
ToUniversalTime and ToLocalTime
Kind plays an important role in the conversion.
DateTime timezoneUnknown = new DateTime(2000, 2, 3, 10, 20, 30).Dump("Original DateTime");
timezoneUnknown.ToUniversalTime().Dump("To UTC (Unspecified Kind)");
timezoneUnknown.ToLocalTime().Dump("To Local (Unspecified Kind)");
timezoneUnknown = DateTime.SpecifyKind(timezoneUnknown, DateTimeKind.Local);
timezoneUnknown.ToUniversalTime().Dump("To UTC (Local kind)");
timezoneUnknown.ToLocalTime().Dump("To Local (Local kind)");
timezoneUnknown = DateTime.SpecifyKind(timezoneUnknown, DateTimeKind.Utc);
timezoneUnknown.ToUniversalTime().Dump("To UTC (UTC kind)");
timezoneUnknown.ToLocalTime().Dump("To Local (UTC kind)");
ToUniversalTime and ToLocalTime
-
If kind = Unspecified (conversion could be wrong)
- ToUniversalTime will substract current timezoneoffset
- ToLocalTime will add current timezoneoffset (treating the original DateTime as UTC)
-
If kind = Local (conversion is correct)
- ToUniversalTime will substract current timezoneoffset
- ToLocalTime will remain the same
-
If kind = Utc (conversion is correct)
- ToUniversalTime will remain the same
- ToLocalTime will add current timezoneoffset
Best Practice
- Always have your kind set correctly before calling the conversion methods.
- Make sure your original Date correct is the first step.
- Avoid using DateTime as much as possible (unless the kind is UTC).
2.5 DateTime(Offset) & String Conversion
Common Scenarios:
- Format a DateTime object to a string in a specified format;
- Format a DateTimeOffset object to a string in a specified format;
- Parse a Date string and convert it to a DateTime object;
- Parse a Date string and convert it to a DateTimeOffset object;
Format (convert Date to string)
- To avoid the dependency of system date format, always use ToString and pass in the format you want;
s
ando
are shorthand formats that you can use;- UTC time is represented with a “Z” at the end in ISO8601 standard, not “+00:00”,
o
works for DateTime, not DateTimeOffset; - DateTime won’t have any timezone info (even with Kind = Local), but
o
format will add aZ
at the end of the string;
- ISO 8601 long dateformat is “yyyy-MM-ddTHH:mm:ssZ”
- o: complete info “yyyy-MM-ddTHH:mm:ss.fffffffK”
- s: strict ISO 8601 “yyyy-MM-ddTHH:mm:ss” Date Formatting Reference
DateTime format
// DateTime
DateTime dtnow = DateTime.Now.Dump();
DateTime dtUTCnow = DateTime.UtcNow.Dump();
dtnow.ToLongDateString().Dump("ToLongDateString");
dtnow.ToLongTimeString().Dump("ToLongTimeString");
dtnow.ToOADate().Dump("ToOADate");
dtnow.ToShortDateString().Dump("ToShortDateString");
dtnow.ToShortTimeString().Dump("ToShortTimeString");
dtnow.ToString().Dump("ToString Default");
dtnow.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture).Dump("ToString custom format");
dtnow.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture).Dump("ToString custom format"); // this can be wrong!!!! it's actually local time
dtnow.ToString("o").Dump("ToString o");
dtnow.ToString("s").Dump("ToString s");
//dtnow.GetDateTimeFormats().Dump("GetDateTimeFormats"); // all supported formats
dtUTCnow.ToString("o").Dump("UtcDateTime - o");
dtUTCnow.ToString("s").Dump("UtcDateTime - s");
DateTimeOffset format
// DateTimeOffset
DateTimeOffset dto = DateTimeOffset.Now.Dump();
DateTimeOffset dtoUTC = DateTimeOffset.UtcNow.Dump();
dto.ToString("o").Dump("DateTimeOffset - Local o");
dto.ToString("s").Dump("DateTimeOffset - Local s");
dto.ToString("yyyy-MM-ddTHH:mm:sszzz").Dump("DateTimeOffset - Local custom");
dtoUTC.ToString("o").Dump("DateTimeOffset - UTC o");
dtoUTC.ToString("s").Dump("DateTimeOffset - UTC s");
dtoUTC.ToString("yyyy-MM-ddTHH:mm:sszzz").Dump("DateTimeOffset - UTC custom");
dtoUTC.ToString("yyyy-MM-ddTHH:mm:ssZ").Dump("DateTimeOffset - UTC custom");
Date Formatting Best Practice - use “o” (character o, not number 0)
DateTime dtnow = DateTime.Now.Dump();
DateTime dtUTCnow = DateTime.UtcNow.Dump();
DateTimeOffset dto = DateTimeOffset.Now.Dump();
DateTimeOffset dtoUTC = DateTimeOffset.UtcNow.Dump();
// 2021-04-17T20:22:53.0631934+10:00
dtnow.ToString("o").Dump("DateTime Local - use o");
// 2021-04-17T10:22:53.0634756Z
dtUTCnow.ToString("o").Dump("DateTime UTC - use o");
// 2021-04-17T20:22:53.0641225+10:00
dto.ToString("o").Dump("DateTimeOffset Local - use o");
// 2021-04-17T10:22:53.0641638+00:00
dtoUTC.ToString("o").Dump("DateTimeOffset Utc - use o");
// 2021-04-17T10:22:53.0641638Z
dtoUTC.UtcDateTime.ToString("o").Dump("DateTimeOffset Utc - convert and use o");
Parsing (convert string to Date)
Both DateTime and DateTimeOffset parse have 4 variations:
- Parse
- TryParse
- ParseExact
- TryParseExact
Note: Each method also has multiple overloads, the chart is simplified.
Method | Error Handling | Format | Provider | DateTimeStyle |
---|---|---|---|---|
Parse | N | N | N | N |
ParseExact | N | Y | Optional | N |
TryParse | Y | N | N | N |
TryParseExact | Y | Y | Optional | Y |
Parsing
DateTimeOffset is similar, we’ll omit the example code for that..
// Local Now
DateTime dtnow = DateTime.Now.Dump("DateTime Local Now");
CultureInfo provider = CultureInfo.InvariantCulture;
string customStringToParse = "2021-01-01".Dump("Custom String - input");
DateTime customStringParseResult = DateTime.Parse(customStringToParse);
DateTime parseResultSuccess;
DateTime parseExactResultSuccess;
DateTime.ParseExact(customStringToParse, "yyyy-mm-dd", provider).Dump("DateTime ParseExact - valid DateTime string");
DateTime.TryParse(customStringToParse, out parseResultSuccess).Dump("DateTime TryParse - valid DateTime string");
DateTime.TryParseExact(customStringToParse, "yyyy-mm-dd", provider, DateTimeStyles.None, out parseExactResultSuccess).Dump("DateTime TryParseExact - valid DateTime string");
Click for more format information
Date comparison
Common Scenarios:
- Compare Dates
- Compare DateTime
- Compare DateTimeOffset
To compare, we need to first make sure d1 and d2 are in the same timezone, usually we convert them to UTC time.
Date Comparison - DateTime
The last one will produce a wrong result, cos we are not comparing 2 utc datetime.
DateTime utcNow = DateTime.UtcNow.Dump();
DateTime utcOneHourBefore = DateTime.UtcNow.AddHours(-1).Dump();
DateTime localOneHourBefore = DateTime.Now.AddHours(-1).Dump();
(utcOneHourBefore.ToUniversalTime() > utcNow).Dump("utcOneHourBefore > utcNow");
(utcOneHourBefore > utcNow).Dump("utcOneHourBefore > utcNow");
(localOneHourBefore.ToUniversalTime() > utcNow).Dump("localOneHourBefore > utcNow");
(localOneHourBefore > utcNow).Dump("localOneHourBefore > utcNow");
Date Comparison - DateTimeOffset
DateTimeOffset doesn’t have this problem, since it has the offset information.
DateTimeOffset utcNow = DateTimeOffset.UtcNow.Dump();
DateTimeOffset utcOneHourBefore = DateTimeOffset.UtcNow.AddHours(-1).Dump();
DateTimeOffset localOneHourBefore = DateTimeOffset.Now.AddHours(-1).Dump();
(utcOneHourBefore.ToUniversalTime() > utcNow).Dump("utcOneHourBefore > utcNow");
(utcOneHourBefore > utcNow).Dump("utcOneHourBefore > utcNow");
(localOneHourBefore.ToUniversalTime() > utcNow).Dump("localOneHourBefore > utcNow");
(localOneHourBefore > utcNow).Dump("localOneHourBefore > utcNow");
3. Best Practice
-
Understand the difference between timezone and timezoneoffset
-
Daylight Saving Time is complicated but you don’t need to remember or hardcode the rules
-
Avoid using local DateTime in your db and application internal logic, utc datetimeoffset is the best option
-
Do not compare dates in different timezone
-
Use “o” or “yyyy-MM-ddTHH:mm:sszzz” to format date string
-
Be careful when you are talking about today, next week, yesterday.. ask yourself, whose day is it?
A nice course to watch - Date and Time Fundamentals
4. Wrap up
-
Date Components
- terminologies
- standards
- storage and precision
- daylight saving time (DST)
- don’t trust local midnight time
- user time vs server time
-
Common Date Operations
- C# Date Related Types
- Different Now (Local & Utc)
- Create a Date properly
- DateTimeKind (the complicated part)
- TimeZone Conversion (not that easy)
- ToUniversalTime and ToLocalTime (better not use if Kind != Utc)
- DateTime and String Conversion
- Date Comparison
-
Best Practice