Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting DateTime.Now To A Different Time Zone

Tags:

c#

datetime

This code has been working for a long time now but has broken now when I try to pass DateTime.Now as the outageEndDate parameter:

public Outage(DateTime outageStartDate, DateTime outageEndDate, Dictionary<string, string> weeklyHours, string province, string localProvince)
    {
        this.outageStartDate = outageStartDate;
        this.outageEndDate = outageEndDate;
        this.weeklyHours = weeklyHours;
        this.province = province;
        localTime = TimeZoneInfo.FindSystemTimeZoneById(timeZones[localProvince]);

        if (outageStartDate < outageEndDate)
        {
            TimeZoneInfo remoteTime = TimeZoneInfo.FindSystemTimeZoneById(timeZones[province]);
            outageStartDate = TimeZoneInfo.ConvertTime(outageStartDate, localTime, remoteTime);
            outageEndDate = TimeZoneInfo.ConvertTime(outageEndDate, localTime, remoteTime);

The error message I am getting on the last line is that the Kind property is not set correctly on the DateTime parameter (outageEndDate). I've Googled and checked SO for examples but I don't really understand the error message.

Any advice is appreciated.

Regards.

EDIT - The exact error message is:

The conversion could not be completed because the supplied DateTime did not have the Kind
property set correctly.  For example, when the Kind property is DateTimeKind.Local, the source
time zone must be TimeZoneInfo.Local.  Parameter name: sourceTimeZone

EDIT: outageEndDate.Kind = Utc

like image 969
Kevin Avatar asked Jan 16 '23 21:01

Kevin


2 Answers

Thanks for clarifying your question.

If the DateTime instance Kind is Local, then TimeZoneInfo.ConvertTime will expect the second parameter to be the local timezone of your computer.

If DateTime instance Kind is Utc, then TimeZoneInfo.ConvertTime will expect the second parameter to be the Utc timezone.

You need to convert outageEndDate to the right timezone first, just in case the localProvice timezone doesn't match the timezone on your computer.

outageEndDate = TimeZoneInfo.ConvertTime(outageEndDate, localTime);
like image 86
Monroe Thomas Avatar answered Jan 28 '23 10:01

Monroe Thomas


here is an example of something that you could try

It depends on what you mean by "a GMT + 1 timezone". Do you mean permanently UTC+1, or do you mean UTC+1 or UTC+2 depending on DST?

If you're using .NET 3.5, use TimeZoneInfo to get an appropriate time zone, then use:

// Store this statically somewhere
TimeZoneInfo maltaTimeZone = TimeZoneInfo.FindSystemTimeZoneById("...");
DateTime utc = DateTime.UtcNow;
DateTime malta = TimeZoneInfo.ConvertTimeFromUtc(utc, maltaTimeZone );

You'll need to work out the system ID for the Malta time zone, but you can do that easily by running this code locally:

Console.WriteLine(TimeZoneInfo.Local.Id);

If you're not using .NET 3.5, you'll need to work out the daylight savings yourself. To be honest, the easiest way to do that is going to be a simple lookup table. Work out the DST changes for the next few years, then write a simple method to return the offset at a particular UTC time with that list hardcoded. You might just want a sorted List<DateTime> with the known changes in, and alternate between 1 and 2 hours until your date is after the last change:

// Be very careful when building this list, and make sure they're UTC times!
private static readonly IEnumerable<DateTime> DstChanges = ...;

static DateTime ConvertToLocalTime(DateTime utc)
{
    int hours = 1; // Or 2, depending on the first entry in your list
    foreach (DateTime dstChange in DstChanges)
    {
        if (utc < dstChange)
        {
            return DateTime.SpecifyKind(utc.AddHours(hours), DateTimeKind.Local);
        }
        hours = 3 - hours; // Alternate between 1 and 2
    }
    throw new ArgumentOutOfRangeException("I don't have enough DST data!");
}
like image 21
MethodMan Avatar answered Jan 28 '23 08:01

MethodMan