views:

209

answers:

8

I have got a very simple function that takes anything in as an object, but generally a string, and attempts to format it in a specific date format that we use for reports at work.

The function is generally called using the OnRowDataBound event of a GridView and returns the date as a string if it could parse it or the original input as a string.

Here is the function:

public string FormatDate(object input)
{
    DateTime output;

    return DateTime.TryParse(input.ToString(), out output)
        ? output.ToString("dd-MMM") : input.ToString();
}

Maybe I am being picky but the issue I have is the creation of a variable, in this case a DateTime object called output, which is created purely for the output of the TryParse function which I then convert to string in the format I specify.

Is there a better, more concise method of doing this?

+2  A: 

I don't see what the purpose would be. Any more concise than that and it'd be difficult to read. That said, if you switched to DateTime.Parse you could just return that outright. Of course, then you would have to worry about the exception if it failed.

Ari Roth
+2  A: 

I'm afraid not, since it's an out parameter and the variable will have to be declared on the stack. I'm a little surprised by your code though, if you get a date you format it, and if the parsing fails you just display the string as-is?

Yann Schwartz
That seems like sensible default behavior to me
Gabe Moothart
I actually kind of like the approach; in the best case the user gets the data in the preferred format, in the worst case the user gets to see something else that may very well still make sense to him/her.
Fredrik Mörk
I'm not saying it's wrong, just wondering aloud. I can see the point. Maybe it should display the original string with some visual cue that it wasn't parsed all right.
Yann Schwartz
Agreed. Regarding the code: As a caller of that public method, I certainly expect a modified representation of the date - or an error of some kind (null, perhaps). Returning the provided value has its place, but I'd somehow indicate that possibility in the name of the method.
lance
Thanks Yann. The input is more than likely going to be a date format it can parse but as it is a user inputted field I could end up with all sorts which is why I am just going to return it as-is if all attempts to parse it fail.
Ian Roke
@lance I could call it FormatDateOrJustReturnAsIs() but I already know that will happen as it is something I tend to do for all GridView formatting.
Ian Roke
+2  A: 

You can't get away from the extra variable instantiation, but you can hide it with a helper method:

public static string DateTimeParseOrDefault(this object input, string format, string def) {
    DateTime output;
    return DateTime.TryParse(input.ToString(), out output)
        ? output.ToString(format)
        : def;
}

Which you then call in your function as:

public string FormatDate(object input) {
    return input.DateTimeParseOfDefault("dd-MMM", input.ToString());
}

You'll probably want to rename that goofy function name, or perhaps not use an extension method (just a regular static method) - but it's up to you at this point. Again all you're doing here is hiding the variable.

Erik Forbes
A: 

Roll that logic into your tryParse method, so it returns the correct thing right away. Right now TryParse returns a boolean. Why can't it just return the final string value? Maybe you can create an overridden or overloaded version of it if you need to.

Mike Pone
It's not his TryParse method - it's the library's static TryParse method on the built-in DateTime type.
Erik Forbes
@Erik - I think Mike was referring to me overriding the TryParse() method with my own version. That is possible... right?
Ian Roke
Using the definition of 'overriding' - no, it's not possible - DateTime is Sealed, and so cannot be derived from. If you mean you'd like to write a different version of TryParse on some other object, then of course you're free to do so - but you'd have to duplicate all the logic that TryParse implements, and you'd have to call it in a different fashion than you are.
Erik Forbes
+4  A: 

Since the DateTime.TryParse() function requires the output variable, I don't see a way to get around creating the output variable there...

You could use the Parse() function instead with a try, catch... I'm not a big fan of this in general and try to avoid this type of stuff...

    try
    {
        this.label1.Text = DateTime.Parse(this.textBox1.Text).ToString("dd-MMM");
    }
    catch (FormatException)
    {
        this.label1.Text = this.textBox1.Text;
    }

EDIT
Erik had a good point, in catching the specific exception. It was a code sample which is why I left it at Exception. Use FormatException if you use this...

RSolberg
Eek - bad! At least catch the proper exception - this thing will catch Threading exceptions, Out of memory exceptions, etc etc...
Erik Forbes
@Erik - Read my comment directly above the code sample... And then realize its only a sample!
RSolberg
I realize it's a sample - but it's worth saying nonetheless.
Erik Forbes
@Erik - Does that look better :)
RSolberg
Expection handling :-)
Bryan Watts
Yes, thanks. :) Either way this is technically bad form (using exceptions for program flow control) - but it would prevent the extra variable, thus answering the OP's original question.
Erik Forbes
@Erik: I agree completely. I don't typically write code like this and would just create the variable, but since the OP didn't want the variable, this seemed viable....
RSolberg
@RSolberg - +1 because this does provide another alternative to what I currently do.
Ian Roke
A: 

I don't think there is.

remember the TryParse is communicating 2 results (1.did the parse succeed and 2. the datetime value if it did), but has only one return value.

Using Parse would make you deal with the exception. You can save the input.ToString, it's already a string.

automatic
+2  A: 

You are referencing output in two places. How could it not be a variable?

I'd be more worried about the exceptions which will happen when someone passes a null value for input.

Also, since your method explicitly works with string only, you should communicate that in your API by accepting a string instead of an object. Let the caller of the method determine how they would like to supply the string instance.

Bryan Watts
+2  A: 

First, I see a problem with the method name. It is called 'FormatDate(...)' I would expect the parameter to be a DateTime field. Taking in an object type makes the method harder to understand. With out knowing the code/implementation I wouldn't know what I would get back if I sent it an ArrayList object or a Person object. There isn't a logical answer. I think rewritting the method to Format a Date and only taking in a DateTime object makes the method clear and eliminates all of the variables.

public string FormatDate(DateTime date) 
{    
    return date.ToString("dd-MMM")
}

Look into "Working Classes" in Code Complete 2 by Steve McConnell. He discusses this with Chaper 6 I belive.

sgmeyer
I would agree however I am passing a date value from the GridView which is normally a string but I am sending the reference to the cell too so I can return the formatted date as a string.
Ian Roke
+1 for the best read of the very first line of Ian's function (the signature).
azheglov
Ok, thinking of Single Responsibility Pricipal (SRP) you wouldn't want a function that converted a GridView's Cell value and then formatting it. You might try to create a function that called FindDateTime(...) then pass that value into the function FormatDate(...)
sgmeyer