Reputation: 24450
I need to check whether a certain time zone is still within a specified date. Something like DateTime.Today == DateTime.Parse("2016-06-30")
but for certain time zone. What is the best way to do it?
Upvotes: 8
Views: 7998
Reputation: 105
I dealt with this struggle recently, needed StartOfDay but for specific timezones. Not easy if the DateTimes don't carry around any timezone info outside of UTC or being "local" (server time, which can vary). Since server timezones can vary, it's always best to work in UTC. But this is how I was able to create and use such extensions for specific timezones!
Here is a dotnet fiddle to play with, with a backup below! https://dotnetfiddle.net/d9WhZV
using System;
using System.Threading;
using System.Globalization;
public class Program
{
private static readonly CultureInfo usaCulture = CultureInfo.GetCultureInfo("en-US");
public static void Main()
{
var utc = DateTime.UtcNow;
var targetTimeZone = TimeZones.EST;
Console.WriteLine("{0,-50} {1,25}", TimeZones.UTC, utc.ToUTC());
Console.WriteLine("{0,-50} {1,25}", TimeZones.EST, utc.ToEST());
Console.WriteLine("{0,-50} {1,25}", TimeZones.CST, utc.ToCST());
Console.WriteLine("{0,-50} {1,25}", TimeZones.MDT, utc.ToMDT());
Console.WriteLine("{0,-50} {1,25}", TimeZones.PST, utc.ToPST());
Console.WriteLine();
Console.WriteLine("DateTime Extension Tests On UTC DateTime For Target TimeZone -> {0}:", targetTimeZone);
Console.WriteLine("SOD {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfDay(targetTimeZone));
Console.WriteLine("EOD {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfDay(targetTimeZone));
Console.WriteLine("SOM {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfMonth(targetTimeZone));
Console.WriteLine("EOM {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfMonth(targetTimeZone));
Console.WriteLine("SOW {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfWeek(targetTimeZone));
Console.WriteLine("EOW {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfWeek(targetTimeZone));
Console.WriteLine("SOP-D {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfPeriod(Period.Day, targetTimeZone));
Console.WriteLine("EOP-D {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfPeriod(Period.Day, targetTimeZone));
Console.WriteLine("SOP-W {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfPeriod(Period.Week, targetTimeZone));
Console.WriteLine("EOP-W {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfPeriod(Period.Week, targetTimeZone));
Console.WriteLine("SOP-M {0}: {1:o}", targetTimeZone.DisplayName, utc.ToStartOfPeriod(Period.Month, targetTimeZone));
Console.WriteLine("EOP-M {0}: {1:o}", targetTimeZone.DisplayName, utc.ToEndOfPeriod(Period.Month, targetTimeZone));
}
}
public static class TimeZones
{
public static readonly TimeZoneInfo UTC = TimeZoneInfo.Utc;
public static DateTime ToUTC(this DateTime dateTime) => dateTime.ToTimeZone(UTC);
public static readonly TimeZoneInfo EST = GetTimeZoneCrossPlatform("Eastern Standard Time", "US/Eastern");
public static DateTime ToEST(this DateTime dateTime) => dateTime.ToTimeZone(EST);
public static readonly TimeZoneInfo CST = GetTimeZoneCrossPlatform("Central Standard Time", "US/Indiana-Starke");
public static DateTime ToCST(this DateTime dateTime) => dateTime.ToTimeZone(CST);
public static readonly TimeZoneInfo MDT = GetTimeZoneCrossPlatform("Mountain Standard Time", "US/Mountain");
public static DateTime ToMDT(this DateTime dateTime) => dateTime.ToTimeZone(MDT);
public static readonly TimeZoneInfo PST = GetTimeZoneCrossPlatform("Pacific Standard Time", "US/Pacific");
public static DateTime ToPST(this DateTime dateTime) => dateTime.ToTimeZone(PST);
public static TimeZoneInfo GetTimeZoneCrossPlatform(string windowsTimeZoneId, string unixTimeZoneId)
{
if (string.IsNullOrEmpty(windowsTimeZoneId))
{
throw new ArgumentException($"'{nameof(windowsTimeZoneId)}' cannot be null or empty.", nameof(windowsTimeZoneId));
}
if (string.IsNullOrEmpty(unixTimeZoneId))
{
throw new ArgumentException($"'{nameof(unixTimeZoneId)}' cannot be null or empty.", nameof(unixTimeZoneId));
}
try
{
return TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId);
}
catch (Exception)
{
// https://github.com/dotnet/runtime/issues/20523
return TimeZoneInfo.FindSystemTimeZoneById(unixTimeZoneId);
}
}
}
public static class DateTimeExtensions
{
public static DateTime ToTimeZone(this DateTime dateTime, TimeZoneInfo timeZone)
{
return TimeZoneInfo.ConvertTime(dateTime, timeZone);
}
public static DateTime ToStartOfDay(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzStartOfDay = tzDateTime.Date;
var utcResult = new DateTimeOffset(tzStartOfDay, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime;
return utcResult;
}
public static DateTime ToEndOfDay(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzEndOfDay = new DateTime(tzDateTime.Year, tzDateTime.Month, tzDateTime.Day, 23, 59, 59, 999, tzDateTime.Kind);
var utcResult = new DateTimeOffset(tzEndOfDay, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime;
return utcResult;
}
public static DateTime ToStartOfWeek(this DateTime dateTime, TimeZoneInfo timeZone) => ToStartOfWeek(dateTime, timeZone, Thread.CurrentThread.CurrentCulture);
public static DateTime ToStartOfWeek(this DateTime dateTime, TimeZoneInfo timeZone, CultureInfo culture)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzStartOfWeek = tzDateTime.AddDays(-(int)tzDateTime.DayOfWeek + (int)culture.DateTimeFormat.FirstDayOfWeek);
var utcResult = new DateTimeOffset(tzStartOfWeek, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToStartOfDay(timeZone);
return utcResult;
}
public static DateTime ToEndOfWeek(this DateTime dateTime, TimeZoneInfo timeZone) => ToEndOfWeek(dateTime, timeZone, Thread.CurrentThread.CurrentCulture);
public static DateTime ToEndOfWeek(this DateTime dateTime, TimeZoneInfo timeZone, CultureInfo culture)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzEndOfWeek = tzDateTime.AddDays(-(int)tzDateTime.DayOfWeek + (int)culture.DateTimeFormat.FirstDayOfWeek).AddDays(6);
var utcResult = new DateTimeOffset(tzEndOfWeek, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToEndOfDay(timeZone);
return utcResult;
}
public static DateTime ToStartOfMonth(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzStartOfMonth = new DateTime(tzDateTime.Year, tzDateTime.Month, 1, tzDateTime.Hour, tzDateTime.Minute, tzDateTime.Second, tzDateTime.Millisecond, tzDateTime.Kind);
var utcResult = new DateTimeOffset(tzStartOfMonth, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToStartOfDay(timeZone);
return utcResult;
}
public static DateTime ToEndOfMonth(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzEndOfMonth = new DateTime(tzDateTime.Year, tzDateTime.Month, DateTime.DaysInMonth(tzDateTime.Year, tzDateTime.Month), tzDateTime.Hour, tzDateTime.Minute, tzDateTime.Second, tzDateTime.Millisecond, tzDateTime.Kind);
var utcResult = new DateTimeOffset(tzEndOfMonth, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToEndOfDay(timeZone);
return utcResult;
}
public static DateTime ToStartOfYear(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzStartOfYear = new DateTime(tzDateTime.Year, 1, 1, tzDateTime.Hour, tzDateTime.Minute, tzDateTime.Second, tzDateTime.Millisecond, tzDateTime.Kind);
var utcResult = new DateTimeOffset(tzStartOfYear, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToStartOfDay(timeZone);
return utcResult;
}
public static DateTime ToEndOfYear(this DateTime dateTime, TimeZoneInfo timeZone)
{
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzEndOfYear = new DateTime(tzDateTime.Year, 12, DateTime.DaysInMonth(tzDateTime.Year, 12), tzDateTime.Hour, tzDateTime.Minute, tzDateTime.Second, tzDateTime.Millisecond, tzDateTime.Kind);
var utcResult = new DateTimeOffset(tzEndOfYear, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToEndOfDay(timeZone);
return utcResult;
}
}
public static class DateTimePeriodExtensions
{
public static DateTime ToStartOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, bool accountingStyle = false) => ToStartOfPeriod(dateTime, period, timeZone, Thread.CurrentThread.CurrentCulture, accountingStyle);
public static DateTime ToStartOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, CultureInfo culture, bool accountingStyle = false)
{
switch (period)
{
case Period.Day:
return dateTime.ToStartOfDay(timeZone);
case Period.Week:
var shifted = dateTime.ToStartOfWeek(timeZone, culture);
if (shifted.Month < dateTime.Month && accountingStyle)
{
return dateTime.ToStartOfMonth(timeZone);
}
return shifted.ToStartOfDay(timeZone);
case Period.Month:
return dateTime.ToStartOfMonth(timeZone);
case Period.Year:
return dateTime.ToStartOfYear(timeZone);
default:
throw new ArgumentOutOfRangeException(nameof(period), $"Unexpected Period '{period}'.");
}
}
public static DateTime ToEndOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, bool accountingStyle = false) => ToEndOfPeriod(dateTime, period, timeZone, Thread.CurrentThread.CurrentCulture, accountingStyle);
public static DateTime ToEndOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, CultureInfo culture, bool accountingStyle = false)
{
switch (period)
{
case Period.Day:
return dateTime.ToEndOfDay(timeZone);
case Period.Week:
var shifted = dateTime.ToEndOfWeek(timeZone, culture);
if (shifted.Month > dateTime.Month && accountingStyle)
{
return dateTime.ToEndOfMonth(timeZone);
}
return shifted.ToEndOfDay(timeZone);
case Period.Month:
return dateTime.ToEndOfMonth(timeZone);
case Period.Year:
return dateTime.ToEndOfYear(timeZone);
default:
throw new ArgumentOutOfRangeException(nameof(period), $"Unexpected Period '{period}'.");
}
}
public static DateTime ToStartOfNextPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, bool accountingStyle = false) => ToStartOfNextPeriod(dateTime, period, timeZone, Thread.CurrentThread.CurrentCulture, accountingStyle);
public static DateTime ToStartOfNextPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone, CultureInfo culture, bool accountingStyle = false)
{
return dateTime.ToEndOfPeriod(period, timeZone, culture, accountingStyle).AddDays(1).ToStartOfDay(timeZone);
}
}
public enum Period
{
Day,
Week,
Month,
Year
}
Upvotes: 0
Reputation: 3328
I would check out the TimeZoneInfo
class.
Method for converting the to a specific timezone is:
public static DateTime ConvertTime(
DateTime dateTime,
TimeZoneInfo sourceTimeZone,
TimeZoneInfo destinationTimeZone
)
There are other methods for dealing with things like UTC as well. Check out the documentation here.
Upvotes: 1
Reputation: 2302
You need to get UTC Time
, find TimeZoneInfo
, and convert UTC time
to your TimeZoneInfo
.
DateTime utcTime = DateTime.UtcNow;
TimeZoneInfo serverZone = TimeZoneInfo.FindSystemTimeZoneById(YourTimeZoneID);
DateTime currentDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, serverZone);
Upvotes: 7