1

I want to add minutes to date where time is changing. Eg.

In 24-10-2015 time at 3 o'clock time goes back one hour in the back.

So when we have 2:20 AM, 50 minutes later we have 2:10 AM.

var date = new DateTime(2015,10,24, 2,20, 00);
Console.WriteLine(date.AddMinutes(50).ToString());

Above code return 3:10 and it's wrong.

How can I fix it? It's depends on the country and timezone.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
123498
  • 93
  • 9

3 Answers3

2

This sort of thing is precisely why I started the Noda Time project. It teases out assumptions you might have. For example, in your example, 2:20am occurs twice - so when you say new DateTime(2015,10,24, 2,20, 00) how is the system meant to know whether you mean the first occurrence or the second? It's not even clear which time zone you expect it to be in.

In Noda Time, the code would be something like:

var local = new LocalDateTime(2015, 10, 24, 2, 20, 0);
var zone = DateTimeZoneProviders.Tzdb[yourTimeZoneId];

// Apparently you want ambiguous times to resolve as the earlier
// occurrence.
var resolver = Resolvers.CreateMappingResolver(
    Resolvers.ReturnEarlier, Resolvers.ThrowWhenSkipped);

// This is now the *first* occurrence of 2:20am
var zoned = local.InZone(zone, resolver);

// This is now the *second* occurrence of 2:10am
var laterZoned = zoned.Plus(Duration.FromMinutes(50));

Note how everything is a lot more explicit here. You don't have to create your own resolver, in many cases - you can use InZoneStrictly which will throw on ambiguous or skipped times, and InZoneLeniently which will take the later of the ambiguous times, and the start of the interval after the gap for skipped times. (Some of this is changing slightly for Noda Time 2.0, hopefully to make things simpler for common cases.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

The big error you face is that the time does not go back on hour on 24. October but on 25.

You can try following code:

var date = new DateTime(2015, 10, 25, 1, 20, 00).ToUniversalTime();
Console.WriteLine($"UTC: {date}\tDST: {date.ToLocalTime().IsDaylightSavingTime()}\t{date.ToLocalTime()}");
date = date.AddMinutes(50);
Console.WriteLine($"UTC: {date}\tDST: {date.ToLocalTime().IsDaylightSavingTime()}\t{date.ToLocalTime()}");
date = date.AddMinutes(50);
Console.WriteLine($"UTC: {date}\tDST: {date.ToLocalTime().IsDaylightSavingTime()}\t{date.ToLocalTime()}");
date = date.AddMinutes(50);
Console.WriteLine($"UTC: {date}\tDST: {date.ToLocalTime().IsDaylightSavingTime()}\t{date.ToLocalTime()}");

and you will get for UTC+1 (CEST UTC+2) following output:

UTC: 24.10.2015 23:20:00    DST: True   25.10.2015 01:20:00
UTC: 25.10.2015 00:10:00    DST: True   25.10.2015 02:10:00
UTC: 25.10.2015 02:00:00    DST: False  25.10.2015 02:00:00
UTC: 25.10.2015 01:50:00    DST: False  25.10.2015 02:50:00
Michael Mairegger
  • 6,833
  • 28
  • 41
0

You can use the TimeZoneInfo to perform the calculation but you need to use DateTimeOffset instead of DateTime. This also solves the ambiguity of the timestamp 2015-10-25 02:20:00 that occurs twice. By including the offset in the timestamp you know that the timestamp describes the point in time before the DST change:

var date = new DateTimeOffset(2015, 10, 25, 2, 20, 0, TimeSpan.FromHours(2));

I assume that you are in a European time zone with offset +01:00 and +02:00 during daylight savings. Normally, you will create this timestamp by calling DateTimeOffset.Now at that specific time but here I create the timestamp manually and I have to specify the UTC offset.

You can now compute the new timestamp 50 minutes ahead:

Console.WriteLine(TimeZoneInfo.ConvertTime(date.AddMinutes(50), TimeZoneInfo.Local));

The output is:

25-10-2015 02:10:00 +01:00
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256