How to represent the current UK time? - c#

I'm facing an issue while converting dates between my server and client where both is running in Germany. The Regional settings on the client machines could be set to both UK or Germany.I recieve a date from the server which is CET format, and I need to represent this time on UI as UK time. For example a time recieved from server like say, 01/07/2010 01:00:00 should be represented on the UI as 01/07/2010 00:00:00. I have written a converter for this purpose, however while running it 'am getting a time difference of 2 hours.Below is the code, please can you help?
public class LocalToGmtConverter : IDateConverter
{
private readonly TimeZoneInfo timeZoneInfo;
public LocalToGmtConverter()
: this(TimeZoneInfo.Local)
{
}
public LocalToGmtConverter(TimeZoneInfo timeZoneInfo)
{
this.timeZoneInfo = timeZoneInfo;
}
public DateTime Convert(DateTime localDate)
{
var utcKind = DateTime.SpecifyKind(localDate, DateTimeKind.Utc);
return utcKind;
}
public DateTime ConvertBack(object fromServer)
{
DateTime serverDate = (DateTime)fromServer;
var utcOffset = timeZoneInfo.GetUtcOffset(serverDate);
var uiTime = serverDate- utcOffset;
return uiTime;
}
}

I think you're converting to UTC (instead of UK) time. Since there is still summer time in Central Europe (event if the temperatures say otherwise), the difference is +2 hours until October, 31st.
If you know that you're converting from Germany to UK (i.e. CEST to BST in summer and CET to GMT in winter), why you don't just subtract 1 hour?
If you want the time zone information for UK, you can construct it using
var britishZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
Then you could convert the date using
var newDate = TimeZoneInfo.ConvertTime(serverDate, TimeZoneInfo.Local, britishZone);

This is what I do:
var BritishZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime dt = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
DateTime DateTimeInBritishLocal = TimeZoneInfo.ConvertTime(dt, TimeZoneInfo.Utc, BritishZone);
I needed to add the SpecifyKind part or the ConvertTime throws an exception

Use TimeZoneInfo.ConvertTime to convert original input timezone (CET) to target timezone (UK).
public static DateTime ConvertTime(
DateTime dateTime,
TimeZoneInfo sourceTimeZone,
TimeZoneInfo destinationTimeZone
)
Full guidance on MSDN here:
Converting Times Between Time Zones
Modified code sample from MSDN:
DateTime ceTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
TimeZoneInfo ceZone = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
TimeZoneInfo gmtZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
Console.WriteLine("{0} {1} is {2} GMT time.",
ceTime,
ceZone.IsDaylightSavingTime(ceTime) ? ceZone.DaylightName : ceZone.StandardName,
TimeZoneInfo.ConvertTime(ceTime, ceZone, gmtZone));
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The registry does not define the required timezones.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the required timezones has been corrupted.");
}

The better approach to deal with local times is store them in unified representation such as UTC.
So you can convert all input times to UTC (via .ToUniversalTime()), and store (or transmit) its value. When you need to show it just convert back by using .ToLocalTime().
So you avoid rquirements to know which time zone was original value and can easily show stored value in different timezones.
Also you can avoid incoming troubles where you have to write specific logic for processing time in next timezone trying to figure out how to convert them amongs all available.

I realize the question is for C#, but if all you want to do is a single conversion you can do this from the PowerShell command line:
$d = [DateTime]::Parse("04/02/2014 17:00:00")
$gmt = [TimeZoneInfo]::FindSystemTimeZoneById("GMT Standard Time");
[TimeZoneInfo]::ConvertTime($d, $gmt, [TimeZoneInfo]::Local)
This script would convert 17:00 UK time into your local time zone.
For me, that would be CST. It's interesting to note that if I had set the date to 03/27/2014, the result would be different because the UK daylight saving time kicks in on different dates that the US.

Related

How to convert Server Date time to Indian Standard Time?

I have WebApp deployed on US server. I have used DateTime.Now in order to capture User Date and Time on certain Action by the User.
Localy it works fine and gets the Date time correct. But post the deployment function is saving the date time for the Server Date time and not the User.
Users are in India hence it should capture IST and not MST as what it is doing now.
Here is my Code I have used so far with no success:
//Getting the current UTC Time
DateTime UTCTime = System.DateTime.UtcNow;
//Adding the time difference 5.5 hours to the utc time
DateTime IndianTime = UTCTime.AddHours(5.5);
dto.ChatCreateDateTime = IndianTime;
Using TimeZone Class did not work either.
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
DateTime timeUTC = DateTime.UtcNow;
DateTime result = TimeZoneInfo.ConvertTimeFromUtc(timeUTC, timeZone);
dto.ChatCreateDateTime = result;
I did try searching online and tried many fix like TimeZone Class, and other but none worked for me.
Use the below code but no correct datetime. Time shows as behind by 30 mins.
DateTime dateTime = DateTime.Now;
DateTime utcTime = dateTime.ToUniversalTime();
TimeZoneInfo istZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
DateTime yourISTTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, istZone);
model.ChatCreateDateTime = yourISTTime;
Chat dto = new Chat();
//dto.CustEmail = model.CustEmail;
dto.CustName = model.CustName;
dto.ChatStartDateTime = model.ChatStartDateTime;
// Gets current local date
// Returns 04/09/12 11:30 in my case
dto.ChatStartDateTime = model.ChatStartDateTime;
Thank you in advance.
If you want to convert time from UTC to any specific Time Zone
you should try follwing way.
DateTime dateTime = DateTime.Now; // I am getting date time here
DateTime utcTime = dateTime.ToUniversalTime(); // From current datetime I am retriving UTC time
TimeZoneInfo istZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); // Now I am Getting `IST` time From `UTC`
DateTime yourISTTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, istZone); // Finally converting it
var hourIST = yourISTTime.Hour; // More granular extraction.
Output:
Note:
I am trying this way and perfectly working for me. If you require
further modification and granularity you could check our official document here.

Is there a way to group by a range of dates or datetimeoffset?

I have a bunch of data with a DateTime that's in UTC, I want to group each data by date by using .GroupBy, but I want to group them according to CST or EST. Is there a way to do this using EF core? I haven't been successful at finding if this is possible by using DateTimeOffset or TimeSpan.
You can create a TimeZoneInfo object representing e.g. Eastern Standard Time with the TimeZoneInfo.FindSystemTimeZoneById method. (Note: this depends on the OS timezone rules, which e.g. in the case of Windows do not cover all DST history.)
var tzest = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
Then you can convert any given DateTime test that has DateTime.Kind of DateTimeKind.Utc to the new timezone:
var testest = TimeZoneInfo.ConvertTime(test, tzest);
If your DateTime has Kind as Unspecified you can use TimeZoneInfo.ConvertTimeFromUtc():
var testest = TimeZoneInfo.ConvertTimeFromUtc(test, tzest);
If test has TimeZoneKind.Local, this will throw an exception and you will need to override the TimeZoneKind:
var testest = TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(test, DateTimeKind.Utc), tzest);

Difference between Staging and production sent datetime in invoice

We have GMT time zone for staging and production. but when the code execute it shows correct result in staging and incorrect in production.
bool checkTimeBSTorGMT = TimeZoneInfo.Local.IsDaylightSavingTime(records.GetDateTimeOrEmpty("notification_date"));
if (checkTimeBSTorGMT == true)
{
DateTime dt = new DateTime();
dt = records.GetDateTimeOrEmpty("notification_date");
dt = dt.AddHours(1);
instance.SentDateTime = dt;
}
else
{
instance.SentDateTime = records.GetDateTimeOrEmpty("notification_date");
}
My code is as above. I want that it should fetch correct date according to the user local machine across the world.
I would not be trying to roll my own times and timezones code. It will end in tears. (Is the daylight savings bias always 60 minutes? Your code assumes so)
Here is a better way to convert between two timezones. I've included some of the more unusual timezones in there.
using System;
public class Program
{
private static void DisplayTimeInTimeZone(DateTime timeOfInterestUTC, string timezoneId)
{
Console.WriteLine($"UTC Time {timeOfInterestUTC} in {timezoneId} is {TimeZoneInfo.ConvertTime(timeOfInterestUTC, TimeZoneInfo.FindSystemTimeZoneById(timezoneId))}");
}
public static void Main()
{
/*
// In case you were wondering what Timezones are available
foreach (var tz in TimeZoneInfo.GetSystemTimeZones())
{
Console.WriteLine(tz.Id);
}
*/
DateTime someArbitraryLocalTime = new DateTime(2018, 2, 15, 9, 30, 0);
DateTime someArbitraryTimeAsUTC = TimeZoneInfo.ConvertTimeToUtc(someArbitraryLocalTime, TimeZoneInfo.FindSystemTimeZoneById("US Eastern Standard Time"));
Console.WriteLine($"US Eastern Standard Time {someArbitraryLocalTime} in UTC is {someArbitraryTimeAsUTC}");
DisplayTimeInTimeZone(someArbitraryTimeAsUTC, "GMT Standard Time");
DisplayTimeInTimeZone(someArbitraryTimeAsUTC, "Cen. Australia Standard Time");
DisplayTimeInTimeZone(someArbitraryTimeAsUTC, "Chatham Islands Standard Time");
DisplayTimeInTimeZone(someArbitraryTimeAsUTC, TimeZoneInfo.Local.Id);
}
}
I'm unclear about what notification_date and SentDateTime are with respect to time zones. If they are already UTC, then it is just the ConvertTime method you need to translate it.
If it is local to a reference timezone, you will need to use ConvertTimeToUtc first. If it comes from user input, be aware that some times don't exist for time zones that have daylight savings (when DST starts, we set our clocks forwards an hour, so any time in that "hour" is undefined). Conversely, the conversion is ambiguous at the end of DST because that "hour" happens twice.

Convert from one timezone to another taking into consideration daylight saving

I want to convert a datetime from one time zone to another. For this i need to pass the zone id to the method FindSystemTimeZoneById. But i do not have this information and need to determine that by using a switch-case.
Here i also need to take into account daylight saving. but in order to determine whether a time is in DST i need that zone id beforehand.
Is there any way to determine whether a time is in DST without the zone id. My server is in zone 1 and i want to convert the time to zone 2.
Here is the snippet:
public DateTime ConvertToDestTime(DateTime currentTime, string sourceTimeZoneUtc, string serverTimeZoneUtc)
{
TimeZoneInfo sourceTimeZone = TimeZoneInfo.FindSystemTimeZoneById(ReturnTimeZoneString(sourceTimeZoneUtc));
TimeZoneInfo serverTimeZone = TimeZoneInfo.FindSystemTimeZoneById(ReturnTimeZoneString(serverTimeZoneUtc));
DateTime serverTime = TimeZoneInfo.ConvertTime(currentTime, sourceTimeZone, serverTimeZone);
return serverTime;
}
private string ReturnTimeZone(string utcOffset)
{
string timezone = string.Empty;
string isDaylight = //need to determine whether time is in DST here
if (isDaylight == "N")
{
switch (utcOffset)
{
case "-04:00":
timezone = "Atlantic Standard Time";
break;
case "-05:00":
timezone = "Eastern Standard Time";
break;
}
}
else
{
switch (utcOffset)
{
case "-04:00":
timezone = "Eastern Standard Time";
break;
case "-05:00":
timezone = "Central America Standard Time";
break;
}
}
return timezone;
Convert the source time to UTC time.
string sourceTimeZone="Atlantic Standard Time;
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone);
DateTime sourceUTCTime = TimeZoneInfo.ConvertTimeToUtc(currentTime, timeZoneInfo);
then using the converted UTC time get the destination time as below,
string destinationTimeZone="India Standard Time";
TimeZoneInfo destTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZone);
DateTime destinationUTCTime = TimeZoneInfo.ConvertTimeFromUtc(sourceUTCTime, destTimeZoneInfo);
Hope this helps!!!
Check ou t Microsoft's "timeless" article Coding Best Practices Using DateTime in the .NET Framework.
The article may be a few years old, but the priciples and problem scenarios are still today's topics.
There is a dedicated chapter about Dealing with Daylight Savings Time.
By converting your local time views to universal time prior to
performing your calculations, you get past the issues of time
accuracy.
So, convert your local time to UTC format first and then into the target time format.
You cannot perform this type of reverse mapping reliably. There are just two many possible time zones that any particular offset could fall into.
See "TimeZone != Offset" in the timezone tag wiki.
See also all the places that -04:00 might be used.
Lastly, recognize that because each time zone in North America falls-back in their own local time, some values are shared by two time zones at once.
For example, 2014-11-02T01:00:00-05:00 could belong to either US Central Time (CDT) or US Eastern Time (EST), as shown here.
A bit old question, but may be somebody will enjoy bellow extension
public static class DateTimeExtension
{
public static DateTime ConvertBetweenTimeZones(this DateTime d, string sourceTimeZone, string destinationTimeZone)
{
var tziSource = TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone);
var tziDestination = TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZone);
var utcDate = TimeZoneInfo.ConvertTimeToUtc(d, tziSource);
return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tziDestination);
}
}
And some unit test for that:
[TestClass]
public class DateTimeTests
{
[TestMethod]
public void ConvertBetweenTimeZonesTest()
{
var dateTime = new DateTime(2023, 1, 27, 21, 0, 0);
var sourceTimeZone = "Central European Standard Time";
var destTimeZone = "UTC-02";
var dateResult = dateTime.ConvertBetweenTimeZones(sourceTimeZone, destTimeZone);
var expectedDate = new DateTime(2023, 1, 27, 18, 0, 0);
Assert.AreEqual(expectedDate, dateResult);
}
}
[TestClass]
public class TimeZoneInfoTests
{
[TestMethod]
public void ConvertBetweenTimeZonesTest()
{
var timeZone = "Central European Standard Time";
var tzi = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
Assert.AreEqual("UTC+01:00", tzi.GetShortName());
}
}

Getting invalid result when using Noda Time c#

Assume Instant variable contains "4/8/2014 11:09:24 AM" when i pass this value to this method it gives me an output "4/8/2014 12:09:24 PM" i checked in some time zone calcluator plus in oracle i should be getting "4/8/2014 04:09:24 PM" or "4/8/2014 16:09:24 PM" depending on hour format. why is it not converting into proper time format?
public static string ConvertDateTimeToUserTimeZone()
{
DateTime dt = DateTime.Parse("4/8/2014 11:09:24 AM");
Instant now = Instant.FromDateTimeUtc(DateTime.SpecifyKind(dt,DateTimeKind.Utc));
DateTimeZone dtZone = DateTimeZoneProviders.Tzdb["Europe/London"];
ZonedDateTime zdt = now.InZone(dtZone);
return zdt.ToDateTimeOffset().ToString("G");
}
Reading through your comments, it would appear that you'd like to do the following:
Parse the input string
Assign it to the the US Eastern time zone ("America/New_York")
Convert it to the time zone for the UK ("Europe/London")
Format it as a string in the general format
I will show using Noda Time for all of these steps, rather than mixing in non-Noda mechanisms.
var generalPattern = LocalDateTimePattern.CreateWithCurrentCulture("G");
string inputString = "4/8/2014 11:09:24 AM";
string sourceTimeZone = "America/New_York";
string targetTimeZone = "Europe/London";
LocalDateTime ldt1 = generalPattern.Parse(inputString).Value;
DateTimeZone tz1 = DateTimeZoneProviders.Tzdb[sourceTimeZone];
ZonedDateTime zdt1 = ldt1.InZoneLeniently(tz1);
DateTimeZone tz2 = DateTimeZoneProviders.Tzdb[targetTimeZone];
ZonedDateTime zdt2 = zdt1.WithZone(tz2);
LocalDateTime ldt2 = zdt2.LocalDateTime;
string output = generalPattern.Format(ldt2);
Notice that I used CreateWithCurrentCulture when setting up the pattern. This assumes you mean to use whatever the current culture is for the machine the code is running on. If that's not the case, then you should set a specific culture instead. This is important when you realize that users in the US will use M/D/Y formatting, while users in the UK will use D/M/Y formatting. This applies to both dates regardless of time zone. (In other words, 4/8/2014 could be April 8th, or August 4th).
Also notice that I used InZoneLeniently when applying the source time zone. This has lenient behavior when it comes to ambiguous and invalid input values due to DST transitions. If you want different behavior, then you might instead use InZoneStrictly, or use InZone and provide your own algorithm.
And finally, it should be noted that I inferred from your comments that you were sourcing these from the US Eastern time zone, which would be either EDT or EST depending on what time of year it is. If you actually meant that the values were always EDT, even when EST is the norm, then you would do the following:
DateTimeZone tz1 = DateTimeZone.ForOffset(Offset.FromHours(-4));
The value you got back from the method is in fact correct.
Let's break it down using LINQPad:
void Main()
{
var t = new DateTime(2014, 8, 4, 11, 09, 24, DateTimeKind.Utc);
var i = Instant.FromDateTimeUtc(t);
var s = ConvertDateTimeToUserTimeZone(i);
s.Dump("User time zone value");
}
public static string ConvertDateTimeToUserTimeZone(Instant now)
{
DateTimeZone dtZone = DateTimeZoneProviders.Tzdb["Europe/London"];
dtZone.GetUtcOffset(now).Dump("TZ at instant");
ZonedDateTime zdt = now.InZone(dtZone);
return zdt.ToDateTimeOffset().ToString("G");
}
Output:
TZ at instant
+01
User time zone value
04.08.2014 12:09:24
The time zone at the point of that instant is thus UTC+1, which means that the value you gave the code gives you the correct value back, 12:09.
To get 16:09, you would need UTC+5, and Europe/London has never been that value.
So 12:09:24 is correct, your assumptions that it should be 16:09:24 is wrong.
You need to go back to the code and/or sites you used to get the "correct" value, the source of your confusion is there, not in this code.

Categories