danielwertheim

danielwertheim


notes from a passionate developer

Developer that lives by the mantra "code is meant to be shared".

Share


Tags


Disclaimer

This is a personal blog. The opinions expressed here represent my own and not those of my employer, nor current or previous. All content is published "as is", without warranty of any kind and I don't take any responsibility and can't be liable for any claims, damages or other liabilities that might be caused by the content.

C#, Custom Date and Time Format Strings - with semantics

Daniel WertheimDaniel Wertheim

When it comes to formatting dates and time strings, people seem to forget (I don't blame them) and mixes up stuff like M vs m; which one is months and which one is minutes? And how many characters was it to get abbreviation instead of month number? I took a few minutes, violated some principles and put together a simple fluent API with semantic meanings in the formating process. Now, it will not cover everything, but you will get the idea.

Lets have a look at how you can put it to use:

static void Main(string[] args)  
{
    var f = F.Date
             .Year().And()
             .Month().And()
             .Day()
             .Time.Hour().And()
             .Minute();
    var s = DateTime.Now.ToString(f, CultureInfo.InvariantCulture);
    Console.WriteLine(s);
}

yields

=> 2014-03-18 19:07

Now, I have set some defaults here, so the TimeFormat class, returned by the final Minute() call, will return: yyyy-MM-dd HH:mm.

Lets say I would like to have something like: 18-Mar, 2014 19:07, you would then consume it like this:

var f = F.Date  
         .Day().And()
         .Month(m => m.Abbreviation).And(',')
         .Year()
         .Time.Hour().And()
         .Minute();

which produces the format: dd-MMM, yyyy HH:mm.

Again, just a simple example put together in a hurry. The point is that you can put semantics into plumbing code as well.

Cheers,

//Daniel


public static class F  
{
  public class Year
  {
    public static class As
    {
      public const int Century = 4;
      public const int Decade = 2;
      public const int Single = 1;
    }

    private static readonly Lazy<Year> InstanceFn = 
        new Lazy<Year>(() => new Year());

    public static Year Instance { get { return InstanceFn.Value; } }

    private Year() { }

    public int Century { get { return As.Century; } }
    public int Decade { get { return As.Decade; } }
    public int Single { get { return As.Single; } }
  }

  public class Month
  {
    public static class As
    {
      public const int Full = 4;
      public const int Abbreviation = 3;
      public const int Number = 2;
      public const int Single = 1;
    }

    private static readonly Lazy<Month> InstanceFn = 
        new Lazy<Month>(() => new Month());

    public static Month Instance { get { return InstanceFn.Value; } }

    private Month() { }

    public int Full { get { return As.Full; } }
    public int Abbreviation { get { return As.Abbreviation; } }
    public int Number { get { return As.Number; } }
    public int Single { get { return As.Single; } }
  }

  public static DateFormat Date { get{return new DateFormat();}}

  public static TimeFormat Time { get { return new TimeFormat(); } }
}

public class DateFormat  
{
  private readonly StringBuilder _value;

  public TimeFormat Time
  {
    get
    {
      _value.Append(" ");
      return new TimeFormat(_value);
    }
  }

  public DateFormat(StringBuilder value = null)
  {
    _value = value ?? new StringBuilder();
  }

  public DateFormat And(string s = null)
  {
    _value.Append(s ?? "-");
    return this;
  }

  public DateFormat Year(Func<F.Year, int> f)
  {
    return Year(f(F.Year.Instance));
  }

  public DateFormat Year(int i = 4)
  {
    _value.Append('y', i);
    return this;
  }

  public DateFormat Month(Func<F.Month, int> f)
  {
    return Month(f(F.Month.Instance));
  }

  public DateFormat Month(int i = 2)
  {
    _value.Append('M', i);
    return this;
  }

  public DateFormat Day(int i = 2)
  {
    _value.Append('d', i);
    return this;
  }

  public static implicit operator string(DateFormat item)
  {
    return item._value.ToString();
  }

  public override string ToString()
  {
    return _value.ToString();
  }
}

public class TimeFormat  
{
  private readonly StringBuilder _value;

  public DateFormat Time
  {
    get
    {
      _value.Append(" ");
      return new DateFormat(_value);
    }
  }

  public TimeFormat(StringBuilder value = null)
  {
    _value = value ?? new StringBuilder();
  }

  public TimeFormat And(string s = null)
  {
    _value.Append(s ?? ":");
    return this;
  }

  public TimeFormat Hour()
  {
    _value.Append("HH");
    return this;
  }

  public TimeFormat Minute()
  {
    _value.Append("mm");
    return this;
  }

  public static implicit operator string(TimeFormat item)
  {
    return item._value.ToString();
  }

  public override string ToString()
  {
    return _value.ToString();
  }
}

Developer that lives by the mantra "code is meant to be shared".

Comments