How to convert DateTimeOffset back to DateTime - c#

When we create a search index and we define a field as DateTime the type is Edm.DateTimeOffset. And the value should be like this: yyyy-MM-ddTHH:mm:ss.fffZ or yyyy-MM-ddTHH:mm:ss.fff[+|-]HH:mm.
Now I have a file in my database of type DateTime that get's converted to Offset like this:
DateTime offset = //get from database the date
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time");
DateTimeOffset offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset));
My question: how can I convert offsetConverted to my orginal DateTime offset?

Use the DateTime property of the DateTimeOffset class to convert the DateTimeOffset to a DateTime.
using System;
namespace StackOverflowProblem1
{
class Program
{
static void Main(string[] args)
{
// input comes from user in form yyyyddMMTHHmmss
DateTime offset = new DateTime(2016, 10, 12, 12, 22, 0);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time");
DateTimeOffset offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset));
DateTime roundTripOffset = offsetConverted.DateTime;
Console.WriteLine("Input {0}, as DateTimeOffset {1},",
offset.ToString(),
offsetConverted.ToString());
Console.WriteLine("after round trip {0}, Kind {1}.",
roundTripOffset,
roundTripOffset.Kind);
}
}
}
Console output:
Input 10/12/2016 12:22:00, as DateTimeOffset 10/12/2016 12:22:00 +03:00,
after round trip 10/12/2016 12:22:00, Kind Unspecified.

Related

Create new DateTime in Country via TimeZoneInfo for office hours

Question
Q: How can I create a DateTime for e.g. 09:00 in Europe/Vienna
Catch: Most solutions that I've found already take a DateTime object and convert it but I want to CREATE it IN A SPECIFIC timezone knowing the timezone.
So it is not DateTimeKind.Utc and it is not DateTimeKind.Local it would be in DateTime in timezone.
Problem
P: TimeZoneInfo is not a parameter of DateTime. Why not? Could there be a simple extension?
Basis data:
1. string From = "09:00" //local time because summertime/wintertime
2. string Till = "17:00" //local time because summertime/wintertime
3. string TimeZoneResolved = "Europe/Vienna"
Implicitly I have:
TimeZoneInfo timeZoneInfo = TZConvert.GetTimeZoneInfo(TimeZoneResolved);
TimeSpan workHoursStart = TimeSpan.Parse(From);
TimeSpan workHoursEnd = TimeSpan.Parse(Till);
What I want to achieve:
//reconstruct today 9am in that country of timeZoneInfo
var now = DateTime.UtcNow;
var startTime = new DateTime(now.Year, now.Month, now.Day, workHoursStart.Hour, workHoursStart.Minute, 0, 0, timeZoneInfo);
-> invalid because TimeZoneInfo parameter is invalid. Expects DateTimeKind
Because constructor overload might be tricky maybe like that
var now = DateTime.UtcNow;
var officeHoursStart = new DateTime().BasedOnTz(timeZoneInfo, now.Year, now.Month, now.Day, workHoursStart.Hour, workHoursStart.Minute, 0, 0);
var officeHoursStartUtc = officeHoursStart.ToUtc();
To restate the problem - you have as input a time and a time zone, and you need as output the point in time that corresponds to that time on the current day in the given time zone.
Since the output is a point in time, you should prefer using DateTimeOffset. (If you must use a DateTime, you can take the .DateTime property from that.)
Since the input is a time of day, you should prefer using TimeOnly, available in .NET 6 and higher. (If you're using older .NET, then use a TimeSpan.)
Here's the general approach:
using System;
using System.Globalization;
// Get the time zone as a TimeZoneInfo object, either directly or via TimeZoneConverter.
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Eurpope/Vienna");
// Parse the time string. Prefer using TimeOnly (.NET 6+).
string timeString = "17:00";
TimeOnly time = TimeOnly.ParseExact(timeString, "HH:mm", CultureInfo.InvariantCulture);
// Or use TimeSpan on older .NET
// TimeSpan timeSpan = TimeSpan.ParseExact(timeString, "hh\\:mm", CultureInfo.InvariantCulture);
// Get the time on "today" with respect to the given time zone
DateTimeOffset timeTodayInTimeZone = time.OnTodayInTimeZone(timeZone);
You'll need some extension methods. Pick one of these, depending on which input you're using.
public static DateTimeOffset OnTodayInTimeZone(this TimeOnly time, TimeZoneInfo tz) =>
DateOnly.FromDateTime(TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz))
.ToDateTime(time)
.ToDateTimeOffset(tz);
public static DateTimeOffset OnTodayInTimeZone(this TimeSpan time, TimeZoneInfo tz) =>
TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz).Date
.Add(time)
.ToDateTimeOffset(tz);
And finally, you need this extension method that has the bulk of the logic.
(I've used this one on several other answers 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));
}

Why UtcDateTime function is not adding the offset to the UTC date?

For instantaneous DateTime tracking, I am using a DateTimeOffset datatype. The following function adds the user corresponding TimeZone ID offset to the UTC DateTime property of DateTimeOffset
According to the documentation, UtcDateTime will perform both a time zone conversion and a type conversion on a DateTimeOffset. The following code does not though. Why is the conversion not taking place?
Function to add TimeSpan offset,
public static DateTimeOffset GetUtcDateTime (DateTime sourceDateTime, string timeZoneId) {
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById (timeZoneId);
TimeSpan offset = timeZone.GetUtcOffset (sourceDateTime);
DateTimeOffset utcTime = new DateTimeOffset (sourceDateTime, offset);
return utcTime;
}
and here where I am trying to convert,
DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;
DateTimeOffset UtcDate = StaticHandlers.GetUtcDateTime (fromUtc, "America/Los_Angeles");
Console.WriteLine ("UTC now is {0} and UTC Date LA is {1} and UtcDateTime LA is {2}", utcDate, UtcDate, utcDate.UtcDateTime);
the output is,
UTC now is 5/8/18 6:43:37 AM +00:00 and and UTC Date LA is 5/8/18
6:43:37 AM -07:00 UtcDateTime LA is 5/8/18 6:43:37 AM
update,
I want to preserve both UTC and the user offset for tracking purposes. DST matters in this context. The example below shows what I am talking about.
DateTime currentDateTime = DateTime.Now;
DateTime beforeDST_LA = new DateTime (2018, 3, 11, 0, 0, 0);
DateTime afterDST_LA = new DateTime (2018, 3, 12, 0, 0, 0);
TimeSpan offsetCurrent = tzi.GetUtcOffset (currentDateTime);
TimeSpan offsetBeforeDST = tzi.GetUtcOffset (beforeDST_LA);
TimeSpan offsetAfterDST = tzi.GetUtcOffset (afterDST_LA);
Console.WriteLine ("Current offset is {0} before DST is {1} and After DST is {2}", offsetCurrent, offsetBeforeDST, offsetAfterDST);
Current offset is -07:00:00 before DST is -08:00:00 and After DST is
-07:00:00
First, I would not call your function GetUtcDateTime, because that's not what it does. It is trying to get a DateTimeOffset for a specific time zone for a specific time, so call it something like GetDateTimeOffset.
The main concept you're missing in your code is that DateTime has .Kind property, which sets a DateTimeKind value. The kind is taken into consideration by several places in your code:
GetUtcOffset will convert Utc or Local kinds to the zone provided before determining the offset.
new DateTimeOffset (the constructor) will error if the kind and the offset conflict, if you provide an offset.
When you assign a DateTime to a DateTimeOffset, the implicit conversion is evaluating the kind.
When you call .DateTime from the DateTimeOffset, the kind will always be Unspecified - regardless of the offset.
If you take all of this into account, you'll realize you need to check the kind yourself before calling GetUtcOffset. If it's not Unspecified then you'll need to convert it to the specified time zone before getting the offset.
public static DateTimeOffset GetDateTimeOffset(DateTime sourceDateTime, string timeZoneId)
{
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
// here, is where you need to convert
if (sourceDateTime.Kind != DateTimeKind.Unspecified)
sourceDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, timeZone);
TimeSpan offset = timeZone.GetUtcOffset(sourceDateTime);
return new DateTimeOffset(sourceDateTime, offset);
}
Now that this is handled, turn to the next set of problems, which is where you call it.
DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;
In line 1, the implicit cast from DateTime to DateTimeOffset sets the offset to 00:00 - because DateTime.UtcNow has .Kind == DateTimeKind.Utc.
In line 2, the call to the .DateTime property sets fromUtc.Kind == DateTimeKind.Unspecified. Essentially, you've stripped away the kind.
So instead of this, just pass DateTime.UtcNow directly into the function. The kind will persist, and it will all work - now that the Kind is recognized and the conversion is happening inside the function.
All that said, if your original values are all DateTimeOffset (example, DateTimeOffset.UtcNow) then you don't need that function at all. Just call TimeZoneInfo.ConvertTime with the DateTimeOffset directly.

How can I create a new instance of DateTime in specific time zone?

Given a specific TimeZoneInfo instance how can I create a new DateTime instance in the specified time zone? For example if I have:
var tz = TimeZoneInfo.FindSystemTimeZoneById("US Eastern Standard Time");
var date = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
Console.WriteLine(TimeZoneInfo.ConvertTime(date, tz));
I am always getting 12/31/2016 7:00:00 PM regardless of what DateTimeKind I define (Utc, Local or Unspecified).
How can I declare a new DateTime that will be January 1st of 2017 at 0:00:00 in US Eastern Standard Time?
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).
you can use the timezoneID as you are using it to specify what timezone you want to create your datetime object.
TimeZoneInfo tzone= TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard
Time");
DateTime dt = DateTime.Now;
later you just convert the datetime to your required timezone.
var datetime2 = TimeZoneInfo.ConvertTimeFromUtc(dt , tzone);
this is the link where you can find all timezones ID. TimeZoneIDs
Thank you, hope this can help you.

In C#, How to convert a date time string with timezone to DateTime? [duplicate]

I am trying to parse 11/23/2011 23:59:59 UTC +0800 as a c# datetime object but trying the standard datetime parse method or even the datetime exact parse I get invalid date.
Any ideas?
I would suggest you parse to a DateTimeOffset instead of a DateTime, as recommended in MSDN when using a time zone offset specifier in the format string:
using System;
using System.Globalization;
class Test
{
static void Main(string[] args)
{
string text = "11/23/2011 23:59:59 UTC +0800";
string pattern = "MM/dd/yyyy HH:mm:ss 'UTC' zzz";
DateTimeOffset dto = DateTimeOffset.ParseExact
(text, pattern, CultureInfo.InvariantCulture);
Console.WriteLine(dto);
}
}
You can then convert that to a DateTime value in UTC if you want, but there's no such thing as "a DateTime with an offset of 8 hours" - a DateTime is either regarded as universal, local or unspecified, with nowhere for a specific offset to be stored.
DateTime is a curious type in various ways, and can cause problems for the unwary developer.
Msdn for Format settings: https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
public class Program
{
public static void Main()
{
//original date
string _date = "Thu Jan 15 11:32:09 +0200 2015";
// Describes the date format
string _parsePattern = "ddd MMM dd HH:mm:ss zzz yyyy";
DateTimeOffset dto = DateTimeOffset.ParseExact(_date, _parsePattern, CultureInfo.InvariantCulture);
//last settings
Console.WriteLine(dto.ToString("dd.MM.yyyy hh:mm:ss",CultureInfo.CreateSpecificCulture("tr-TR")));
}
}
for extension method:
public static DateTime getDateFromFormat(this string _date, string _parsePattern)
{
DateTimeOffset dto = DateTimeOffset.ParseExact(_date, _parsePattern, CultureInfo.InvariantCulture);
return Convert.ToDateTime(dto.ToLocalTime());
}
For test: https://dotnetfiddle.net/xdnjGy
As written by James, you can try
var dt = DateTime.ParseExact(
"11/23/2011 23:59:59 UTC +0800",
"MM/dd/yyyy HH:mm:ss 'UTC' K",
CultureInfo.InvariantCulture);
You'll get a date in the "local" time.
I think you need to use ParseExact
http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx

How to get back the converted Time zone value?

I am converting a datetime value to Indian Standard Time using the below code:
public DateTime GetdatetimedetailsinIST(DateTime datetimeinfo, String timeoffsetvalue)
{
string offset= timeoffsetvalue;
string timeZoneFormat = Convert.ToString("India Standard Time");
string strIndianTimezone = timeZoneFormat;
TimeZoneInfo tzinfoIndian = TimeZoneInfo.FindSystemTimeZoneById(strIndianTimezone);
DateTime dtDateTime = datetimeinfo.AddMinutes(Convert.ToInt32(offset));//ToUniversalTime();
dtDateTime = TimeZoneInfo.ConvertTimeFromUtc(dtDateTime, tzinfoIndian);
return dtDateTime;
}
Now I am calling GetdatetimedetailsinIST(5/6/2014 8:00:00 AM,"240");
and it will reurn Indian Time 5/6/2014 5:30:00 PM.
Now I want to get back the 5/6/2014 8:00:00 AM for another scenario by using value 5/6/2014 5:30:00 PM.
What are the changes need to do in the above function?
Please help.
howeverCould you add a string timeZoneToConvertTo parameter to your convert method?
public static DateTime DateTimeConvert(DateTime nonConvertedDateTime, string timeoffsetvalue, string timeZoneToConvertTo)
{
TimeZoneInfo tzinfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneToConvertTo);
DateTime dtDateTime = nonConvertedDateTime.AddMinutes(Convert.ToInt32(timeoffsetvalue));
dtDateTime = TimeZoneInfo.ConvertTimeFromUtc(dtDateTime, tzinfo);
return dtDateTime;
}
Console.WriteLine(DateTimeConvert(new DateTime(2014, 5, 6, 8, 00, 00), "240", "India Standard Time").ToString());
Console.WriteLine(DateTimeConvert(new DateTime(2014, 5, 6, 8, 00, 00), "240", "Central Standard Time").ToString());
You still need to handle any exceptions resulting from an inability to find the timezone.
I don't understand why you want an offset instead of using the ToUniversal() extension, however, that is your choice.
Adding minutes manually is seldom required or recommended. Also, there are a lot of unnecessary strings floating around your method. Consider the following instead:
public static DateTime ConvertToIndiaTime(DateTime dateTime, int offsetMinutes)
{
// Create a DateTimeOffset from the input values.
// This assumes positive offset values are *WEST* of UTC,
// such as if it came from the getTimeZoneOffset function of
// JavaScript's Date object.
TimeSpan offset = TimeSpan.FromMinutes(-offsetMinutes);
DateTimeOffset dto = new DateTimeOffset(dateTime, offset);
// Convert the DateTimeOffset to the desired time zone
DateTimeOffset converted =
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dto, "Indian Standard Time");
// Return the DateTime portion, representing the local time in India.
return converted.DateTime;
}
You would call it like this:
// get a DateTime object
DateTime dt = DateTime.ParseExact("5/6/2014 8:00:00 AM",
"M/d/yyyy h:mm:ss tt",
CultureInfo.InvariantCulture);
// get the offset as an integer
int offsetMinutes = 240;
// call the conversion method
DateTime indiaTime = ConvertToIndiaTime(dt, offsetMinutes);
Your method seems to combine two separate DateTime operations into one - hence it's not easy for you to reverse the operation. How about the following structure:
private static readonly TimeZoneInfo IstTimeZone =
TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
public static DateTime ConvertDateTimeUtcToIst(DateTime toConvert)
{
return TimeZoneInfo.ConvertTimeFromUtc(toConvert, IstTimeZone);
}
public static DateTime ConvertDateTimeIstToUtc(DateTime toConvert)
{
return TimeZoneInfo.ConvertTimeToUtc(toConvert, IstTimeZone);
}
Usage:
var converted = ConvertDateTimeUtcToIst(DateTime.Parse("5/6/2014 8:00:00 AM"))
.AddMinutes(240);
var reverted = ConvertDateTimeIstToUtc(converted).AddMinutes(-240);
Or if you absolutely need to have it in one method:
public static DateTime ConvertDateTimeUtcToIst(
DateTime toConvert, int offset = 0)
{
return TimeZoneInfo.ConvertTimeFromUtc(toConvert, IstTimeZone)
.AddMinutes(offset);
}
public static DateTime ConvertDateTimeIstToUtc(
DateTime toConvert, int offset = 0)
{
return TimeZoneInfo.ConvertTimeToUtc(toConvert, IstTimeZone)
.AddMinutes(offset);
}
Usage:
var converted = ConvertDateTimeUtcToIst(
DateTime.Parse("5/6/2014 8:00:00 AM"), 240);
var reverted = ConvertDateTimeIstToUtc(converted, -240);

Categories

Resources