时间戳 太平洋夏令时间和本地时间相互转换及自定义夏令时

自定义夏令时及时区转换官网案例不详细,真是脑袋大。。。。。

时区转换 时间戳转本地时间  太平洋夏令时 PDT PST

太平洋时间

在2006年以及之前,美国太平洋时区总是于每年四月第一个星期日深夜二时正将本地时间(UTC−8)转成夏令时间(UTC−7) ,并于十月的最后一个星期日深夜二时正转回本地时间。

于2007年生效的2005年能源政策法案,决定了美国太平洋时区的夏令时间始于每年三月的第二个星期六深夜二时正,并终于每年十一月的第一个星期日深夜二时正。而加拿大亦跟随美国的夏令时间制度。

TimeZoneInfo是某个地方时区转换类。通过此类可以进行各时区自定义和转换。

TimeZoneInfo.AdjustmentRule定义某个地区国家的某个时间段的夏令时,一个国家或地区可能有多个,如上面太平洋时间有两个TimeZoneInfo.AdjustmentRule。
第一个为从时间戳为零(1年1月1日0时0分0秒)开始,到2006年12月31日止。

第二个为2007年第一天(2007年1月1日0时0分0秒)到c#计时最大值最后一天

TimeZoneInfo.TransitionTime为定义某个时间段(如上面从时间戳为零(1年1月1日0时0分0秒)开始,到2006年12月31日止)的夏令时间时间的开始时间和结束时间。通过
TimeZoneInfo.TransitionTime CreateFloatingDateRule(
  DateTime timeOfDay,
  int month,
  int week,
  DayOfWeek dayOfWeek)方法创建。

timeOfDay参数的年月日都是从1年1月1日(时间开始的第一天)

如:

 TimeZoneInfo.TransitionTime startTransitionTow= TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
    new DateTime(1, 1, 1, 2, 0, 0),
    4, 2, DayOfWeek.Sunday);

此方法创建了一个夏令时开始时间为每年4月第2个(参数2)星期天(参数DayOfWeek.Sunday)一个时间点。

.net 3.5版本居然不支持TimeZoneInfo.ConvertTime()。只能单独写写方法。

夏令时相互转换全部代码如下:

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;

public class TimeTool
{
   static TimeTool()
    {
        palmer = GetTimeZoneInfoPDTAndPST();;
    }

    /// <summary>
    /// 时间戳开始时间
    /// </summary>
    private static DateTime utsTime = new DateTime(1970, 1, 1, 0, 0, 0, kind: DateTimeKind.Utc);
   private static TimeZoneInfo palmer;
    private static long unit = 10000000;
    private static long startTimeStamp = utsTime.Ticks / unit;
    private enum WeekOfMonth
    {
        First = 1,
        Second = 2,
        Third = 3,
        Fourth = 4,
        Last = 5,
    }

    #region net.35以上版本(net.3.5一下版本TimeZoneInfo.Local属性为null不兼容)

    /// <summary>
    /// 通过夏令时或者太平洋标准时间转换到时间戳
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static long GetPDTAndPSTByString(string time)
    {
        DateTime dateTimeUtc = DateTime.Parse(time);
        DateTime PDTOrPST = TimeZoneInfo.ConvertTime(dateTimeUtc, palmer, TimeZoneInfo.Utc);
        return (PDTOrPST - utsTime).Ticks / unit;
    }

    /// <summary>
    /// 时间戳转换夏令时或者太平洋标准时间
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static DateTime TimeStampToPDTAndPST(long time)
    {
        DateTime dateTimeUtc = utsTime + new TimeSpan(time * unit);
        DateTime PDTOrPST = TimeZoneInfo.ConvertTime(dateTimeUtc, TimeZoneInfo.Utc, palmer);
        return PDTOrPST;
    }

    /// <summary>
    /// 时间戳转换到本地时间
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static DateTime TimeStampToLocal(long time)
    {
        DateTime dateTime = utsTime + new TimeSpan(time * unit);
        return TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Utc, TimeZoneInfo.Local);
    }

    /// <summary>
    /// 太平洋时间转本地时间
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static DateTime PDTAndPSTToLocal(DateTime dateTime)
    {
        return TimeZoneInfo.ConvertTime(dateTime, palmer, TimeZoneInfo.Local);
    }

    /// <summary>
    /// 太平洋时间转时间戳
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static long PDTAndPSTToTimeStamp(DateTime dateTime)
    {
        DateTime temp = TimeZoneInfo.ConvertTime(dateTime, palmer, TimeZoneInfo.Utc);
        return (temp - utsTime).Ticks / unit;
    }


    /// <summary>
    /// 本地时间转换太平洋时间
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static DateTime LocalToPDTOrPST(DateTime dateTime)
    {
        return TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, palmer);
    }

    /// <summary>
    /// 本地时间转时间戳
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static long LocalToTimeStamp(DateTime dateTime)
    {
        DateTime temp = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, TimeZoneInfo.Utc);
        return (temp - utsTime).Ticks / unit;
    }


    /// <summary>
    /// 获取太平洋标准时间或者夏令时间
    /// 在2006年以及之前,美国太平洋时区总是于每年四月第一个星期日深夜二时正将本地时间(UTC−8)转成夏令时间(UTC−7) ,并于十月的最后一个星期日深夜二时正转回本地时间。
    ///于2007年生效的2005年能源政策法案,决定了美国太平洋时区的夏令时间始于每年三月的第二个星期六深夜二时正,并终于每年十一月的第一个星期日深夜二时正。而加拿大亦跟随美国的夏令时间制度。
    /// </summary>
    /// <returns></returns>
    public static TimeZoneInfo GetTimeZoneInfoPDTAndPST()
    {
        TimeSpan delta = new TimeSpan(1, 0, 0);
        TimeZoneInfo.AdjustmentRule adjustment;
        DateTime startDateTime = new DateTime(1, 1, 1);
        DateTime endDateTime = new DateTime(2006, 12, 31);
        TimeSpan time = new TimeSpan(0, 2, 0, 0, 0);
        adjustment = GetAdjustmentRulePDTAndPST(
            startDateTime,
            time,
            4,
            DayOfWeek.Sunday,
            WeekOfMonth.First,
            endDateTime,
            time,
            10,
            DayOfWeek.Sunday,
            WeekOfMonth.Last,
            delta);
        DateTime startDateTimeTow = new DateTime(2007, 1, 1);
        DateTime endDateTimeTwo = DateTime.MaxValue.Date;
        endDateTimeTwo.AddHours(2);
        TimeZoneInfo.AdjustmentRule adjustmentTow = GetAdjustmentRulePDTAndPST(
            startDateTimeTow,
            time,
            3,
            DayOfWeek.Sunday,
            WeekOfMonth.Second,
            endDateTimeTwo,
            time,
            11,
            DayOfWeek.Sunday,
            WeekOfMonth.First,
            delta);
        // Create array for adjustment rules
        TimeZoneInfo.AdjustmentRule[] adjustments = {adjustment, adjustmentTow};
        // Define other custom time zone arguments
        string displayName = "(GMT-08:00) Palmer Time";
        string standardName = "Palmer Time";
        string daylightName = "Palmer Daylight Time";
        TimeSpan offset = new TimeSpan(-8, 0, 0);
        TimeZoneInfo palmer = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, displayName, standardName,
            daylightName, adjustments);
        return palmer;
    }

    /// <summary>
    /// 获取夏令时时间规则
    /// </summary>
    /// <param name="startDateTime">夏令时的开始时间</param>
    /// <param name="startMonth">夏令时开始月份</param>
    /// <param name="startDayOfWeek">夏令时星期几开始</param>
    /// <param name="startWeekOfMonth">夏令时开始月份第几周</param>
    /// <param name="endDateTime">夏令时的结束时间</param>
    /// <param name="endMonth">夏令时结束月份</param>
    /// <param name="endDayOfWeek">夏令时星期几结束</param>
    /// <param name="endWeekOfMonth">夏令时结束月份第几周</param>
    /// <param name="delta">夏令时调整时间</param>
    /// <returns></returns>
    private static TimeZoneInfo.AdjustmentRule GetAdjustmentRulePDTAndPST(
        DateTime startDateTime,
        TimeSpan startTime,
        int startMonth,
        DayOfWeek startDayOfWeek,
        WeekOfMonth startWeekOfMonth,
        DateTime endDateTime,
        TimeSpan endTime,
        int endMonth,
        DayOfWeek endDayOfWeek,
        WeekOfMonth endWeekOfMonth,
        TimeSpan delta)
    {
        TimeZoneInfo.TransitionTime startTransitionTow, endTransitionTow;
        startTransitionTow = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
            new DateTime(1, 1, 1, startTime.Hours, startTime.Minutes, startTime.Seconds),
            startMonth, (int) startWeekOfMonth, startDayOfWeek);
        endTransitionTow = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
            new DateTime(1, 1, 1, endTime.Hours, endTime.Minutes, endTime.Seconds),
            endMonth, (int) endWeekOfMonth, endDayOfWeek);
        startDateTime = new DateTime(startDateTime.Year, startDateTime.Month, startDateTime.Day);
        endDateTime = new DateTime(endDateTime.Year, endDateTime.Month, endDateTime.Day);
        TimeZoneInfo.AdjustmentRule adjustmentTow;
        adjustmentTow = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
            startDateTime,
            endDateTime,
            delta,
            startTransitionTow,
            endTransitionTow);
        return adjustmentTow;
    }

    #endregion

    #region net.3.5兼容接口

    /// 获取太平洋标准时间或者夏令时间
    /// 在2006年以及之前,美国太平洋时区总是于每年四月第一个星期日深夜二时正将本地时间(UTC−8)转成夏令时间(UTC−7) ,并于十月的最后一个星期日深夜二时正转回本地时间。
    ///于2007年生效的2005年能源政策法案,决定了美国太平洋时区的夏令时间始于每年三月的第二个星期六深夜二时正,并终于每年十一月的第一个星期日深夜二时正。而加拿大亦跟随美国的夏令时间制度。
    struct PDSData
    {
        /// <summary>
        /// 下令时区开始时间
        /// </summary>
        public DateTime PDTStart;

        /// <summary>
        /// 夏令时区结束时间
        /// </summary>
        public DateTime PDTPSTEnd;

        public bool IsDaylightSavingTime(DateTime dateTime)
        {
            //dateTime为标准太平洋时间(-8时区),实际夏令时向前推一个小时(-7时区),所以结束时间需要向前推一个小时
            return dateTime >= PDTStart && dateTime < PDTPSTEnd.AddHours(-1);
        }
        /// <summary>
        /// 通过太平洋夏令时间判断是否在夏令时
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public bool IsDaylightSavingTimeByPST(DateTime dateTime)
        {
            //dateTime为标准太平洋时间(-8时区),实际夏令时向前推一个小时(-7时区),所以结束时间需要向前推一个小时
            return dateTime >= PDTStart && dateTime < PDTPSTEnd;
        }

        public override string ToString()
        {
            return string.Format("PDTStart:{0}   PDTPSTEnd{1} ", PDTStart, PDTPSTEnd);
        }
    }


    /// <summary>
    /// 时间戳转换太平洋标准时间或者夏令时间
    /// 在2006年以及之前,美国太平洋时区总是于每年四月第一个星期日深夜二时正将本地时间(UTC−8)转成夏令时间(UTC−7) ,并于十月的最后一个星期日深夜二时正转回本地时间。
    ///于2007年生效的2005年能源政策法案,决定了美国太平洋时区的夏令时间始于每年三月的第二个星期六深夜二时正,并终于每年十一月的第一个星期日深夜二时正。而加拿大亦跟随美国的夏令时间制度。
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static DateTime TimeStampToPDTAndPST3_5(long time)
    {
        DateTime gmtTime = utsTime.AddSeconds(time);
        gmtTime = gmtTime.AddHours(-8);
        PDSData pdsData = getDaylightSavingTimeState();
        if (pdsData.IsDaylightSavingTime(gmtTime))
        {
            gmtTime = gmtTime.AddHours(1); //夏令时前推1小时
        }

        return gmtTime;
    }


    private static PDSData getDaylightSavingTimeState()
    {
        PDSData _pdsData = new PDSData
        {
            PDTStart = getDaylightSavingTime(DateTime.Now.Year, 3, WeekOfMonth.Second, 2),
            PDTPSTEnd = getDaylightSavingTime(DateTime.Now.Year, 11, WeekOfMonth.First, 2),
        };
        return _pdsData;
    }

    /// <summary>
    /// 获取夏令时状态时间
    /// </summary>
    /// <param name="year"></param>
    /// <param name="month"></param>
    /// <param name="week"></param>
    /// <param name="hour"></param>
    /// <returns></returns>
    private static DateTime getDaylightSavingTime(int year, int month, WeekOfMonth week, int hour)
    {
        DateTime start;
        int dayCount;
        if (week == WeekOfMonth.Last)
        {
            start = new DateTime(year, month + 1, 1, hour, 0, 0);
            dayCount = (7 - (int) start.DayOfWeek) % 7 - 7; //通过下一个月1号计算当月月最后一个星期日天数差
        }
        else
        {
            start = new DateTime(year, month, 1, hour, 0, 0);
            dayCount = (7 - (int) start.DayOfWeek) % 7; //计算当月1号开始的第一个星期日天数差
        }

        int weekCount = 7 * ((int) week - 1);
        start = start.AddDays(dayCount + weekCount);
        return start;
    }
    /// <summary>
    /// 时间戳转换到本地时间
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static DateTime TimeStampToLocal3_5(long time)
    {
        DateTime dateTime = utsTime + new TimeSpan(time * unit);
        return TimeZone.CurrentTimeZone.ToLocalTime(dateTime);
    }
    /// <summary>
    /// 太平洋标准时间或者夏令时间转换时间戳
    /// 在2006年以及之前,美国太平洋时区总是于每年四月第一个星期日深夜二时正将本地时间(UTC−8)转成夏令时间(UTC−7) ,并于十月的最后一个星期日深夜二时正转回本地时间。
    ///于2007年生效的2005年能源政策法案,决定了美国太平洋时区的夏令时间始于每年三月的第二个星期六深夜二时正,并终于每年十一月的第一个星期日深夜二时正。而加拿大亦跟随美国的夏令时间制度。
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static long PDTAndPSTToTimeStamp3_5(DateTime dateTime)
    {
        PDSData pdsData = getDaylightSavingTimeState();
        if (pdsData.IsDaylightSavingTimeByPST(dateTime))
        {
            dateTime = dateTime.AddHours(7); //夏令时推1小时
        }
        else
        {
            dateTime = dateTime.AddHours(8);
        }


        return (dateTime - utsTime).Ticks / unit;
    }
    /// <summary>
    /// 太平洋时间转本地时间
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static DateTime PDTAndPSTToLocal3_5(DateTime dateTime)
    {
        long time  = PDTAndPSTToTimeStamp3_5(dateTime);
        
        dateTime = utsTime+ new TimeSpan(time*unit);
        return TimeZone.CurrentTimeZone.ToLocalTime(dateTime);
    }

    /// <summary>
    /// 本地时间转时间戳
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static long LocalToTimeStamp3_5(DateTime dateTime)
    {
        DateTime temp = TimeZone.CurrentTimeZone.ToUniversalTime(dateTime);
        return (temp - utsTime).Ticks / unit;
    }


    /// <summary>
    /// 本地时间转换太平洋时间
    /// </summary>
    /// <param name="dateTime"></param>
    /// <returns></returns>
    public static DateTime LocalToPDTOrPST3_5(DateTime dateTime)
    {
        dateTime = TimeZone.CurrentTimeZone.ToUniversalTime(dateTime);
        TimeZoneInfo palmer = GetTimeZoneInfoPDTAndPST();
        return TimeZoneInfo.ConvertTimeFromUtc(dateTime, palmer);
    }
    #endregion

    #region 调试代码

    public static void ShowStartAndEndDates()
    {
        ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
        foreach (TimeZoneInfo timeZone in timeZones)
        {
            if (timeZone.Id == "Pacific Standard Time")
            {
                Print(timeZone);
            }
        }
    }


    public static void Print(TimeZoneInfo timeZone)
    {
      //  Debug.LogError("================" + timeZone.BaseUtcOffset.Hours);
        string[] monthNames = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;
        TimeZoneInfo.AdjustmentRule[] adjustments = timeZone.GetAdjustmentRules();
        // Display message for time zones with no adjustments
        if (adjustments.Length == 0)
        {
           // Debug.LogErrorFormat("{0} has no adjustment rules", timeZone.StandardName);
        }
        else
        {
            // Handle time zones with 1 or 2+ adjustments differently
            bool showCount = false;
            int ctr = 0;
            string spacer = "";
            // builder.Append(string.Format("{0} Adjustment rules", timeZone.StandardName));
          //  Debug.LogErrorFormat("{0} Adjustment rules", timeZone.StandardName);
            if (adjustments.Length > 1)
            {
                showCount = true;
                spacer = "   ";
            }

            // Iterate adjustment rules
            foreach (TimeZoneInfo.AdjustmentRule adjustment in adjustments)
            {
                StringBuilder builder = new StringBuilder();

                if (showCount)
                {
                    builder.Append(string.Format("   Adjustment rule #{0}", ctr + 1));
                    //Debug.LogErrorFormat("   Adjustment rule #{0}", ctr + 1);
                    ctr++;
                }

                // Display general adjustment information
                builder.Append(string.Format("{0}   Start Date: {1:D} \n", spacer, adjustment.DateStart));
                builder.Append(string.Format("{0}   End Date: {1:D} \n", spacer, adjustment.DateEnd));
                builder.Append(string.Format("{0}   Time Change: {1}:{2:00} hours \n", spacer,
                    adjustment.DaylightDelta.Hours, adjustment.DaylightDelta.Minutes));
                // Debug.LogErrorFormat("{0}   Start Date: {1:D}", spacer, adjustment.DateStart);
                // Debug.LogErrorFormat("{0}   End Date: {1:D}", spacer, adjustment.DateEnd);
                // Debug.LogErrorFormat("{0}   Time Change: {1}:{2:00} hours", spacer,
                //     adjustment.DaylightDelta.Hours, adjustment.DaylightDelta.Minutes);

                // Get transition start information
                TimeZoneInfo.TransitionTime transitionStart = adjustment.DaylightTransitionStart;
                //Debug.LogErrorFormat("{0}   Annual Start: ", spacer);
                builder.Append(string.Format("{0}   Annual Start: \n", spacer));
                if (transitionStart.IsFixedDateRule)
                {
                    builder.Append(string.Format("On {0} {1} at {2:t}",
                        monthNames[transitionStart.Month - 1],
                        transitionStart.Day,
                        transitionStart.TimeOfDay));
                    // Debug.LogErrorFormat("On {0} {1} at {2:t}",
                    //     monthNames[transitionStart.Month - 1],
                    //     transitionStart.Day,
                    //     transitionStart.TimeOfDay);
                }
                else
                {
                    builder.Append(string.Format("The year {0}  mounth{1} day {2}  TimeOfDay{3}  DayOfWeek{4}  \n",
                        1, transitionStart.Month, transitionStart.Day, transitionStart.TimeOfDay,
                        transitionStart.DayOfWeek));
                    builder.Append(string.Format("The {0} {1} of {2} at {3:t} \n",
                        ((WeekOfMonth) transitionStart.Week).ToString(),
                        transitionStart.DayOfWeek.ToString(),
                        monthNames[transitionStart.Month - 1],
                        transitionStart.TimeOfDay));

                    // Debug.LogErrorFormat("The year {0}  mounth{1} day {2}  TimeOfDay{3}  DayOfWeek{4}",
                    //     1, transitionStart.Month, transitionStart.Day, transitionStart.TimeOfDay,
                    //     transitionStart.DayOfWeek);
                    // Debug.LogErrorFormat("The {0} {1} of {2} at {3:t}",
                    //     ((WeekOfMonth) transitionStart.Week).ToString(),
                    //     transitionStart.DayOfWeek.ToString(),
                    //     monthNames[transitionStart.Month - 1],
                    //     transitionStart.TimeOfDay);
                }

                // Get transition end information
                TimeZoneInfo.TransitionTime transitionEnd = adjustment.DaylightTransitionEnd;
                builder.Append(string.Format("{0}   Annual End: ", spacer));

                //Debug.LogErrorFormat("{0}   Annual End: ", spacer);
                if (transitionEnd.IsFixedDateRule)
                {
                    builder.Append(string.Format("On {0} {1} at {2:t}",
                        monthNames[transitionEnd.Month - 1],
                        transitionEnd.Day,
                        transitionEnd.TimeOfDay));

                    // Debug.LogErrorFormat("On {0} {1} at {2:t}",
                    //     monthNames[transitionEnd.Month - 1],
                    //     transitionEnd.Day,
                    //     transitionEnd.TimeOfDay);
                }
                else
                {
                    builder.Append(string.Format("The year {0}  mounth{1} day {2}  TimeOfDay{3}  DayOfWeek{4}  \n",
                        1, transitionEnd.Month, transitionEnd.Day, transitionEnd.TimeOfDay, transitionEnd.DayOfWeek));
                    builder.Append(string.Format("The {0} {1} of {2} at {3:t}",
                        ((WeekOfMonth) transitionEnd.Week).ToString(),
                        transitionEnd.DayOfWeek.ToString(),
                        monthNames[transitionEnd.Month - 1],
                        transitionEnd.TimeOfDay));
                    //
                    // Debug.LogErrorFormat("The year {0}  mounth{1} day {2}  TimeOfDay{3}  DayOfWeek{4}",
                    //     1, transitionEnd.Month, transitionEnd.Day, transitionEnd.TimeOfDay, transitionEnd.DayOfWeek);
                    // Debug.LogErrorFormat("The {0} {1} of {2} at {3:t}",
                    //     ((WeekOfMonth) transitionEnd.Week).ToString(),
                    //     transitionEnd.DayOfWeek.ToString(),
                    //     monthNames[transitionEnd.Month - 1],
                    //     transitionEnd.TimeOfDay);
                }

               // Debug.LogError(builder);
            }
        }
    }

    #endregion
}

猜你喜欢

转载自blog.csdn.net/fengya1/article/details/127780192