38

I have the following code in an ASP.NET MVC3 Controller:

public PartialViewResult GetCalendar(int? month, int? year)
    {
        var test = new DateTime((year.HasValue ? year.Value : 1), (month.HasValue ? month.Value : 1), 1);
        return PartialView("Calendar", new DateTimeOffset(test));
    }

My view model is DateTimeOffset?

What is the reason for the exception thrown?

Babu James
  • 2,740
  • 4
  • 33
  • 50

4 Answers4

65

The DateTimeOffset constructor first converts any DateTime that is not of Kind 'UTC' to the equivalent UTC time. It will then check whether the UTC-equivalent DateTime falls outside of the bounds of DateTimeOffset.MinValue and DateTimeOffset.MaxValue, and if it does, will throw an ArgumentOutOfRangeException similar to the one you are experiencing.

Check the DateTime.Kind of the variable test that you are using, and if it is not 'UTC', work out if a conversion to UTC will make the DateTime specified by test fall outside of those bounds - according to the MSDN documentation, the MinValue and MaxValue (in UTC) are '1/1/0001 12:00:00 AM +00:00' and '12/31/9999 11:59:59 PM +00:00' respectively.

The docs (DateTimeOffset.MinValue) note that:

"Any DateTimeOffset value is converted to Coordinated Universal Time (UTC) before the method performs the comparison with MinValue. This means that a DateTimeOffset value whose date and time are close to the minimum range, but whose offset is positive, may throw an exception. For example, the value 1/1/0001 1:00:00 AM +02:00 is out of range because it is one hour earlier than MinValue when it is converted to UTC."

And also (DateTimeOffset.MaxValue):

"Any DateTimeOffset value is converted to Coordinated Universal Time (UTC) before the method compares it with MaxValue. This means that a DateTimeOffset value whose date and time are close to the maximum range, but whose offset is negative, may throw an exception. For example, the value 12/31/9999 11:00 PM -02:00 is out of range because it is one hour later than MaxValue when it is converted to UTC."

And as per the docs (DateTimeOffset Constructor), the offset that is applied to a non-UTC Kind is the "offset of the local system's current time zone".

Chamila Chulatunga
  • 4,856
  • 15
  • 17
  • 1
    I don't know why it's not working, finally I solved it by changing the model to DateTime? – Babu James Dec 10 '12 at 11:17
  • 13
    Like chamila said, it fails because the date is outside the range allowed. `new DateTimeOffset(DateTime.MinValue)` will fail on any computer with a timezone that is ahead of UTC (positive offset), and `new DateTimeOffset(DateTime.MaxValue)` will fail on any computer with a timezone that is behind UTC (negative offset). – Matt Johnson-Pint Jan 24 '13 at 00:21
  • 1
    Part of the problem is MinValue/MaxValue have DateTimeKind = unspecified. If you convert them to UTC, it works. var x1 = new DateTimeOffset(DateTime.MaxValue.ToUniversalTime()); var x2 = new DateTimeOffset(DateTime.MinValue.ToUniversalTime()); – Mike S Oct 05 '16 at 17:06
18

I just had this issue, introduced by the part of my team that's on a negative UTC zone...

What chamila_c posted is the real reason why this happens, but I needed a quick fix.

To "solve it" I basically created this extension:

public static class DateTimeExtensions
{
    public static DateTimeOffset ToDateTimeOffset(this DateTime dateTime)
    {
        return dateTime.ToUniversalTime() <= DateTimeOffset.MinValue.UtcDateTime
                   ? DateTimeOffset.MinValue 
                   : new DateTimeOffset(dateTime);
    }
}

you might also want to check against the MaxValue.

fbiagi
  • 766
  • 6
  • 11
5

If the data type you are dealing with is a DateTime, you should create a DateTime object specifying the Kind.

DateTime maxDate = DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.UTC);

When this converts to the DateTimeOffset data type, you will not get that error.

Mestaris
  • 71
  • 1
  • 5
2

This can happen during Azure Function development when you set a timer trigger schedule in function.json so it never runs, like this:

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
        "name": "mytimer",
        "type": "timerTrigger",
        "direction": "in",
        "schedule": "0 0 0 31 2 *"
    }
  ]
}

... where I have set this to run on February 31st (that is, never.) Apparently "never" is outside the allowable date range. Solution is to be less tricky and just set a real date in the far future:

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
        "name": "mytimer",
        "type": "timerTrigger",
        "direction": "in",
        "schedule": "0 0 0 1 1 * "
    }
  ]
}

(Run once on January 1st, won't run until next year.)

Again, credit to Chamila Chulatunga for describing the root of the problem.

Tom Wilson
  • 797
  • 9
  • 26