§1 ランタイム・システム・プラットフォームの情報

§1.1 ランタイムバージョン

Environment.Versionプロパティを参照することで、現在動作しているランタイム(.NET Framework、Mono等)のバージョンを取得することが出来ます。 バージョンは数値や文字列ではなくVersionクラスとして返されるため、メジャーバージョン番号・マイナーバージョン番号・ビルド番号等を個別に参照することも出来ます。

using System;

class Sample {
  static void Main()
  {
    // ランタイムバージョンを取得・表示
    Console.WriteLine(Environment.Version);

    // ランタイムバージョンを取得
    Version v = Environment.Version;

    // メジャー・マイナー・ビルド・リビジョンの各バージョン番号を表示
    Console.WriteLine("{0}.{1}.{2}.{3}", v.Major, v.Minor, v.Build, v.Revision);
  }
}
.NET Framework 4での実行結果
4.0.30319.239
4.0.30319.239
Mono 2.10.8での実行結果
4.0.30319.1
4.0.30319.1

RuntimeEnvironment.GetSystemVersionメソッドを呼ぶことでもランタイムのバージョンを取得することが出来ます。 ただし、このメソッドの戻り値はVersionクラスではなく文字列となっています。 返されるバージョンは数字のみからなる形式でなくvから始まるものとなるようです(.NET Frameworkのディレクトリ名やバージョン表記で使われるものと同じ形式)。

using System;
using System.Runtime.InteropServices;

class Sample {
  static void Main()
  {
    // ランタイムバージョンを取得・表示
    Console.WriteLine(RuntimeEnvironment.GetSystemVersion());
  }
}
.NET Framework 4での実行結果
v4.0.30319
Mono 2.10.8での実行結果
v4.0.30319

現在動作しているランタイムがMonoかどうか調べる方法はTipsで解説しています。

§1.2 OSバージョン

Environment.OSVersionプロパティを参照することで、現在動作しているOSのバージョンを取得することが出来ます。 このバージョンも数値や文字列ではなくOperatingSystemクラスとして返されるため、バージョンの他にも適用されているサービスパック名、プラットフォームIDなども参照することも出来ます。

using System;

class Sample {
  static void Main()
  {
    // OSバージョンを取得・表示
    Console.WriteLine(Environment.OSVersion);

    // OSバージョンを取得
    OperatingSystem os = Environment.OSVersion;

    Console.WriteLine(os.VersionString); // 文字列形式のバージョン名
    Console.WriteLine(os.Version);       // バージョン番号
    Console.WriteLine(os.ServicePack);   // サービスパック名
    Console.WriteLine(os.Platform);      // プラットフォームID

    if (os.Platform == PlatformID.Win32NT)
      Console.WriteLine("NT系OS");
    else if (os.Platform == PlatformID.Unix)
      Console.WriteLine("Unix系OS");
    else
      Console.WriteLine("その他のOS");
  }
}
Windows 7 + .NET Framework 4での実行結果
Microsoft Windows NT 6.1.7601 Service Pack 1
Microsoft Windows NT 6.1.7601 Service Pack 1
6.1.7601.65536
Service Pack 1
Win32NT
NT系OS
Ubuntu 11.10 + Mono 2.10.8での実行結果
Unix 3.0.0.14
Unix 3.0.0.14
3.0.0.14

Unix
Unix系OS

PlatformIDは、OSがNT系Windowsか、9x系Windowsか、Unix系かといった大きな分類を表すものです。 より細かいOSのバージョン(XP, Vista, 7, etc.)やエディション(Professional, Ultimate, etc.)等を知るには、VersionStringを解析するか、バージョン番号を詳しく見ていく必要があります。 また、古いバージョンのランタイムではPlatformID.MacOSXPlatformID.Xboxなどの値が定義されていない場合がある点にも注意が必要です。

現在動作しているOSがUnix系(Linux, Mac OS, BSD等)であるかどうかを調べる方法はTipsで解説しています。

§1.3 プロセッサ数・プロセッサ情報

Environment.ProcessrCountプロパティを参照することで、現在動作している環境のCPU数(プロセッサコア数)を取得することができます。 ドキュメントによると、.NET Frameworkの実装では環境変数NUMBER_OF_PROCESSORSの値を参照しているようです。

なお、NT系WindowsではPROCESSOR_ARCHITECTURE等の環境変数の値を取得することでプロセッサ情報を取得することが出来ます。

using System;

class Sample {
  static void Main()
  {
    // プロセッサ数を取得・表示する
    Console.WriteLine("ProcessorCount: {0}", Environment.ProcessorCount);

    // 環境変数からプロセッサ情報を取得する
    Console.WriteLine("NUMBER_OF_PROCESSORS   = {0}", Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"));
    Console.WriteLine("PROCESSOR_ARCHITECTURE = {0}", Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"));
    Console.WriteLine("PROCESSOR_IDENTIFIER   = {0}", Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER"));
  }
}
Windows 7 + .NET Framework 4での実行結果例
ProcessorCount: 2
NUMBER_OF_PROCESSORS   = 2
PROCESSOR_ARCHITECTURE = AMD64
PROCESSOR_IDENTIFIER   = AMD64 Family 15 Model 43 Stepping 1, AuthenticAMD
Ubuntu 11.10 + Mono 2.10.8での実行結果例
ProcessorCount: 2
NUMBER_OF_PROCESSORS   = 
PROCESSOR_ARCHITECTURE = 
PROCESSOR_IDENTIFIER   = 

CPUの使用率等の情報はパフォーマンスカウンタで取得できます。 一方、クロック周波数など環境変数では取得できないようなハードウェア情報を取得するにはWMI(Windows Management Instrumentation, System.Management名前空間)を使用したり、レジストリに格納されている情報や/proc/cpuinfoなどを参照する必要があります。

環境変数の取得については環境変数で詳しく解説しています。

§1.4 32ビット環境・64ビット環境

Environment.Is64BitProcessプロパティおよびEnvironment.Is64BitOperatingSystemプロパティを参照することで、実行環境が32ビットか64ビットかを判断も出来ます。 Is64BitProcessプロパティは自プロセスが64ビットで動作しているかどうか、Is64BitOperatingSystemは実行しているOSが64ビットで動作しているかどうかを返します。 なお、このプロパティはいずれも.NET Framework 4で追加されたものです。 それより前のバージョンでは使用できない点に注意が必要です。

using System;

class Sample {
  static void Main()
  {
    // 現在のプロセスが64ビットで動作しているかどうか
    if (Environment.Is64BitProcess)
      Console.WriteLine("64bit process");
    else
      Console.WriteLine("32bit process?");

    // 実行しているOSが64ビットかどうか
    if (Environment.Is64BitOperatingSystem)
      Console.WriteLine("64bit OS");
    else
      Console.WriteLine("32bit OS?");
  }
}

実行環境が64ビットかどうかを調べるためにIntPtr.Sizeプロパティを参照することも出来ます。 IntPtr.SizeプロパティはIntPtr(ポインタ)のバイト数を表す値を返し、プロセスが64ビットモードで動作している場合(64ビット版のランタイムが使われている場合)はSizeプロパティが8(バイト=64ビット)、32ビットの場合は4(バイト=32ビット)を返します。

using System;

class Sample {
  static void Main()
  {
    // IntPtr.Sizeプロパティの値から動作しているプロセスが32ビットか64ビットかを調べる
    if (IntPtr.Size == 4)
      Console.WriteLine("32bit");
    else if (IntPtr.Size == 8)
      Console.WriteLine("64bit");
    else
      Console.WriteLine("?");
  }
}

以下の結果は、上記のコードを64ビット版Windows上でコンパイル、動作させたものです。 コンパイルオプション(/platform)によって32ビット版・64ビット版のどちらのランタイムで動作させるか指定しています。

/platformコンパイルオプションによってランタイムのビット数を変えた場合の実行結果
E:\>csc /platform:x64 sample.cs && sample.exe
64bit

E:\>csc /platform:x86 sample.cs && sample.exe
32bit


§1.5 エンディアン

BitConverter.IsLittleEndianプロパティを参照することで、現在実行している環境がリトルエンディアンであるかどうかを調べることができます。

using System;

class Sample {
  static void Main()
  {
    // リトルエンディアンかどうかを調べる
    if (BitConverter.IsLittleEndian)
      Console.WriteLine("little endian");
    else
      Console.WriteLine("big endian?");
  }
}

この他、次の例のように、メモリ上に格納される値のレイアウトを見ることでエンディアンを調べることも出来ます。

using System;

class Sample {
  static void Main()
  {
    // エンディアンを調べる
    unsafe {
      int i = 1;
      byte* b = (byte*)&i;

      if (b[0] == 1)
        Console.WriteLine("little endian");
      else if (b[3] == 1)
        Console.WriteLine("big endian");
      else
        Console.WriteLine("middle endian?");
    }
  }
}
unsafeを使わない場合
using System;
using System.Runtime.InteropServices;

class Sample {
  static void Main()
  {
    IntPtr buffer = Marshal.AllocCoTaskMem(4);

    Marshal.WriteInt32(buffer, 0, 1);

    // エンディアンを調べる
    if (Marshal.ReadByte(buffer, 0) == 1)
      Console.WriteLine("little endian");
    else if (Marshal.ReadByte(buffer, 3) == 1)
      Console.WriteLine("big endian");
    else
      Console.WriteLine("middle endian?");

    Marshal.FreeCoTaskMem(buffer);
  }
}

バイトオーダーの変換にはIPAddress.NetworkToHostOrderメソッドおよびIPAddress.HostToNetworkOrderメソッドが使えます。 これらのメソッドについては基本型の型変換 §.基本型とバイト配列への/からの変換で解説しています。

§1.6 改行文字

Environment.NewLineプロパティを参照することで、現在実行している環境での改行文字を取得することが出来ます。

using System;

class Sample {
  static void Main()
  {
    // 改行文字を取得
    string newline = Environment.NewLine;

    // 表示
    Console.WriteLine("Length = {0}", newline.Length);

    foreach (char c in newline) {
      Console.Write("{0:X2} ", (int)c);
    }
    Console.WriteLine();
  }
}
Windows 7 + .NET Framework 4での実行結果
Length = 2
0D 0A 
Ubuntu 11.10 + Mono 2.10.8での実行結果
Length = 1
0A 

Console.WriteLineメソッドStreamWriter.WriteLineメソッドStringBuilder.AppendLineメソッドでは、末尾に追加される改行文字にEnvironment.NewLineと同じものが使用されます。

なお、StreamWriterではNewLineプロパティに任意の文字列を設定することでEnvironment.NewLineとは異なる改行文字を使用することが出来ます。 StringBuilderにはそのようなプロパティは用意されていません。

Consoleの場合は、Console.Out.NewLineに値を指定することで改行文字を変更することが出来ます。 次の例ではNewLineに"↵\n"を指定することで改行文字を変更しています。

using System;

class Sample {
  static void Main()
  {
    // 改行文字を変更
    Console.Out.NewLine = "↵\n";

    // 標準出力に文字列を表示
    Console.WriteLine("Hello, world!");
    Console.WriteLine("foo");
    Console.WriteLine("bar");
    Console.WriteLine("baz");
  }
}
実行結果
Hello, world!↵
foo↵
bar↵
baz↵

なお、現在実行している環境でのデフォルトの文字コードについては別途解説しています。

§1.7 ファイル・ディレクトリの区切り文字・無効な文字

Path.DirectorySeparatorCharフィールドを参照することで、ファイル・ディレクトリの区切り文字を取得できます。 Windowsでは区切り文字に \ (バックスラッシュ)、MaxOSやUnix系OSなどでは / (スラッシュ)が使われますが、この区切り文字を取得できます。 ただ、Pathクラスのメソッドを使えば適切な区切り文字を使用した処理が行われるので、このフィールドの値を参照することはあまりありません。 例えばパスの連結にはCombineメソッド、パスからディレクトリ・ファイル名の取得にはGetDirectoryNameメソッドGetFileNameメソッドを使うことが出来るため、わざわざ区切り文字を使って文字列の分割・結合をする必要はありません。 また、これらのメソッドでは区切り文字に \/ が混在していても適切に動作します。

using System;
using System.IO;

class Sample {
  static void Main()
  {
    // パス区切り文字を取得、表示
    Console.WriteLine(Path.DirectorySeparatorChar);

    string path1 = @"D:\test";
    string path2 = @"subdir/file.txt";

    // パスを連結
    string fullPath = Path.Combine(path1, path2);

    Console.WriteLine(fullPath);

    // 連結したパスから、ディレクトリ名・ファイル名・拡張子を取得して表示
    Console.WriteLine(Path.GetDirectoryName(fullPath));
    Console.WriteLine(Path.GetFileName(fullPath));
    Console.WriteLine(Path.GetExtension(fullPath));
  }
}
Windows 7 + .NET Framework 4での実行結果
\
D:\test\subdir/file.txt
D:\test\subdir
file.txt
.txt
Ubuntu 11.10 + Mono 2.10.8での実行結果
/
D:\test/subdir/file.txt
D:\test/subdir
file.txt
.txt

ファイル名に使えない文字、パスに使えない文字を取得するには、Path.GetInvalidFileNameCharsメソッドもしくはPath.GetInvalidPathCharsメソッドを呼び出します。 これらのメソッドは、使用不可能な文字をcharの配列で返します。

using System;
using System.IO;

class Sample {
  static void Main()
  {
    // ファイル名に使えない文字を取得、表示
    Console.Write("InvalidFileNameChars: ");

    foreach (char c in Path.GetInvalidFileNameChars()) {
      if (char.IsControl(c)) // 制御文字かどうか
        Console.Write("'\\x{0:X2}', ", (int)c);
      else
        Console.Write("'{0}', ", c);
    }
    Console.WriteLine();

    // パス名に使えない文字を取得、表示
    Console.Write("InvalidPathChars: ");

    foreach (char c in Path.GetInvalidPathChars()) {
      if (char.IsControl(c))
        Console.Write("'\\x{0:X2}', ", (int)c);
      else
        Console.Write("'{0}' ", c);
    }
    Console.WriteLine();
  }
}
Windows 7 + .NET Framework 4での実行結果
InvalidFileNameChars: '"', '<', '>', '|', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F', ':', '*', '?', '\', '/',
InvalidPathChars: '"' '<' '>' '|' '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F',
Ubuntu 11.10 + Mono 2.10.8での実行結果
InvalidFileNameChars: '\x00', '/', 
InvalidPathChars: '\x00', 

§1.8 特別なディレクトリ

§1.8.1 ホームフォルダ・デスクトップ・システムディレクトリ等

Environment.GetFolderPathメソッドを使うことで、OSのバージョンやユーザ毎に異なるフォルダ・ディレクトリのパスを取得することが出来ます。 取得したいフォルダの種類はEnvironment.SpecialFolder列挙体で指定します。

また、Environment.SystemDirectoryプロパティを参照することでシステムディレクトリを取得することも出来ます。

using System;

class Sample {
  static void Main()
  {
    // ユーザの個人用フォルダ (マイ ドキュメント)
    Console.WriteLine("Personal:              {0}", Environment.GetFolderPath(Environment.SpecialFolder.Personal));
    // デスクトップ
    Console.WriteLine("Desktop:               {0}", Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
    // ユーザの個人用アプリケーションデータ
    Console.WriteLine("ApplicationData:       {0}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
    // 全ユーザ共通のアプリケーションデータ
    Console.WriteLine("CommonApplicationData: {0}", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));

    // システムディレクトリ
    Console.WriteLine("SystemDirectory:       {0}", Environment.SystemDirectory);
  }
}
Windows 7 + .NET Framework 4での実行結果例
Personal:              C:\Users\smdn\Documents
Desktop:               C:\Users\smdn\Desktop
ApplicationData:       C:\Users\smdn\AppData\Roaming
CommonApplicationData: C:\ProgramData
SystemDirectory:       C:\windows\system32
Ubuntu 11.10 + Mono 2.10.8での実行結果例
Personal:              /home/smdn
Desktop:               /home/smdn/Desktop
ApplicationData:       /home/smdn/.config
CommonApplicationData: /usr/share
SystemDirectory: 

これらのフォルダは環境によっては対応するものが無い場合もあります。 次の表は、Environment.SpecialFolder列挙体で指定できるフォルダの種類と、実際に取得されたパスの対応表です。 一つの参考としてご覧ください。 パス中に含まれるユーザ名の部分は username、該当するフォルダが無い場合(GetFolderPathが空の文字列を返す場合)は - と表記しています。 フォルダの具体的な意味や役割と得られるパスについてはEnvironment.SpecialFolder列挙体のドキュメントを参照してください。

Environment.SpecialFolderの値と対応するフォルダのパス
Environment.SpecialFolder Windows 7 (.NET Framework 4) Ubuntu 11.10 (Mono 2.10.8)
AdminTools C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools -
ApplicationData C:\Users\username\AppData\Roaming /home/username/.config
CDBurning C:\Users\username\AppData\Local\Microsoft\Windows\Burn\Burn1 -
CommonAdminTools C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools -
CommonApplicationData C:\ProgramData /usr/share
CommonDesktopDirectory C:\Users\Public\Desktop -
CommonDocuments C:\Users\Public\Documents -
CommonMusic C:\Users\Public\Music -
CommonOemLinks - -
CommonPictures C:\Users\Public\Pictures -
CommonProgramFiles C:\Program Files\Common Files -
CommonProgramFilesX86 C:\Program Files (x86)\Common Files -
CommonPrograms C:\ProgramData\Microsoft\Windows\Start Menu\Programs -
CommonStartMenu C:\ProgramData\Microsoft\Windows\Start Menu -
CommonStartup C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup -
CommonTemplates C:\ProgramData\Microsoft\Windows\Templates /usr/share/templates
CommonVideos C:\Users\Public\Videos -
Cookies C:\Users\username\AppData\Roaming\Microsoft\Windows\Cookies -
Desktop C:\Users\username\Desktop /home/username/Desktop
DesktopDirectory C:\Users\username\Desktop /home/username/Desktop
Favorites C:\Users\username\Favorites -
Fonts C:\windows\Fonts /home/username/.fonts
History C:\Users\username\AppData\Local\Microsoft\Windows\History -
InternetCache C:\Users\username\AppData\Local\Microsoft\Windows\Temporary Internet Files -
LocalApplicationData C:\Users\username\AppData\Local /home/username/.local/share
LocalizedResources - -
MyComputer - -
MyDocuments C:\Users\username\Documents /home/username
MyMusic C:\Users\username\Music /home/username/Music
MyPictures C:\Users\username\Pictures /home/username/Pictures
MyVideos C:\Users\username\Videos /home/username/Videos
NetworkShortcuts C:\Users\username\AppData\Roaming\Microsoft\Windows\Network Shortcuts -
Personal C:\Users\username\Documents /home/username
PrinterShortcuts C:\Users\username\AppData\Roaming\Microsoft\Windows\Printer Shortcuts -
ProgramFiles C:\Program Files -
ProgramFilesX86 C:\Program Files (x86) -
Programs C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs -
Recent C:\Users\username\AppData\Roaming\Microsoft\Windows\Recent -
Resources C:\windows\resources -
SendTo C:\Users\username\AppData\Roaming\Microsoft\Windows\SendTo -
StartMenu C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu -
Startup C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup -
System C:\windows\system32 -
SystemX86 C:\windows\SysWOW64 -
Templates C:\Users\username\AppData\Roaming\Microsoft\Windows\Templates /home/username
UserProfile C:\Users\username -
Windows C:\windows -
Environment.SpecialFolder Windows 7 (.NET Framework 4) Ubuntu 11.10 (Mono 2.10.8)
Environment.SpecialFolderと対応するフォルダの取得に使ったコード
using System;
using System.Linq;

class Sample {
  static void Main()
  {
    var typeOfSF = typeof(Environment.SpecialFolder);

    foreach (var name in Enum.GetNames(typeOfSF).OrderBy(n => n)) {
      var sf = (Environment.SpecialFolder)Enum.Parse(typeOfSF, name);
      var path = Environment.GetFolderPath(sf);

      Console.WriteLine("|{0,-30}|{1}|", name, path.Length == 0 ? "-" : path);
    }
  }
}

§1.8.2 ランタイムのディレクトリ

RuntimeEnvironment.GetRuntimeDirectoryメソッドを呼ぶことで現在動作しているランタイムが格納されているディレクトリを取得することが出来ます。

using System;
using System.Runtime.InteropServices;

class Sample {
  static void Main()
  {
    // ランタイムが格納されているディレクトリを取得・表示
    Console.WriteLine(RuntimeEnvironment.GetRuntimeDirectory());
  }
}
Windows 7 + .NET Framework 4での実行結果
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
Ubuntu 11.10 + Mono 2.10.5での実行結果
/usr/lib/mono/4.0

§1.8.3 一時フォルダ

一時ディレクトリを取得する・一時ファイルを作成するで解説しています。

§1.9 ファイルシステム

ファイルシステムの種類を調べる(Windows)で解説しています。

§1.10 レジストリ情報

RegistryKeyクラスを使うことで、レジストリに保存されている情報を読み込むことが出来ます。 次の例では、HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0を開き、CPU名(ProcessorNameString)を読み込み、表示しています。

using System;
using Microsoft.Win32;

class Sample {
  static void Main()
  {
    // HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0を開く
    using (RegistryKey cpu = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\CentralProcessor\0")) {
      // キー'ProcessorNameString'に設定されている値を読み込み、表示する
      Console.WriteLine(cpu.GetValue("ProcessorNameString"));
    }
  }
}
Windows 7 + .NET Framework 4での実行結果例
AMD Athlon(tm) 64 X2 Dual Core Processor 4200+

次の例では、HKEY_CURRENT_USERの下にある'MyApplication'というサブキーを開き、キー'foo'に設定されているデータを読み込んだ後、新しい値を上書きしています。

using System;
using Microsoft.Win32;

class Sample {
  static void Main()
  {
    // HKEY_CURRENT_USER\MyApplicationを書き込み可能な状態で開く
    using (RegistryKey myapp = Registry.CurrentUser.OpenSubKey("MyApplication", true)) {
      // キー'foo'に設定されている値を読み込み、表示する
      Console.WriteLine(myapp.GetValue("foo"));

      // キー'foo'に値"bar"を設定する
      myapp.SetValue("foo", "bar");
    }
  }
}

レジストリの読み取り・書き込みの実例についてはMIMEタイプの取得・判定壁紙を変更するなどを参照してください。

§2 時刻

§2.1 現在日時

現在日時を取得するにはDateTime.Nowプロパティを参照します。 日付のみを取得したい場合は、DateTime.Todayプロパティが使えます。 DateTime.Todayは、日付の部分はDateTime.Nowと同じで、時刻は常に00:00:00となった値を返します。 Now, Todayともにローカルタイムゾーンでの値を返しますが、DateTime.UtcNowを使えばUTC(世界協定時)での現在時刻を取得できます。

また、DateTime型でなくDateTimeOffset型で取得したければ、DateTimeOffset.NowDateTimeOffset.UtcNowを参照します。 だた、DateTimeOffset.Todayは用意されていないので、DateTimeOffset.Now.Dateとして現在時刻から日付のみを取得する必要があります。

using System;

class Sample {
  static void Main()
  {
    // 現在時刻 (DateTime)
    Console.WriteLine("DateTime.Now = {0}", DateTime.Now); // 現在の日時
    Console.WriteLine("DateTime.Now = {0}-{1}-{2}", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); // 現在の年・月・日
    Console.WriteLine("DateTime.Today = {0}", DateTime.Today); // 現在の日付
    Console.WriteLine("DateTime.UtcNow = {0}", DateTime.UtcNow); // UTCでの現在の日時
    Console.WriteLine();

    // 現在時刻 (DateTimeOffset)
    Console.WriteLine("DateTimeOffset.Now = {0}", DateTimeOffset.Now); // 現在の日時
    Console.WriteLine("DateTimeOffset.Now = {0}-{1}-{2}", DateTimeOffset.Now.Year, DateTimeOffset.Now.Month, DateTimeOffset.Now.Day); // 現在の年・月・日
    Console.WriteLine("DateTimeOffset.Now.Date = {0}", DateTimeOffset.Now.Date); // 現在の日付
    Console.WriteLine("DateTimeOffset.UtcNow = {0}", DateTimeOffset.UtcNow); // UTCでの現在の日時
  }
}
実行結果例
DateTime.Now = 2012/01/06 4:49:01
DateTime.Now = 2012-1-6
DateTime.Today = 2012/01/06 0:00:00
DateTime.UtcNow = 2012/01/05 19:49:01

DateTimeOffset.Now = 2012/01/06 4:49:01 +09:00
DateTimeOffset.Now = 2012-1-6
DateTimeOffset.Now.Date = 2012/01/06 0:00:00
DateTimeOffset.UtcNow = 2012/01/05 19:49:01 +00:00

DateTime・DateTimeOffsetについては日付・時刻の型と操作、タイムゾーンについては時刻の種類・UTCとの時差・タイムゾーン間の変換で解説しています。

§2.2 稼働時間

§2.2.1 Environment.TickCount

システムの稼働時間(uptime)を取得するには、Environment.TickCountプロパティを参照します。 このプロパティはシステムが起動してからの経過時間をミリ秒単位で返します。

TickCountは値がInt32.MaxValue(= 2147483647 = 約24.9日分)までカウントアップすると、次の値はInt32.MinValue(= -2147483648)に戻ってから再びカウントアップするという点に注意が必要です。 次の例では、TickCountの生の値と、生の値からTimeSpanに変換した値を表示しています。

using System;

class Sample {
  static void Main()
  {
    // 稼働時間を取得・表示する
    Console.WriteLine(Environment.TickCount);

    // 稼働時間を取得し、TimeSpanに変換する
    int tick = Environment.TickCount;
    TimeSpan uptime;

    if (0 <= tick)
      // TickCountが0~Int32.MaxValueまでの場合
      uptime = TimeSpan.FromMilliseconds((double)tick);
    else
      // TickCountがInt32.MinValue~-1までの場合
      uptime = TimeSpan.FromMilliseconds((double)(int.MinValue + tick) + (double)int.MaxValue);

    Console.WriteLine("{0} days, {1}:{2}:{3}", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds);
  }
}
実行結果例
708073440
8 days, 4:41:13

TickCountが返す値の精度は500ミリ秒以上となる点にも注意が必要です。 TickCountと精度についてはSystem.Diagnostics.Stopwatchでも解説しています。

§2.2.2 パフォーマンスカウンタ

Environment.TickCountとは別に、次の例のようにパフォーマンスカウンタを使って稼働時間を取得する方法もあります。 パフォーマンスカウンタを使った場合は、秒単位の値で取得できます。

using System;
using System.Diagnostics;

class Sample {
  static void Main()
  {
    // System/System Up Timeを計測するパフォーマンスカウンタを作成
    PerformanceCounter pc = new PerformanceCounter("System", "System Up Time");

    pc.NextValue(); // 最初の呼び出しでは常に0が返されるので値を破棄

    // 稼働時間(秒単位)を取得
    float tick = pc.NextValue();

    Console.WriteLine(tick);

    // 取得した稼働時間をTimeSpanに変換
    TimeSpan uptime = TimeSpan.FromSeconds(tick);

    Console.WriteLine("{0} days, {1}:{2}:{3}", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds);
  }
}
実行結果例
1425.846
0 days, 0:23:45

パフォーマンスカウンタの使い方についてはパフォーマンス情報の計測を参照してください。

§2.3 経過時間

経過時間を計測するには、二つの時点でのEnvironment.TickCountの差を取るなどの方法の他に、Stopwatchクラスを使う方法があります。 次のコードでは、Environment.TickCountとStopwatchを使ってある処理にかかる時間を計測する方法を例示しています。

using System;
using System.Diagnostics;
using System.Threading;

class Sample {
  static void Main()
  {
    // 開始時点のタイマ刻みを保持
    int tickStart = Environment.TickCount;

    // 経過時間を計測したい処理を実行 (ここでは時間がかかる処理の代わりとしてThread.Sleepを使う)
    Thread.Sleep(1000);

    // 終了時点のタイマ刻みを保持
    int tickEnd = Environment.TickCount;

    // 計測した経過時間を表示
    Console.WriteLine("TickCount : {0}", TimeSpan.FromMilliseconds(tickEnd - tickStart));



    // Stopwatchを作成すると同時に、経過時間の計測を開始
    Stopwatch sw = Stopwatch.StartNew();

    // 経過時間を計測したい処理を実行 (同上)
    Thread.Sleep(1000);

    // 経過時間の計測を止める
    sw.Stop();

    // 計測した経過時間を表示
    Console.WriteLine("Stopwatch : {0}", sw.Elapsed);
  }
}
実行結果例
TickCount : 00:00:01
Stopwatch : 00:00:01.0002382

Stopwatchの使い方や計測できる値の精度など、詳しくはSystem.Diagnostics.Stopwatchで解説しています。