Creating a DateTime in a specific Time Zone in c#
Jon's answer talks about TimeZone, but I'd suggest using TimeZoneInfo instead.
Personally I like keeping things in UTC where possible (at least for the past; storing UTC for the future has potential issues), so I'd suggest a structure like this:
public struct DateTimeWithZone
{
private readonly DateTime utcDateTime;
private readonly TimeZoneInfo timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone);
this.timeZone = timeZone;
}
public DateTime UniversalTime { get { return utcDateTime; } }
public TimeZoneInfo TimeZone { get { return timeZone; } }
public DateTime LocalTime
{
get
{
return TimeZoneInfo.ConvertTime(utcDateTime, timeZone);
}
}
}
You may wish to change the "TimeZone" names to "TimeZoneInfo" to make things clearer - I prefer the briefer names myself.
How can I create a new instance of DateTime in specific time zone?
You can use TimeZoneInfo to retrieve your zone
You can find timezones here
var zn = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
to express that you are using a local eastern standard time use DateTimeOffset
struct instead of DateTime
DateTimeOffset dateTimeOffset = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), zn.BaseUtcOffset);
Why DateTimeOffset
DateTimeOffset is a representation of instantaneous time (also known as absolute time).
Set Datetime in C# based on Timezone like +08:00
You need DateTimeOffset.ToOffset(TimeSpan) to convert Utc to your desired timezone.
DateTime now = DateTime.UtcNow;
DateTimeOffset dtoUtc = new DateTimeOffset(now);
TimeSpan offset = new TimeSpan(+5, 00, 00); // Specify timezone
var dtToSpecificTimezone = dtoUtc.ToOffset(offset);
Console.WriteLine(dtToSpecificTimezone.ToString());
Output:
7/11/2021 3:02:10 PM +05:00
Sample program
Create DateTime in specific time zone then convert to utc
You'd basically need TimeZoneInfo.ConvertTimeToUtc method.
Just make sure the Kind
property of the passed DateTime
is Unspecified
, otherwise the method has special expectations for the sourceTimeZone
argument and will throw exception.
e.g.
var testTime = new DateTime(testDate.Year, testDate.Month, testDate.Day, 4, 0, 0);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("West Asia Standard Time");
var utcTime = TimeZoneInfo.ConvertTimeToUtc(testTime, timeZoneInfo);;
How to set a time zone (or a Kind) of a DateTime value?
While the DateTime.Kind property does not have a setter, the static method DateTime.SpecifyKind creates a DateTime instance with a specified value for Kind.
Altenatively there are several DateTime constructor overloads that take a DateTimeKind parameter
Converting a datetime to a particular timezone but in a specific format c#
use DateTimeOffset
to format the string in desired format
DateTime close_line_UTC = DateTime.SpecifyKind(Convert.ToDateTime("25-May-2021 18:36"), DateTimeKind.Utc);
var myTimeZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var closeline_local = TimeZoneInfo.ConvertTimeFromUtc(close_line_UTC, myTimeZone);
TimeSpan utcOffsett = myTimeZone.GetUtcOffset(closeline_local);
DateTimeOffset dateTimeOffset = new DateTimeOffset(closeline_local, utcOffsett);
var closeline_local_formatted = dateTimeOffset.ToString("yyyy-MM-dd'T'HH:mm:ss.fffffffzzz");
References
DateTime.ToString Method
DateTimeOffset.ToString Method
Specify a date in another timezone C#
Seems I was able to answer my own question. Here's the code I'm using to get a next-run DateTime
object.
private DateTime GetNextRun()
{
var today = DateTime.Today;
var runTime = new DateTime(today.Year, today.Month, today.Day, 17, 0, 0);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var offset = timeZoneInfo.GetUtcOffset(runTime);
var dto = new DateTimeOffset(runTime, offset);
if (DateTime.Now > dto.LocalDateTime)
dto = dto.AddDays(1);
return dto.LocalDateTime;
}
Doing all the conversion using DateTimeOffset
instead of DateTime
proved effective. It even seems to handle Daylight Savings Time correctly.
How can I add a day to a DateTime in a specific timezone
Here are extension methods that you can use for this.
First, this AddDays
method matches the signature you were asking about. It operates on DateTime
values:
public static DateTime AddDays(this DateTime dt, double days, TimeZoneInfo tz)
{
// If the kind is Local or Utc, convert that point in time to the given time zone
DateTimeKind originalKind = dt.Kind;
if (originalKind != DateTimeKind.Unspecified)
{
dt = TimeZoneInfo.ConvertTime(dt, tz);
}
// Add days with respect to the wall time only
DateTime added = dt.AddDays(days);
// Resolve the added value to a specific point in time
DateTimeOffset resolved = added.ToDateTimeOffset(tz);
// Return only the DateTime portion, but take the original kind into account
switch (originalKind)
{
case DateTimeKind.Local:
return resolved.LocalDateTime;
case DateTimeKind.Utc:
return resolved.UtcDateTime;
default: // DateTimeKind.Unspecified
return resolved.DateTime;
}
}
Here is another variation of that extension method. This one operates on DateTimeOffset
values:
public static DateTimeOffset AddDays(this DateTimeOffset dto, double days, TimeZoneInfo tz)
{
// Make sure the input time is in the provided time zone
dto = TimeZoneInfo.ConvertTime(dto, tz);
// Add days with respect to the wall time only
DateTime added = dto.DateTime.AddDays(days);
// Resolve the added value to a specific point in time
DateTimeOffset resolved = added.ToDateTimeOffset(tz);
// Return the fully resolved value
return resolved;
}
Both of the above methods depend on the following ToDateTimeOffset
extension method (which I've used in a few different posts now).
public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeZoneInfo tz)
{
if (dt.Kind != DateTimeKind.Unspecified)
{
// Handle UTC or Local kinds (regular and hidden 4th kind)
DateTimeOffset dto = new DateTimeOffset(dt.ToUniversalTime(), TimeSpan.Zero);
return TimeZoneInfo.ConvertTime(dto, tz);
}
if (tz.IsAmbiguousTime(dt))
{
// Prefer the daylight offset, because it comes first sequentially (1:30 ET becomes 1:30 EDT)
TimeSpan[] offsets = tz.GetAmbiguousTimeOffsets(dt);
TimeSpan offset = offsets[0] > offsets[1] ? offsets[0] : offsets[1];
return new DateTimeOffset(dt, offset);
}
if (tz.IsInvalidTime(dt))
{
// Advance by the gap, and return with the daylight offset (2:30 ET becomes 3:30 EDT)
TimeSpan[] offsets = { tz.GetUtcOffset(dt.AddDays(-1)), tz.GetUtcOffset(dt.AddDays(1)) };
TimeSpan gap = offsets[1] - offsets[0];
return new DateTimeOffset(dt.Add(gap), offsets[1]);
}
// Simple case
return new DateTimeOffset(dt, tz.GetUtcOffset(dt));
}
Lastly, I'll point out that there is another option to consider: Use the Noda Time library. It's ZoneDateTime.Add
method has exactly this purpose.
Related Topics
How to Get the Current Username in .Net Using C#
Check If a Class Is Derived from a Generic Class
How to Monitor Clipboard Changes in C#
Cast Generic≪Derived≫ to Generic≪Base≫
C# Getting the Path of %Appdata%
Picturebox Paintevent With Other Method
Which .Net Dependency Injection Frameworks Are Worth Looking Into
How to Find the Number of Cpu Cores Via .Net/C#
How to Check For Internet Connectivity Using .Net
Given a Filesystem Path, Is There a Shorter Way to Extract the Filename Without Its Extension
Is "Else If" Faster Than "Switch() Case"
Convert a Bitmap into a Byte Array
How to Deserialize an Array of Values With a Fixed Schema to a Strongly Typed Data Class
Writing Data into CSV File in C#
Copy Datagridview Values to Textbox
How to Ensure That a Division of Integers Is Always Rounded Up