Wednesday, January 18, 2006

.NET DateTime Format String

You can display a DateTime with custom format using DateTime.ToString() or String.Format() methods in .NET. The custom format string follows a set of naming convention such as y for year, M for month, d for day, h for hour 12, m for minute, s for second, and z for time zone. Let's create a simple ASP.NET page to exam the DateTime format string:

    public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string dtString = string.Empty;
DateTime dt = DateTime.Now;
StringBuilder sb = new StringBuilder();
sb.Append("y yy yyy yyyy \t--- (Year) " + dt.ToString("y yy yyy yyyy") + "<br>");
sb.Append("M MM MMM MMMM \t--- (Month) " + dt.ToString("M MM MMM MMMM") + "<br>");
sb.Append("d dd ddd dddd \t--- (Day) " + dt.ToString("d dd ddd dddd") + "<br>");
sb.Append("h hh H HH \t--- (Hour) " + dt.ToString("h hh H HH") + "<br>");
sb.Append("m mm \t\t--- (Minute) " + dt.ToString("m mm") + "<br>");
sb.Append("z zz zzz \t--- (Zone) " + dt.ToString("z zz zzz") + "<br>");

sb.Append("d \t--- " + dt.ToString("d") + "<br>");
sb.Append("D \t--- " + dt.ToString("D") + "<br>");
sb.Append("f \t--- " + dt.ToString("f") + "<br>");
sb.Append("F \t--- " + dt.ToString("F") + "<br>");
sb.Append("g \t--- " + dt.ToString("g") + "<br>");
sb.Append("G \t--- " + dt.ToString("G") + "<br>");
sb.Append("m \t--- " + dt.ToString("m") + "<br>");
sb.Append("r \t--- " + dt.ToString("r") + "<br>");
sb.Append("s \t--- " + dt.ToString("s") + "<br>");
sb.Append("u \t--- " + dt.ToString("u") + "<br>");
sb.Append("U \t--- " + dt.ToString("U") + "<br>");
sb.Append("y \t--- " + dt.ToString("y") + "<br>");

sb.Append("yyyy-MM-dd \t\t--- " + dt.ToString("yyyy-MM-dd") + "<br>");
sb.Append("yyyy-MM-dd HH:mm \t--- " + dt.ToString("yyyy-MM-dd HH:mm") + "<br>");
sb.Append("yyyy-MM-dd HH:mm:ss \t--- " + dt.ToString("yyyy-MM-dd HH:mm:ss") + "<br>");
sb.Append("yyyy-MM-dd HH:mm tt \t--- " + dt.ToString("yyyy-MM-dd HH:mm tt") + "<br>");
sb.Append("yyyy-MM-dd H:mm \t--- " + dt.ToString("yyyy-MM-dd H:mm") + "<br>");
sb.Append("yyyy-MM-dd h:mm \t--- " + dt.ToString("yyyy-MM-dd h:mm") + "<br>");
sb.Append("ddd, dd MMM yyyy HH:mm \t--- " + dt.ToString("ddd, dd MMM yyyy HH:mm") + "<br>");
sb.Append("dddd, dd MMMM yyyy HH:mm \t--- " + dt.ToString("dddd, dd MMMM yyyy HH:mm") + "<br>");

lblDateTimeFormat.Text = sb.ToString();
}
}
Result:
y yy yyy yyyy  --- (Year) 6 06 2006 2006
M MM MMM MMMM --- (Month) 1 01 Jan January
d dd ddd dddd --- (Day) 18 18 Wed Wednesday
h hh H HH --- (Hour) 9 09 21 21
m mm --- (Minute) 12 12
z zz zzz --- (Zone) -5 -05 -05:00
d --- 1/18/2006
D --- Wednesday, January 18, 2006
f --- Wednesday, January 18, 2006 9:12 PM
F --- Wednesday, January 18, 2006 9:12:36 PM
g --- 1/18/2006 9:12 PM
G --- 1/18/2006 9:12:36 PM
m --- January 18
r --- Wed, 18 Jan 2006 21:12:36 GMT
s --- 2006-01-18T21:12:36
u --- 2006-01-18 21:12:36Z
U --- Thursday, January 19, 2006 2:12:36 AM
y --- January, 2006
yyyy-MM-dd --- 2006-01-18
yyyy-MM-dd HH:mm --- 2006-01-18 21:12
yyyy-MM-dd HH:mm:ss --- 2006-01-18 21:12:36
yyyy-MM-dd HH:mm tt --- 2006-01-18 21:12 PM
yyyy-MM-dd H:mm --- 2006-01-18 21:12
yyyy-MM-dd h:mm --- 2006-01-18 9:12
ddd, dd MMM yyyy HH:mm --- Wed, 18 Jan 2006 21:12
dddd, dd MMMM yyyy HH:mm --- Wednesday, 18 January 2006 21:12
In reality a DateTime value is often passed through with a formatted string, and is converted back to DateTime at some point. The safest way for parsing a DateTime string is using the TryParseExact method:
string dtString = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
DateTime curDate;
DateTime.TryParseExact(dtString, "yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.None, out curDate);

Thursday, January 12, 2006

.NET 2.0 Yield Usage

The .NET equivalent of Java Iterator is called Enumerators. Enumerators are a collection of objects which provide "cursor" behavior moving through an ordered list of items one at a time. Enumerator objects can be easily looped through by using "foreach" statement in .NET.

Actually .NET framework provides two interfaces relating to Enumerators: IEnumerator and IEnumerable. IEnumerator classes implement three interfaces, and IEnumerable classes simply provide enumerators when a request is made to their GetEnumerator method:
namespace System.Collections
{
    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

    public interface IEnumerator
    {
        object Current { get; }
        bool MoveNext();
        void Reset();
    }
}

.NET 2.0 introduces "yield" keyword to simplify the implementation of Enumerators. With yield keyword defined, compiler will generate the plumbing code on the fly to facilitate the Enumerators functions. Following example demos how to use "yield" in C#:
using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    public class OddNumberEnumerator : IEnumerable
    {
        int _maximum;
        public OddNumberEnumerator(int max)
        {
            _maximum = max;
        }

        public IEnumerator GetEnumerator()
        {
            Console.WriteLine("Start Enumeration...");
            for (int number = 1; number < _maximum; number++)
            {
                if (number % 2 != 0)
                    yield return number;
            }
            Console.WriteLine("End Enumeration...");
        }

        public static IEnumerable<int> GetOddNumbers(IEnumerable<int> numbers)
        {
            Console.WriteLine("Start GetOddNumbers Method...");
            foreach (int number in numbers)
            {
                if (number % 2 != 0)
                    yield return number;
            }
            Console.WriteLine("End GetOddNumbers Method...");
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            OddNumberEnumerator oddNumbers = new OddNumberEnumerator(10);
            Console.WriteLine("Loop through odd number under 10:");
            foreach (int number in oddNumbers)
            {
                Console.WriteLine(number);
            }

            Console.WriteLine();
            int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            Console.WriteLine("Using method with yield return:");

            foreach (int number in OddNumberEnumerator.GetOddNumbers(numbers))
            {
                Console.WriteLine(number);
            }
            Console.ReadLine();
        }
    }
}
Result:


Notice we are using two approaches to loop through odd numbers. In the first approach where "yield return" is used in IEnumerable.GetEnumerator, there's no space allocated to hold the odd numbers, and they are all generated on the fly, which is very efficient when dealing with a large list of items (think about if we want to print out or save all 32-bit odd numbers in our example).