using System.Globalization;
private static readonly CultureInfo usaCulture = CultureInfo.GetCultureInfo("en-US");
public static void Main()
var utc = DateTime.UtcNow;
var targetTimeZone = TimeZones.EST;
var utcOffset = targetTimeZone.GetUtcOffset(utc);
Console.WriteLine($"UTC offset for '{targetTimeZone}' is {utcOffset}");
Console.WriteLine("{0, -50} {1, 25:o}", TimeZones.UTC, utc);
Console.WriteLine("{0, -50} {1, 25:o} (note no 'Z')", targetTimeZone, TimeZoneInfo.ConvertTimeFromUtc(utc, targetTimeZone));
Console.WriteLine("SOD {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfDay(targetTimeZone));
Console.WriteLine("EOD {0, -50} {1, 25:o}", targetTimeZone, utc.ToEndOfDay(targetTimeZone));
Console.WriteLine("SOM {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfMonth(targetTimeZone));
Console.WriteLine("EOM {0, -50} {1, 25:o}", targetTimeZone, utc.ToEndOfMonth(targetTimeZone));
Console.WriteLine("SOW {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfWeek(targetTimeZone));
Console.WriteLine("EOW {0, -50} {1, 25:o}", targetTimeZone, utc.ToEndOfWeek(targetTimeZone));
Console.WriteLine("SOP-D {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfPeriod(Period.Day, targetTimeZone));
Console.WriteLine("EOP-D {0, -50} {1, 25:o}", targetTimeZone, utc.ToEndOfPeriod(Period.Day, targetTimeZone));
Console.WriteLine("SOP-W {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfPeriod(Period.Week, targetTimeZone));
Console.WriteLine("EOP-W {0, -50} {1, 25:o}", targetTimeZone, utc.ToEndOfPeriod(Period.Week, targetTimeZone));
Console.WriteLine("SOP-M {0, -50} {1, 25:o}", targetTimeZone, utc.ToStartOfPeriod(Period.Month, targetTimeZone));
Console.WriteLine("EOP-M {0, -50} {1, 25:o}", targetTimeZone, 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));
return TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId);
return TimeZoneInfo.FindSystemTimeZoneById(unixTimeZoneId);
public static DateTime NewDateTime(this TimeZoneInfo timeZone, int year, int month, int day)
var tzDateTime = new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Unspecified);
var utcResult = new DateTimeOffset(tzDateTime, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime;
public static DateTime NewDateTime(this TimeZoneInfo timeZone, int year, int month, int day, int hour, int minute, int second)
var tzDateTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified);
var utcResult = new DateTimeOffset(tzDateTime, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime;
public static DateTime NewDateTime(this TimeZoneInfo timeZone, int year, int month, int day, int hour, int minute, int second, int millisecond)
var tzDateTime = new DateTime(year, month, day, hour, minute, second, millisecond, DateTimeKind.Unspecified);
var utcResult = new DateTimeOffset(tzDateTime, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime;
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;
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;
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);
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);
public static DateTime ToStartOfWeek(this DateTime dateTime, TimeZoneInfo timeZone)
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzStartOfWeek = tzDateTime.AddDays(-(int)tzDateTime.DayOfWeek + (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek);
var utcResult = new DateTimeOffset(tzStartOfWeek, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToStartOfDay(timeZone);
public static DateTime ToEndOfWeek(this DateTime dateTime, TimeZoneInfo timeZone)
var tzDateTime = dateTime.ToTimeZone(timeZone);
var tzEndOfWeek = tzDateTime.AddDays(-(int)tzDateTime.DayOfWeek + (int)System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek).AddDays(6);
var utcResult = new DateTimeOffset(tzEndOfWeek, timeZone.GetUtcOffset(tzDateTime)).UtcDateTime.ToEndOfDay(timeZone);
public static DateTime ToStartOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone)
return dateTime.ToStartOfDay(timeZone);
var shifted = dateTime.ToStartOfWeek(timeZone);
if (shifted.Month < dateTime.Month)
return dateTime.ToStartOfMonth(timeZone);
return shifted.ToStartOfDay(timeZone);
return dateTime.ToStartOfMonth(timeZone);
throw new ArgumentOutOfRangeException(nameof(period), $"Unexpected Period '{period}'.");
public static DateTime ToEndOfPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone)
return dateTime.ToEndOfDay(timeZone);
var shifted = dateTime.ToEndOfWeek(timeZone);
if (shifted.Month > dateTime.Month)
return dateTime.ToEndOfMonth(timeZone);
return shifted.ToEndOfDay(timeZone);
return dateTime.ToEndOfMonth(timeZone);
throw new ArgumentOutOfRangeException(nameof(period), $"Unexpected Period '{period}'.");
public static DateTime ToBeginningOfNextPeriod(this DateTime dateTime, Period period, TimeZoneInfo timeZone)
return dateTime.ToEndOfPeriod(period, timeZone).AddDays(1).ToStartOfDay(timeZone);