Thứ Ba, 18 tháng 1, 2011

Exchange log disk is full, Prevention and Remedies

Exchange log disk is full, Prevention and Remedies
We would like to extend a warm welcome to Microsoft MVP Erik Rozman to our team of authors as he presents his first article to MSExchange.org readers. In the following document I will describe preventive measures that should help you avoid running out of disk space and in addition I will also describe possible remedies if this has (gasp) already happened.


* Published: Jan 13, 2005
* Updated: Jan 13, 2005
* Section: Planning & Architecture
* Author: Erik Rozman
* Printable Version
* Adjust font size: + -
* Rating: 4.7/5 - 206 Votes

* 1
* 2
* 3
* 4
* 5

AddThis

I find Exchange server to be a very complicated system and as in most complicated systems the most "trivial things" may bring it to its knees. One of these "trivial things" is lack of disk space on the disk that holds the log files for a specific storage group. When the Information Store identifies lack of disk space for a storage group's logs it will dismount the stores inside the respective storage group.

The last sentence I wrote may sound very calm yet when this happens on one of the Exchange servers you are responsible for you will be anything but calm. Once the stores in the storage group are dismounted, users are disconnected from their precious information (mail, calendars, contacts…) and they will come waving pitchforks…

Before we delve into our main subjects I think it is important to understand the exact role that log files have.
Describing the Exchange storage system

A very oversimplified analysis of an Exchange server may state that that an Exchange server is nothing more then a database server that has some exotic extensions through which users can manipulate their data. This analysis (even though oversimplified) is not far from truth, and it emphasizes the importance of the database that stores the user's information on an Exchange server.

Exchange server uses a database technology called ESE (Extensible Storage Engine), this database technology is based on the JET (Joint Engine Technology) database engine.

The ESE engine employs several files upon which the database is built (I have only specified the ones that are relevant to our topic):

1. Store files- The store files hold the information that is already committed to disk. Each Exchange store (Private and Public) consists of two files:
1. EDB- Rich-text database stores information in a proprietary format called Microsoft Database Encapsulated Format (MDBEF) that is submitted by MAPI clients.
2. STM- Native Content Database holds all data that is submitted by non-MAPI clients.
2. Transaction Log files- the log file stores altered data before it is committed to the database. A set of log files is unique to a storage group. The log files name begins with a prefix that identifies the storage group they belong to- E00XXXXX.log (belongs to the first storage group). The suffix for each log files name is a hexadecimal sequentially assigned number.
The active log file for a specific storage group is always called: EX0.log (X represents the storage group), once it is filled (5MB) it is renamed using the next sequential hexadecimal number and a new EX0.log is created. Since by default log files are not erased (by default storage groups do not use circular logging) the space on a log disk will eventually be depleted. The standard procedure for removing unused log files is backing the system up (full or incremental).
As mentioned earlier the size of a log file is 5120KB, if you find that the size of the files is different you may be looking at a corrupt log file.
Each set of log files has two placeholder files called: res1.log and res2.log. These files are used by the storage group when it runs out of disk space to store altered information before dismounting the storage group.
3. Checkpoint File- The checkpoint file is used to track which transactions have been committed to the database and which transactions have to be committed to the database. The name of the file is EX0.chk (X stands for the storage group) and its size is 8KB.

Using the files described above the ESE engine builds a transactional database. You may have noticed that during the description of the checkpoint file I mentioned transactions without explaining their essence, so to repay this debt here we go: a transaction is a set of commands that are regarded as one logical unit- they must all succeed or fail (as a unit).

The classic example for a transaction is a funds transfer in a bank:

1. A bank client gives an order to move funds from account A to account B
2. The money is deducted from account A
3. The money is added to account B

If there is a failure in the process before the money is added to account B the whole event is considered as failed and it is rolled back - so no money is lost. In other words the whole transaction must succeed or fail as a unit.

The following steps describe the events that occur when data is committed or changed in the store:

1. A user changes an item that is stored in Exchange's data store.
2. The relevant information (the information that has to be changed) is loaded into RAM.
3. The information is changed in RAM and simultaneously written to the log file(s).
4. At predefined time intervals the "new data" is flushed from RAM to the database.

After the data is flushed the checkpoint file is updated to indicate which log files are no longer needed since the transactions they represent have already been flushed to the database directly from RAM.

Based on the preceding description of how the database engine functions the importance of log files is in keeping the database in a consistent state.

If the database terminates in an abnormal way while a transaction is in progress or while "dirty pages" (data that has been changed and not yet committed to the database) still exists in RAM, the next time the database is mounted it will go through a soft recovery process.

Soft recovery causes uncompleted transactions to roll back and uncommitted data to be committed to the database.

So, as you can see log files play a very important role in protecting the consistency of your Exchange stores. When the system runs out of disk space on a log disk it will dismount the respective storage group(s) to avoid the possibility of inconsistency being caused.
The symptoms

The symptoms for a full log disk are quite obvious, first of all, all of the stores inside the storage group will be dismounted:


Fig. 1: All stores in the storage group are dismounted

The second symptom will be a lot more descriptive - when looking at the Application Log you will find Event ID 9559:


Fig. 2: Event ID 9559

Preventive measures

The best way to deal with the loss of disk space on a log disk is not to deal with it at all - simply try to prevent it. If the storage group has already been dismounted because of lack of space, you as a system administrator have failed to protect your system.

You may receive some lenience from the court since at times the loss of disk space may be caused by a group or individual that is trying to maliciously disrupt the messaging services you provide to your company by sending huge amounts of data to your recipients (a.k.a. mail-bombing).

So at this stage you must be asking yourself how do I prevent this awful fate that awaits me???

In the upcoming sections of this document I will try to provide a few tips and tricks that may help you.
Preventive measures - Be vigilante

If the space on your log disk is near depletion you should know about it. If you are vigilant enough and you identify the problem while it is building up you can take steps to prevent it altogether.

Basically your weapon of choice can be any of the following:

1. Check the disk space every few hours or at least once a day manually. The advantage of this option is that you do not need to invest in any monitoring service, thus you are not lowering your budget. An additional advantage is that you are not hampering server performance by running a monitoring service against it. The disadvantage is quite obvious - you have to do it… Now you may be a very productive system administrator but you are human so you may forget to check the space from time to time and the attack on your server may happen at night while you are fast asleep.
2. Use a monitoring service. This solution is an automatic solution that will monitor the system and raise an alarm once a problem is found. There are many monitoring tools on the market from which you can choose and one of them is built into the operating system (Performance Monitor). Perfmon will do the job after you configure an Alert (with a threshold of 30% available disk space) and best of all it's free.
In addition you can monitor the System Log for event 2013 (warns about low disk space). This warning actually tells you that your disk drive has reached a threshold of 10% of free space or lower. This threshold can be changed by editing the registry as per knowledge base article 112509.

Looking into the abyss

So you were vigilant. Your systems raised the alarm and you are ready to leap into action - what do you do? Well as I said earlier if you received warning about your disk space getting depleted there are two courses of action that can be taken:

1. Run an online backup (Full or Incremental)-backing the storage group up using either of the aforementioned methods will remove the unneeded log files providing you with extra disk space.
1. Advantages- Your system is backed up. If the system crashes later that day you can restore to the exact point in time it crashed (if the new logs created after the backup survived the crash).
An additional advantage is that by using this method there is no downtime and your user community will be pleased.
2. Disadvantages- The backup process may take precious time which you do not have. If the log files will not be pruned before you run out of disk space you stores will dismount.
2. Turn on Circular Logging for the storage group- Before you scream and shout I do understand that I am walking on thin ice here - but drastic situations call for drastic measures. By turning on the Circular Logging option for the storage group while the stores are still mounted the log files will be pruned and only five log files will remain. Turning on circular logging can be done by accessing the properties of the storage group and by checking the option called "Enable circular logging". Read and acknowledge the warning that appears and you are done - watch the log files disappear.
1. Advantages- The only advantage here is time. This is the fastest solution for the problem.
2. Disadvantages- Circular Logging will take away your ability to restore the system to the point in time at which the server crashed.


Fig. 3: Turning on Circular Logging.

And then came the rain

It is inevitable- rain will eventually come, so you really should walk around with an umbrella…

If you have passed the threshold and your stores are down your most important task is to renew service to your messaging clients.

Prepare for a rainy day

In our case preparing for a rainy day means saving some disk space. If your log files get out of control release the disk space you saved and presto - you have a few more minutes/hours of grace to take care of the problem…

I saw this method being practiced by many messaging administrators. They copy a large amount of data onto their log disk (approximately 10% to 15% out of the disk's space) and when they start running out of space they simply erase the files. By erasing the placeholder files the system administrator allows himself some extra breathing room until he solves the problem.

Another advantage of this method manifests itself once the disk space for your log files has been depleted. Most methods to fix the problem will take some amount of time during which your users have no access to their data. If you prepared ahead and you captured disk space, as I advised earlier, to get the system up and running all you have to do is to erase the placeholder files and remount the storage group. Once this is done, you can quietly contemplate on finding a solution for the problem at hand (for additional information read the section called "Looking into the abyss").

Move the log files

If you have enough (actually more then enough, preferably a lot more) disk space to hold your log files on a different volume on the same system you can move them there. Once you moved the log files you can mount your databases. Since this is a temporary solution after you have your system up and running you should solve the problem by using one of the methods specified in the earlier section called "Looking into the abyss".

A word of warning:
Before you choose this course of action be sure to consider the downtime your clients will experience. Depending on the total size of your log files it may take a long time to move them to the new volume. In addition keep in mind that eventually you will want to move the log files back to their original location - that means more downtime since moving the log files will automatically dismount the databases in the respective storage groups.


The path less traveled- Remove unneeded log files manually

As I already said earlier, drastic situations need drastic measures and this is the most drastic measure you can take.

Almost all Exchange administrators know and live by the golden rule: "Do not remove Exchange log files manually!". Basically I agree. If you have any other course of action that may work for you when you lost all empty space on your system then use it before trying this one.

Users data in Exchange is stored inside Exchange stores which are homed inside Exchange storage groups that have one set of log files for all stores that are homed in that storage group. In a point in time users data may be spread out between the stores and the log files. To keep a store consistent all database files (EDB and STM) and log files that have uncommitted data are needed.

The only log files that can be removed manually are log files that do not contain uncommitted data. If a log file that is needed by one of the stores (contains uncommitted data) is mistakenly erased the store becomes inconsistent and un-mountable(restore time-woohooo!!).

At this point you must be asking yourself - how can I know which log files have been committed (and should be earsed) and which have not been committed (and should not be erased)?

There are two answers to your question:

1. The Checkpoint file- as mentioned earlier the checkpoint file is used by the Exchange storage system to identify the point up to which log files have been committed to the stores. By using the ESEUTIL tool a system administrator can dump this information from the checkpoint file (Fig.4).
The exact command used to dump the file is eseutil /mk .
The only information we are interested in is the line that looks similar to the following one: Checkpoint: <0xF,208,E2> . On this line inside the brackets you have three pieces of information of which only the first interests us- 0xF. The first piece of information points to the log file which is borderline, everything before it can be removed and everything after it is needed to keep the databases consistent.
In our case 0xF actually means that the log file prefix is E00 and suffix is 0000F. So the filename is E000000F.log .
Keep in mind that by erasing log files you lose the ability to restore the system to a point in time so my advice is to simply move the files to a different location, another benefit that is gained from moving the files is that if anything goes wrong you can always copy all log files back to their original location.


Fig. 4: Dumping the checkpoint file
2. The database files- Each database file used by the store contains information about the log files it needs to become consistent. To glean this information from the databases a system administrator has to use ESEUTIL again. The command slightly changes: ESEUTIL /mh . The output can be overwhelming but we are interested in two lines:
1. State- this line specifies the database state which can be either:

- Clean Shutdown (fig. 5)- indicates that the database was dismounted in an orderly fashion or in other words it means that all outstanding transactions were committed to the database and it is consistent(no log files are needed to bring it to a consistent state).


Fig. 5: Clean Shutdown

- Dirty Shutdown (fig. 6)- indicates that the database was shut down incorrectly - outstanding transaction from log files were not committed and the database is inconsistent. The next time the store is mounted the database files will need specific log files to become consistent-without them the store will not mount.


Fig. 6: Dirty Shutdown
2. Log Required - this lines specifies the log files needed to make the database file consistent.

- State: Clean Shutdown – the Log Required line will show 0-0, meaning no log files are needed.

- State: Dirty Shutdown - the Log Required line will show a range of numbers such as 17-19. This is the range of log files needed to bring the database to a consistent state (17, 18, 19). To identify the log filenames the numbers have to be converted hexadecimal, in our case 11, 12, 13 adding the prefix to it(based on the log prefix for the storage group) E0000011.log, E0000012.log, E0000013.log.

Of the methods discussed I prefer using the checkpoint file. It is simpler and there is only one place to look as opposed to checking the database file where you have several places to check.

After identifying the committed log files they can be manually erased. As I said earlier I prefer copying t

Thứ Ba, 21 tháng 9, 2010

So, you wanna change the registration point of a MovieClip at runtime? Here is some piece of code that allows you to do just that.

Based on an old AS2 class written by Darron Schall, this AS3 class extends MovieClip and adds a new set of properties (x2, y2, rotation2, scaleX2, scaleY2, mouseX2, mouseY2) that allow you to manipulate the sprite based on a contextual registration point that can be set using the setRegistration method.

Here is how it works



// Create a new instance
var square:DynamicMovieClip = new DynamicMovieClip();
addChild(square);

// Change registration coordinates at runtime
square.setRegistration(20, 20);

// From this point on, instead of using 'rotation'
// we use 'rotation2'
// Same principle applies for 'x', 'y', 'scaleX' and 'scaleY'
square.rotation2 = 45;

Here's a simple application.

http://www.oscartrelles.com/examples/DynamicMovie.zip
Sources

Thứ Bảy, 17 tháng 7, 2010

DarkBaron

DarkBaron

Thứ Ba, 11 tháng 5, 2010

Block phím start của win

Add a new class to your project and paste this code:

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class KeyboardFilter {
  private Keys[] mFilter;
  private IntPtr mHook;
  private LowLevelKeyboardProc mProc;

  public KeyboardFilter(Keys[] keysToFilter) {
    // Install hook
    mFilter = keysToFilter;
    ProcessModule mod = Process.GetCurrentProcess().MainModule;
    mProc = new LowLevelKeyboardProc(KeyboardProc);   // Avoid garbage collector problems
    mHook = SetWindowsHookEx(13, mProc, GetModuleHandle(mod.ModuleName), 0);
    if (mHook == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to set hook");
  }
  public void Dispose() {
    // Release hook
    if (mHook != IntPtr.Zero) {
      UnhookWindowsHookEx(mHook);
      mHook = IntPtr.Zero;
    }
  }
  private IntPtr KeyboardProc(int nCode, IntPtr wp, IntPtr lp) {
    // Callback, filter key
    if (nCode >= 0) {
      KBDLLHOOKSTRUCT info = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
      foreach (Keys key in mFilter)
        if ((key & Keys.KeyCode) == info.key && CheckModifier(key)) return (IntPtr)1;
    }
    return CallNextHookEx(mHook, nCode, wp, lp);
  }
  private bool CheckModifier(Keys key) {
    // Check if modifier key in required state
    if ((key & Keys.Control) == Keys.Control &&
      GetAsyncKeyState(Keys.LControlKey) == 0 && GetAsyncKeyState(Keys.RControlKey) == 0) return false;
    if ((key & Keys.Shift) == Keys.Shift &&
      GetAsyncKeyState(Keys.LShiftKey) == 0 && GetAsyncKeyState(Keys.RShiftKey) == 0) return false;
    if ((key & Keys.Alt) == Keys.Alt &&
      GetAsyncKeyState(Keys.LMenu) == 0 && GetAsyncKeyState(Keys.RMenu) == 0) return false;
    return true;
  }

  // P/Invoke declarations
  [StructLayout(LayoutKind.Sequential)]
  private struct KBDLLHOOKSTRUCT {
    public Keys key;
    public int scanCode;
    public int flags;
    public int time;
    public IntPtr extra;
  }
  private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  private static extern bool UnhookWindowsHookEx(IntPtr hook);
  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
  [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  private static extern IntPtr GetModuleHandle(string name);
  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  private static extern short GetAsyncKeyState(Keys key);
}

Add this line to your main form:

    KeyboardFilter filter = new KeyboardFilter(new Keys[] { Keys.LWin, Keys.RWin, Keys.Escape | Keys.Control }); 

Before continue reading please note that this article doesn’t intend to call upon you to create nasty applications. If you use this code it should be for your own fun or for learning purposes.
After doing some research on disabling keys or key combinations I found out that there are several ways of achieving the before mentioned key combos. CTRL-ALT-DEL combo is part of the SAS (Secure Attention Sequence) thus the solution to disable this is to write your own gina.dll (Graphical Identification and Authentication).
Don’t worry, I’m not looking into that as for now, I’m going to show you the work around. We will use C#’s Registry editing possibilities to set/change the group policy for the CTRL-ALT-DEL key sequence. Let’s see what we are about to do without programming anything. Open Start Menu > Run and enter gpedig.msc. Navigate to: User Configuration > Administrative Templates > System > CTRL+ALT+DELETE Options.This is the place where you normally set the behaviour of the key combo. Select Remove Task Manager > Double-click the Remove Task Manager option.
If you change it’s value, the following registry entry gets created/modified: Software\Microsoft\Windows\CurrentVersion\Policies\System and the value of DisableTaskMgr gets set to 1.
Now, the task is set. Let’s get down to business and start coding:
Important thing, don’t miss out this line:
using Microsoft.Win32;
And now the method I have created looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void KillCtrlAltDelete()
        {
            RegistryKey regkey;
            string keyValueInt = "1";
            string subKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
 
            try
            {
                regkey = Registry.CurrentUser.CreateSubKey(subKey);
                regkey.SetValue("DisableTaskMgr", keyValueInt);
                regkey.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
If you run the method and try to press CTRL-ALT-DEL the following screen should come up:
CTRL ALT DEL
So the CTRL-ALT-DEL combo has been taken care of, let’s see the rest. You might have found this a bit difficult, so here’s an easy one. How to disable ALT+F4. 5 lines of code alltogether:
1
2
3
4
5
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            base.OnClosing(e);
        }
Okay. As for the rest I was reading many many articles, and they gave a lot of help. I can’t name one, as I was looking into at least 15 which all held some useful peace of information. I will give you the the source of the method called hooks. The code snippet uses the LowLevelKeyboardProc which is:
The LowLevelKeyboardProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function every time a new keyboard input event is about to be posted into a thread input queue. The keyboard input can come from the local keyboard driver or from calls to the keybd_event function. If the input comes from a call to keybd_event, the input was “injected”. However, the WH_KEYBOARD_LL hook is not injected into another process. Instead, the context switches back to the process that installed the hook and it is called in its original context. Then the context switches back to the application that generated the event.
Again, dont forget:
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Diagnostics;
Here’s the rest what you need:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[DllImport("user32", EntryPoint = "SetWindowsHookExA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, int hMod, int dwThreadId);
        [DllImport("user32", EntryPoint = "UnhookWindowsHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int UnhookWindowsHookEx(int hHook);
        public delegate int LowLevelKeyboardProcDelegate(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        [DllImport("user32", EntryPoint = "CallNextHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int CallNextHookEx(int hHook, int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        public const int WH_KEYBOARD_LL = 13;
 
        /*code needed to disable start menu*/
        [DllImport("user32.dll")]
        private static extern int FindWindow(string className, string windowText);
        [DllImport("user32.dll")]
        private static extern int ShowWindow(int hwnd, int command);
 
        private const int SW_HIDE = 0;
        private const int SW_SHOW = 1;
public struct KBDLLHOOKSTRUCT
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        public static int intLLKey;
 
        public int LowLevelKeyboardProc(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam)
        {
            bool blnEat = false;
 
            switch (wParam)
            {
                case 256:
                case 257:
                case 260:
                case 261:
                    //Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key,
                    blnEat = ((lParam.vkCode == 9) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 0)) | ((lParam.vkCode == 91) && (lParam.flags == 1)) | ((lParam.vkCode == 92) && (lParam.flags == 1)) | ((lParam.vkCode == 73) && (lParam.flags == 0));
                    break;
            }
 
            if (blnEat == true)
            {
                return 1;
            }
            else
            {
                return CallNextHookEx(0, nCode, wParam, ref lParam);
            }
        }
public void KillStartMenu()
        {
            int hwnd = FindWindow("Shell_TrayWnd", "");
            ShowWindow(hwnd, SW_HIDE);
        }
private void Form1_Load(object sender, EventArgs e)
        {
            intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(), 0);
        }
Quite obviously you can programmatically reset these values. Here’s the code to re-enable everything:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void ShowStartMenu()
        {
            int hwnd = FindWindow("Shell_TrayWnd", "");
            ShowWindow(hwnd, SW_SHOW);
        }
public static void EnableCTRLALTDEL()
        {
            try
            {
                string subKey = "Software\Microsoft\Windows\CurrentVersion\Policies\System";
                RegistryKey rk = Registry.CurrentUser;
                RegistryKey sk1 = rk.OpenSubKey(subKey);
                if (sk1 != null)
                    rk.DeleteSubKeyTree(subKey);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnhookWindowsHookEx(intLLKey);
        }
I hope you enjoyed my article and that you found some useful bits. I tried to collect all the information I managed to find during my research on this topic.

Chủ Nhật, 9 tháng 5, 2010

String Format for DateTime [C#]

String Format for DateTime [C#]

This example shows how to format DateTime using String.Format method. All formatting can be done also using DateTime.ToString method.

Custom DateTime Formatting

There are following custom format specifiers y (year), M (month), d (day), h (hour 12), H (hour 24), m (minute), s (second), f (second fraction), F (second fraction, trailing zeroes are trimmed),t (P.M or A.M) and z (time zone).
Following examples demonstrate how are the format specifiers rewritten to the output.
[C#]
// create date time 2008-03-09 16:05:07.123
DateTime dt = new DateTime(2008, 3, 9, 16, 5, 7, 123);

String.Format("{0:y yy yyy yyyy}", dt);  // "8 08 008 2008"   year
String.Format("{0:M MM MMM MMMM}", dt);  // "3 03 Mar March"  month
String.Format("{0:d dd ddd dddd}", dt);  // "9 09 Sun Sunday" day
String.Format("{0:h hh H HH}",     dt);  // "4 04 16 16"      hour 12/24
String.Format("{0:m mm}",          dt);  // "5 05"            minute
String.Format("{0:s ss}",          dt);  // "7 07"            second
String.Format("{0:f ff fff ffff}", dt);  // "1 12 123 1230"   sec.fraction
String.Format("{0:F FF FFF FFFF}", dt);  // "1 12 123 123"    without zeroes
String.Format("{0:t tt}",          dt);  // "P PM"            A.M. or P.M.
String.Format("{0:z zz zzz}",      dt);  // "-6 -06 -06:00"   time zone

You can use also date separator / (slash) and time sepatator : (colon). These characters will be rewritten to characters defined in the current DateTimeForma tInfo.DateSepa rator andDateTimeForma tInfo.TimeSepa rator.
[C#]
// date separator in german culture is "." (so "/" changes to ".")
String.Format("{0:d/M/yyyy HH:mm:ss}", dt); // "9/3/2008 16:05:07" - english (en-US)
String.Format("{0:d/M/yyyy HH:mm:ss}", dt); // "9.3.2008 16:05:07" - german (de-DE)

Here are some examples of custom date and time formatting:
[C#]
// month/day numbers without/with leading zeroes
String.Format("{0:M/d/yyyy}", dt);            // "3/9/2008"
String.Format("{0:MM/dd/yyyy}", dt);          // "03/09/2008"

// day/month names
String.Format("{0:ddd, MMM d, yyyy}", dt);    // "Sun, Mar 9, 2008"
String.Format("{0:dddd, MMMM d, yyyy}", dt);  // "Sunday, March 9, 2008"

// two/four digit year
String.Format("{0:MM/dd/yy}", dt);            // "03/09/08"
String.Format("{0:MM/dd/yyyy}", dt);          // "03/09/2008"

Standard DateTime Formatting

In DateTimeForma tInfo there are defined standard patterns for the current culture. For example property ShortTimePattern is string that contains value h:mm tt for en-US culture and value HH:mm for de-DE culture.
Following table shows patterns defined in DateTimeForma tInfo and their values for en-US culture. First column contains format specifiers for the String.Format method.

SpecifierDateTimeFormatInfo propertyPattern value (for en-US culture)
tShortTimePatternh:mm tt
dShortDatePatternM/d/yyyy
TLongTimePatternh:mm:ss tt
DLongDatePatterndddd, MMMM dd, yyyy
f(combination of D and t)dddd, MMMM dd, yyyy h:mm tt
FFullDateTimePatterndddd, MMMM dd, yyyy h:mm:ss tt
g(combination of d and t)M/d/yyyy h:mm tt
G(combination of d and T)M/d/yyyy h:mm:ss tt
mMMonthDayPatternMMMM dd
yYYearMonthPatternMMMM, yyyy
rRRFC1123Patternddd, dd MMM yyyy HH':'mm':'ss 'GMT' (*)
sSortableDateTi mePatternyyyy'-'MM'-'dd'T'HH':'mm':'ss (*)
uUniversalSorta bleDateTimePat ternyyyy'-'MM'-'dd HH':'mm':'ss'Z' (*)
  (*) = culture independent

Following examples show usage of standard format specifiers in String.Format method and the resulting output.
[C#]
String.Format("{0:t}", dt);  // "4:05 PM"                         ShortTime
String.Format("{0:d}", dt);  // "3/9/2008"                        ShortDate
String.Format("{0:T}", dt);  // "4:05:07 PM"                      LongTime
String.Format("{0:D}", dt);  // "Sunday, March 09, 2008"          LongDate
String.Format("{0:f}", dt);  // "Sunday, March 09, 2008 4:05 PM"  LongDate+ShortTime
String.Format("{0:F}", dt);  // "Sunday, March 09, 2008 4:05:07 PM" FullDateTime
String.Format("{0:g}", dt);  // "3/9/2008 4:05 PM"                ShortDate+ShortTime
String.Format("{0:G}", dt);  // "3/9/2008 4:05:07 PM"             ShortDate+LongTime
String.Format("{0:m}", dt);  // "March 09"                        MonthDay
String.Format("{0:y}", dt);  // "March, 2008"                     YearMonth
String.Format("{0:r}", dt);  // "Sun, 09 Mar 2008 16:05:07 GMT"   RFC1123
String.Format("{0:s}", dt);  // "2008-03-09T16:05:07"             SortableDateTime
String.Format("{0:u}", dt);  // "2008-03-09 16:05:07Z"            UniversalSor