Code Listings

Chapter 6: Framework Fundamentals

Using TimeZoneInfo:

static void Main()
{
  TimeZoneInfo wa = TimeZoneInfo.FindSystemTimeZoneById
                    ("W. Australia Standard Time");

  Console.WriteLine (wa.Id);                   // W. Australia Standard Time
  Console.WriteLine (wa.DisplayName);          // (GMT+08:00) Perth
  Console.WriteLine (wa.BaseUtcOffset);        // 08:00:00
  Console.WriteLine (wa.SupportsDaylightSavingTime);     // True

  foreach (TimeZoneInfo.AdjustmentRule rule in wa.GetAdjustmentRules())
  {
    Console.WriteLine ("Rule: applies from " + rule.DateStart +
                                      " to " + rule.DateEnd);
  
    Console.WriteLine ("   Delta: " + rule.DaylightDelta);  

    Console.WriteLine ("   Start: " + FormatTransitionTime
                                     (rule.DaylightTransitionStart, false));

    Console.WriteLine ("   End:   " + FormatTransitionTime
                                     (rule.DaylightTransitionEnd, true));
    Console.WriteLine();
  }
}

static string FormatTransitionTime (TimeZoneInfo.TransitionTime tt,
                                    bool endTime)
{
  if (endTime && tt.IsFixedDateRule 
              && tt.Day == 1 && tt.Month == 1 
              && tt.TimeOfDay == DateTime.MinValue)
    return "-";

  string s;
  if (tt.IsFixedDateRule)
    s = tt.Day.ToString();
  else
    s = "The " +
        "first second third fourth last".Split() [tt.Week - 1] +
        " " + tt.DayOfWeek + " in";

  return s + " " + DateTimeFormatInfo.CurrentInfo.MonthNames [tt.Month-1]
           + " at " + tt.TimeOfDay.TimeOfDay;
}

DateTime and daylight saving:

DaylightTime changes = TimeZone.CurrentTimeZone.GetDaylightChanges (2008);
TimeSpan halfDelta = new TimeSpan (changes.Delta.Ticks / 2);

DateTime utc1 = changes.End.ToUniversalTime() - halfDelta;
DateTime utc2 = utc1 - changes.Delta;

// Converting these variables to local times demonstrates why you should use
// UTC and not local time if your code relies on time moving forward:

DateTime loc1 = utc1.ToLocalTime();  // (Pacific Standard Time)
DateTime loc2 = utc2.ToLocalTime(); 
Console.WriteLine (loc1);            // 2/11/2008 1:30:00 AM
Console.WriteLine (loc2);            // 2/11/2008 1:30:00 AM
Console.WriteLine (loc1 == loc2);    // True

Console.Write (loc1.ToString ("o"));  // 2008-11-02T02:30:00.0000000-08:00
Console.Write (loc2.ToString ("o"));  // 2008-11-02T02:30:00.0000000-07:00

Console.WriteLine (loc1.ToUniversalTime() == utc1);   // True
Console.WriteLine (loc2.ToUniversalTime() == utc2);   // True

Writing a custom format provider:

public class WordyFormatProvider : IFormatProvider, ICustomFormatter
{
  static readonly string[] _numberWords =
   "zero one two three four five six seven eight nine minus point".Split();

  IFormatProvider _parent;   // Allows consumers to chain format providers

  public WordyFormatProvider() : this (CultureInfo.CurrentCulture) { }
  public WordyFormatProvider (IFormatProvider parent)
  {
    _parent = parent;
  }

  public object GetFormat (Type formatType)
  {
    if (formatType == typeof (ICustomFormatter)) return this;
    return null;
  }

  public string Format (string format, object arg, IFormatProvider prov)
  {
    // If it's not our format string, defer to the parent provider:
    if (arg == null || format != "W")
      return string.Format (_parent, "{0:" + format + "}", arg);

    StringBuilder result = new StringBuilder();
    string digitList = string.Format (CultureInfo.InvariantCulture,
                                      "{0}", arg);
    foreach (char digit in digitList)
    {
      int i = "0123456789-.".IndexOf (digit);
      if (i == -1) continue;
      if (result.Length > 0) result.Append (' ');
      result.Append (_numberWords[i]);
    }
    return result.ToString();
  }
}

Overriding equality semantics:

public struct Area : IEquatable <Area>
{
  public readonly int Measure1;
  public readonly int Measure2;

  public Area (int m1, int m2)
  {
    Measure1 = m1;
    Measure2 = m2;
  }

  public override bool Equals (object other)
  {
    if (!(other is Area)) return false;
    return Equals ((Area) other);        // Calls method below
  }

  public bool Equals (Area other)        // Implements IEquatable<Area>
  {
    return Measure1 == other.Measure1 && Measure2 == other.Measure2
        || Measure1 == other.Measure2 && Measure2 == other.Measure1;
  }

  public override int GetHashCode()
  {
    if (Measure1 > Measure2)
      return Measure1 * 37 + Measure2;    // 37 = a prime number
    else
      return Measure2 * 37 + Measure1;
  }

  public static bool operator == (Area a1, Area a2)
  {
     return a1.Equals (a2);
  }

  public static bool operator != (Area a1, Area a2)
  {
    return !a1.Equals (a2);
  }
}

Implementing the IComparable interfaces:

public struct Note : IComparable<Note>, IEquatable<Note>, IComparable
{
  int _semitonesFromA;

  public Note (int semitonesFromA)
  {
    _semitonesFromA = semitonesFromA;
  }

  public int CompareTo (Note other)            // Generic IComparable<T>
  {
    if (Equals (other)) return 0;              // Fail-safe check
    return _semitonesFromA.CompareTo (other._semitonesFromA);
  }

  int IComparable.CompareTo (object other)     // Nongeneric IComparable
  {
    if (!(other is Note))
      throw new InvalidOperationException ("CompareTo: Not a note");
    return CompareTo ((Note) other);
  }

  public static bool operator < (Note n1, Note n2)
  {
     return n1.CompareTo (n2) < 0;
  }

  public static bool operator > (Note n1, Note n2)
  {
    return n1.CompareTo (n2) > 0;
  }

  public bool Equals (Note other)    // for IEquatable<Note>
  {
    return _semitonesFromA == other._semitonesFromA;
  }

  public override bool Equals (object other)
  {
    if (!(other is Note)) return false;
    return Equals ((Note) other);
  }

  public override int GetHashCode()
  {
    return _semitonesFromA.GetHashCode();
  }

  public static bool operator == (Note n1, Note n2)
  {
     return n1.Equals (n2);
  }

  public static bool operator != (Note n1, Note n2)
  {
     return !(n1 == n2);
  }
}

© 2007, O'Reilly Media, Inc. All rights reserved

C# 3.0 in a Nutshell
Buy from amazon.com Available now