1

What I want to do is have a user enter a date and have a class that returns the last day of the month. So, I've put this in my class module:

public static class StringExtensions
{
    public static DateTime LastDayOfMonth(DateTime MyDate)
    {
        DateTime today = MyDate;
        DateTime EOM = new DateTime(today.Year,today.Month,
                           DateTime.DaysInMonth(today.Year,
                           today.Month));
            return EOM;
    }
}

In my code-behind, I have this:

DateTime LDOM = StringExtensions.LastDayOfMonth(txtCIT.Text);

I've also tried hard-coding a date like:

DateTime LDOM = StringExtensions.LastDayOfMonth('1/12/2016');

I'm getting these errors:

Error 14 The best overloaded method match for 'ClientDPL.StringExtensions.LastDayOfMonth(System.DateTime)' has some invalid arguments

and

Error 15 Argument 1: cannot convert from 'string' to 'System.DateTime'

Can anyone see what I'm doing wrong?

D Stanley
  • 149,601
  • 11
  • 178
  • 240
Johnny Bones
  • 8,786
  • 7
  • 52
  • 117
  • 2
    If you're going to put it in a class called StringExtensions, there's an expectation that it's an [extension method](https://msdn.microsoft.com/en-us/library/bb383977.aspx) and that it accepts a string as the first parameter. Your method doesn't do either of these. – mason Feb 05 '16 at 19:19
  • 1
    Are you sure you're using single quotes in the second example? If you were you'd get an error about too many characters in character literal. – juharr Feb 05 '16 at 19:27

4 Answers4

4

You are trying to pass String argument to the method that need a DateTime argument. Then you need parse your value first:

var textCitValue = DateTime.Parse(txtCIT.Text);
DateTime LDOM = StringExtensions.LastDayOfMonth(textCitValue);

The better way is to use safe method DateTime.TryParse that will never throws an exception

DateTime textCitDateTime;
if(DateTime.TryParse(txtCIT.Text, out textCitDateTime))
{
    DateTime LDOM = StringExtensions.LastDayOfMonth(textCitValue);
    // your logic here
}
else
{
    // handle invalid textbox date here
}

Also, you have unclear naming. Your StringExtensions class has a method that is not an extension method and uses DateTime as a parameter. It'll be better to rename your class and change LastDayOfMonth signature like next:

public static class DateTimeExtensions
{
    public static DateTime LastDayOfMonth(this DateTime date) { ... }
}

Then you can call this method to as a DateTime public instance method:

DateTime LDOM = textCitValue.LastDayOfMonth();

You can also change method signature to public static DateTime LastDayOfMonth(string date) but it will break single responsibility principle for your method.

Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
  • 3
    Alternatively, `LastDayOfMonth()` can be changed to accept a `string` argument and then the logic you show here can be encapsulated in that method. – Code-Apprentice Feb 05 '16 at 19:16
  • 1
    @Code-Apprentice yes it can, but then `LastDayOfMonth()` will handle only one format of input string (or we will need to add extra parameter with formatting). Now it encapsulates exactly one task and has a single responsibility. – Vadim Martynov Feb 05 '16 at 19:22
  • I'm unclear how `LastDayOfMonth()` will handle only one format. You make a good point about single responsibility. My suggestion probably breaks this. – Code-Apprentice Feb 05 '16 at 19:26
  • @Code-Apprentice What Vadim means is that if it takes a string and then parses it to a `DateTime` the method would need to know the format vs. letting the format be determined by the caller before passing a parsed `DateTime`. – juharr Feb 05 '16 at 19:30
  • @juharr well in one isolated case it's no sense. But in the different parts of application we may need to call `LastDayOfMonth()` with different date formats or for DateTime object. Nowthequestion is: "What actually should LastDayOfMount does?". Method name and SOLID principles tells that DateTime is better candidate to input parameter. – Vadim Martynov Feb 05 '16 at 19:44
3

Your method is expecting a parameter of DateTime.

In your calls:

DateTime LDOM = StringExtensions.LastDayOfMonth(txtCIT.Text);

and

DateTime LDOM = StringExtensions.LastDayOfMonth('1/12/2016');

in both cases you're not passing a DateTime. You need to convert your string to a DateTime prior to calling the function.

Lots of methods of doing that here: Converting a String to DateTime

Community
  • 1
  • 1
Kritner
  • 13,557
  • 10
  • 46
  • 72
1

As @mason pointed out in comment, a probably better way to do it would be to use a DateTime extension method similar to:

public static class DateTimeExtensions
{
    public static DateTime LastDayOfMonth(this DateTime date)
    {
        DateTime EOM = new DateTime(
            date.Year,date.Month,
            DateTime.DaysInMonth(
                date.Year,
                date.Month
            )
        );

        return EOM;
    }
}

Can be used like:

Console.WriteLine(DateTime.Now.LastDayOfMonth());

See it in action at:

https://dotnetfiddle.net/59Oj7c

Kritner
  • 13,557
  • 10
  • 46
  • 72
  • All the answers here were great and useful, but I ended up using this one so I'll give the checkmark here. I may explore Vadim's TryParse idea at a later date. – Johnny Bones Feb 15 '16 at 20:37
1

Hope I'm not just re-stating the question by presenting this answer and apologize in advance, but I would be more privy to just declaring extensions for both types along the lines of the following (note the Nullable return type denoted by the question mark):

public static class StringExtensions
{
    public static DateTime LastDayOfMonth(this DateTime self)
    {
        return new DateTime(self.Year, self.Month, DateTime.DaysInMonth(self.Year, self.Month));
    }

    public static DateTime? LastDayOfMonth(this string self)
    {
        DateTime dt;
        if (!DateTime.TryParse(self, out dt))
            return null;

        return dt.LastDayOfMonth();
    }
}

Then to use it in code:

private void App()
{
    var lastDayFromDate = (DateTime.Now).LastDayOfMonth();
    var lastDayFromString = "1/12/2016".LastDayOfMonth();

    if (lastDayFromString != null)
    {

    }
}
Matt Borja
  • 1,509
  • 1
  • 17
  • 38
  • For the first method, the one with `DateTime`, there is no need to return a Nullable `DateTime`: if will never return null. I would declare it with a regular `DateTime` return value, so client code will not need to check "if it's not null" – Gian Paolo Feb 05 '16 at 21:33
  • @GianPaolo Right you are :) – Matt Borja Feb 07 '16 at 00:59