LoginSignup
2
2

More than 5 years have passed since last update.

Windowsのローカルタイムゾーン設定をtz database名で取得

Last updated at Posted at 2014-07-15

Windowsのローカルタイムゾーン設定をtz database名で取得しようとすると、結構めんどくさい。

MSDNで検索すると、タイムゾーンを取得するには、GetTimeZoneInformationを使えとある。

#include <windows.h>

int main()
{
  TIME_ZONE_INFORMATION tzi;

  memset(&tzi, 0,sizeof(tzi));
  GetTimeZoneInformation(&tzi);

  // #define UNICODEしていなくてもwchar_tで取得される
  MessageBoxW(NULL, tzi.StandardName, NULL, MB_OK);
  return 0;
}

これで取得できる名称は「東京 (標準時)」のような文字列で、おそらく中国語のWindowsなら「东京」とかが取得できちゃう、これ誰が得するんだよという糞仕様のAPIなので、これをまず英語名に変換するため、レジストリを検索する。

レジストリの"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"に、英語名のディレクトリ名が並んでいて、その中のStdに、タイムゾーンの日本語名が入っているので、これを使う。

timezone.png

#include <windows.h>
#include <stdio.h>

enum {
  MAX_NAME_LEN = 64,
};

static void convert_english_tzname(char *dst, const wchar_t *src)
{
  const wchar_t *path = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones";
  HKEY hKey;
  int i;

  if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
    strcpy(dst, "UTC");
    return;
  }
  for (i = 0; ; i++) {
    wchar_t wbuf[MAX_NAME_LEN];
    DWORD wbuf_size = MAX_NAME_LEN;

    switch (RegEnumKeyExW(hKey, i, wbuf, &wbuf_size, 0, NULL, NULL, NULL)) {
    case ERROR_SUCCESS: {
      HKEY hKey2;
      if (RegOpenKeyExW(hKey, wbuf, 0, KEY_READ, &hKey2) == ERROR_SUCCESS) {
        wchar_t wbuf2[MAX_NAME_LEN];
        DWORD wbuf2_size = MAX_NAME_LEN * sizeof(wchar_t);
        DWORD type;

        if (RegQueryValueExW(hKey2, L"Std", NULL, &type, (BYTE*)wbuf2, &wbuf2_size) == ERROR_SUCCESS) {
          if (type == REG_SZ && wcscmp(wbuf2, src) == 0) {
            WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, dst, 64, NULL, NULL);
            RegCloseKey(hKey2);
            goto BREAK;
          }
        }
        RegCloseKey(hKey2);
       }
       break;
    }
    case ERROR_NO_MORE_ITEMS:
      strcpy(dst, "UTC");
      goto BREAK;
    default:
      break;
    }
  }
BREAK:
  RegCloseKey(hKey);
}
int main()
{
  char cbuf[MAX_NAME_LEN];
  TIME_ZONE_INFORMATION tzi;

  memset(&tzi, 0,sizeof(tzi));
  GetTimeZoneInformation(&tzi);
  convert_english_tzname(cbuf, tzi.StandardName);

  printf("%s\n", cbuf);
  return 0;
}

これでやっとタイムゾーンの英語名が取得できたが、もちろんこれで終わりではない。
Windowsのタイムゾーン名とtz databaseのタイムゾーン名の変換は、以下の表を使うとよいが、一対一の対応になっていないことに注意。

新たに国が独立してタイムゾーンが増えたりしない限り、この表を更新する必要はない。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2