Creating a Datetime in a Specific Time Zone in C#

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

  1. DateTime.ToString Method

  2. 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



Leave a reply



Submit