views:

3682

answers:

3

I am using DateTime.Now to show something according to today's date, and when working locally (Malta, Europe) the times appear correctly (obviously because of the Time Zone) but ofcourse when I upload it to my hosting server (USA), DateTime.Now does not represent the correct time zone.

Therefore, in my code, how can I convert DateTime.Now to correctly return the time from a GMT + 1 timezone ?

+2  A: 

I don't think that you can set a property in your code that will make DateTime.Now return anything else than the current time of the computer in which the code executes. If you want to have a way of always getting another time, you will probably need to wrap in another function. You can can do the round-trip over UTC and add the desired offset:

private static DateTime GetMyTime()
{
    return DateTime.UtcNow.AddHours(1);
}

(code sample updated after Luke's comment on the inner workings of DateTime.Now)

Fredrik Mörk
Using `DateTime.UtcNow.AddHours(1)` instead will save you some typing!
LukeH
Yes, I realized that. But then I am not sure that they do exactly the same thing; UtcNow fetches the system time and does some operations with "magic numbers", while ToUniversalTime uses the TimeZone.CurrentTimeZone to get the Utc time. I suppose they will always return the same time though ;o)
Fredrik Mörk
`DateTime.Now` uses `UtcNow` behind the scenes, so your original code translates to something like `DateTime.UtcNow.ToLocalTime().ToUniversalTime().AddHours(1)`.
LukeH
So true; didn't think about that. Thanks for pointing it out. Will update the answer. I am not afraid of typing, but when the code is inefficient like that it's a different matter.
Fredrik Mörk
(By the way, I think the first magic number used in `UtcNow` is to convert from `FILETIME` - ticks since 01/01/1601 - to `DateTime` - ticks since 01/01/0001. The second magic number is a mask used internally to signify `DateTimeKind.Utc`.)
LukeH
+9  A: 

Use the TimeZoneInfo class found in System.Core;

You must set the DateTimeKind to DateTimeKind.Utc for this.

DateTime MyTime = new DateTime(1990, 12, 02, 19, 31, 30, DateTimeKind.Utc);

DateTime MyTimeInWesternEurope = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(MyTime, "W. Europe Standard Time");

Only if you're using .Net 3.5 though!

ThePower
+6  A: 

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);


Judging by your comments, this bit will be irrelevant, but just for others...

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!");
}
Jon Skeet
Jon, I edited your answer to invert the parameters of TimeZoneInfo.ConvertTimeFromUtc
Andreas Grech
Whoops, thanks. The bizarre thing is I did actually check them first - then got them the wrong way round anyway!
Jon Skeet
Your solution is throwing this exception in the ConvertTimeFromUtc method: 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
Andreas Grech
Are you sure you're passing it DateTime.UtcNow rather than DateTime.Now?
Jon Skeet
yes, I'm using your exact code snippet (obviously change the id to "W. Europe Standard Time" though)
Andreas Grech
And are you sure you're calling ConvertTimeFromUtc rather than ConvertTimeToUtc? This is more likely to be the issue, given the exact exception you're specifying...
Jon Skeet
I've just tried that snippet, and it works fine on my machine.
Jon Skeet
(Whereas changing to ConvertTimeToUtc gives the exact exception message you've given here.)
Jon Skeet
Excuse my stupidity, but you are right. I was using ConvertTimeToUtc instead of ConvertTimeFromUtc.
Andreas Grech