1

.NET 2.0でレガシーアプリケーションに取り組んでおり、時刻を現地時間(たまたまUTC + 1)からブラジルの時間(Windowsでは「南米標準時」と呼んでいます)に変換したいと考えています。帰ってきた。

変換を行うために思いついたこのコードをまとめました。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace timezone
{
 class Program
 {
  [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
  private static extern int SystemTimeToTzSpecificLocalTime(ref
   TIME_ZONE_INFORMATION lpTimeZone, ref SYSTEMTIME lpUniversalTIme, out
   SYSTEMTIME lpLocalTime);

  [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
  private static extern int TzSpecificLocalTimeToSystemTime(ref
   TIME_ZONE_INFORMATION lpTimeZone, ref SYSTEMTIME lpLocalTime, out SYSTEMTIME
   lpUniversalTIme);

  [DllImport("kernel32.dll")]
  private static extern void GetSystemTime(out SYSTEMTIME lpSystemTime);

  [StructLayout(LayoutKind.Sequential)]
  private struct SYSTEMTIME
  {
   public ushort wYear;
   public ushort wMonth;
   public ushort wDayOfWeek;
   public ushort wDay;
   public ushort wHour;
   public ushort wMinute;
   public ushort wSecond;
   public ushort wMilliseconds;
  }

  //Registry time zone format. See KB article Q115231
  [StructLayout(LayoutKind.Sequential)]
  private struct REG_TIME_ZONE_INFORMATION
  {
   public int Bias;
   public int StandardBias;
   public int DaylightBias;
   public SYSTEMTIME StandardDate;
   public SYSTEMTIME DaylightDate;
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  private struct TIME_ZONE_INFORMATION
  {
   public int Bias;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
   public string StandardName;
   public SYSTEMTIME StandardDate;
   public int StandardBias;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
   public string DaylightName;
   public SYSTEMTIME DaylightDate;
   public int DaylightBias;
  }

  private static List<TIME_ZONE_INFORMATION> GetTimeZones()
  {
   List<TIME_ZONE_INFORMATION> list = new List<TIME_ZONE_INFORMATION>();
   RegistryKey key =
   Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones");
   if (key == null)
    return list;

   string[] subKeyNames = key.GetSubKeyNames();
   foreach (string subKeyName in subKeyNames)
   {
    RegistryKey subKey = key.OpenSubKey(subKeyName);
    if (subKey != null)
    {
     object value = subKey.GetValue("TZI");
     if (value != null)
     {
      int length =
      Marshal.SizeOf(typeof(REG_TIME_ZONE_INFORMATION));
      IntPtr p = Marshal.AllocHGlobal(length);
      Marshal.Copy((byte[])value, 0, p, length);
      REG_TIME_ZONE_INFORMATION rtzi =
      (REG_TIME_ZONE_INFORMATION)Marshal.PtrToStructure(p,
      typeof(REG_TIME_ZONE_INFORMATION));
      Marshal.FreeHGlobal(p);

      TIME_ZONE_INFORMATION tzi = new TIME_ZONE_INFORMATION();
      tzi.Bias = rtzi.Bias;
      tzi.DaylightBias = rtzi.DaylightBias;
      tzi.StandardBias = rtzi.StandardBias;
      tzi.DaylightDate = rtzi.DaylightDate;
      tzi.StandardDate = rtzi.StandardDate;
      tzi.DaylightName = (string)subKey.GetValue("Dlt", "");
      tzi.StandardName = (string)subKey.GetValue("Std", "");
      list.Add(tzi);
     }
     subKey.Close();
    }
   }
   key.Close();
   return list;
  }

  static void Main(string[] args)
  {
   foreach (TIME_ZONE_INFORMATION tzi in GetTimeZones())
   {
    if ("E. South America Standard Time" == tzi.StandardName)
    {
     Console.WriteLine("local time: " + DateTime.Now);
     Console.WriteLine("name: {0} st bias:{1} daylight date:{2}-{3}-{4}, bias:{5}", tzi.StandardName, tzi.DaylightBias, tzi.DaylightDate.wDay, tzi.DaylightDate.wMonth, tzi.DaylightDate.wYear, tzi.Bias);
     TIME_ZONE_INFORMATION tzi2 = tzi; //local copy so that i can pass it as a ref
     SYSTEMTIME braziltime = new SYSTEMTIME();
     SYSTEMTIME localtime = new SYSTEMTIME();
     GetSystemTime(out localtime);
     SystemTimeToTzSpecificLocalTime(ref tzi2, ref localtime, out braziltime);
     Console.WriteLine("{0}:{1}", braziltime.wHour, braziltime.wMinute);
     Console.WriteLine("{0}-{1}-{2} {3}:{4}:{5}", braziltime.wYear, braziltime.wMonth, braziltime.wDay, braziltime.wHour, braziltime.wMinute, braziltime.wSecond);
     DateTime dt = DateTime.Now;
     braziltime.wYear = (ushort)dt.Year;
     braziltime.wMonth = (ushort)dt.Month;
     braziltime.wDay = (ushort)dt.Day;
     braziltime.wHour = (ushort)(dt.Hour - 3); //today the timezone difference is 3 hours
     braziltime.wMinute = (ushort)dt.Minute;
     braziltime.wSecond = (ushort)dt.Second;
     TzSpecificLocalTimeToSystemTime(ref tzi2, ref braziltime, out localtime);
     Console.WriteLine("{0}-{1}-{2} {3}:{4}:{5}", localtime.wYear, localtime.wMonth, localtime.wDay, localtime.wHour, localtime.wMinute, localtime.wSecond);
     break;
    }
   }
   Console.ReadLine();
  }
 }
}

しかし、私はこの出力を取得します:

local time: 11/22/2010 11:55:15 AM
name: E. South America Standard Time st bias:-60 daylight date:3-10-0, bias:180 8:55
2010-11-22 8:55:15
2010-11-22 10:55:15

だから私は現地時間をブラジルの時間に変換して戻し、1時間短縮します。何が問題なのですか?

4

3 に答える 3

1

出力の最初の行が最後の行と一致することを期待していると思います。最初の行が現地時間を書き込んでいるため、これは発生していません。次に、GetSystemTimeを呼び出し、その値をブラジル時間に変換して、再度戻します。GetSystemTimeはUTCを返すため、最後の行に戻って出力する値もUTCである必要があります。言い換えれば、あなたはlikeとlikeを比較していません。

GetSystemTimeの呼び出しの直後にlocaltimeの値を出力すると、変換後に出力された値と一致することがわかります。

現地時間からブラジル時間に変換する場合は、おそらく現地時間をUTCに変換してから、各ステップの適切なタイムゾーン情報を使用してUTCをブラジル時間に変換する必要があります。

于 2010-11-22T11:41:19.820 に答える
0

DateTimeは、日時を格納するための単なる構造体であることを忘れないでください。

アプリUTCのどこでも使用し、出力にはロケールを使用する必要があります。きれいにするために、私はほとんどの場合utcを使用し、それから変換を行うことを好みます。

于 2010-11-22T11:34:15.663 に答える
0

3.5だったら...

using System;

// ReSharper disable once CheckNamespace
public static class BrazilTime
{
    public static DateTime Now
    {
        get
        {
            return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time"));
        }
    }
}
于 2015-07-03T13:36:33.987 に答える