实现时区的转换--涉及到冬令时和夏令时的时候

Posted liwenqian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现时区的转换--涉及到冬令时和夏令时的时候相关的知识,希望对你有一定的参考价值。

时区转换

主要是用来转换时区用的,特别涉及到冬令时和夏令时的区域,这样会很烦,所以需要用个方法来转换

这个主要是创建一些模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tools.TimeZone
{

    /// <summary>
    /// 国家时区类型
    /// </summary>
    public enum ZoneType
    {
        Same = 0,//普通的时区转换
        Summer = 1,//启用夏时令 在夏令时的时候比冬令时早1个小时
    }


    /// <summary>
    /// 时区
    /// </summary>
    public class TimeZoneModel
    {
        /// <summary>
        /// 冬令时GMT
        /// </summary>
        public int GMT { get; set; }


        /// <summary>
        /// 这个国家应用的时区是什么
        /// </summary>
        public ZoneType ZoneType { get; set; }

        /// <summary>
        /// 时区名称
        /// </summary>
        public string ZoneName { get; set; }
        /// <summary>
        /// 时区备注
        /// </summary>
        public string ZoneRemark { get; set; }

        /// <summary>
        /// 夏时令开始时间
        /// </summary>
        public TimeNode BeginDate { get; set; }

        /// <summary>
        /// 夏时令结束时间
        /// </summary>
        public TimeNode EndDate { get; set; }


    }
    /// <summary>
    /// 时间节点
    /// </summary>
    public class TimeNode
    {
        /// <summary>
        /// 月份
        /// </summary>
        public int Month { get; set; }
        /// <summary>
        /// 排序方式
        /// </summary>
        public Sort Sort { get; set; }
        /// <summary>
        /// 第几个
        /// </summary>
        public int Num { get; set; }
        /// <summary>
        /// 周几
        /// </summary>
        public DayOfWeek DayOfWeek { get; set; }

        /// <summary>
        /// 几点开始
        /// </summary>
        public int Hours { get; set; } = 0;//一般是0点开始
    }
    /// <summary>
    /// 查找方式
    /// </summary>
    public enum Sort
    {
        /// <summary>
        /// 倒数第几个
        /// </summary>
        desc = 0,
        /// <summary>
        /// 正数第几个
        /// </summary>
        asc=1,
    }
}

下面的是具体的方法


using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Tools.TimeZone
{
    public static class DateZoneHelper
    {
        private static List<TimeZoneModel> _zoneList;
        private static readonly string PATH = "TimeZone.json";

        public static List<TimeZoneModel> ZoneList
        {
            get
            {
                if (_zoneList == null)
                {
                    //从数据源中获取数据
                    //string Path = "TimeZone.json";
                    if (!File.Exists(PATH))
                    {
                        _zoneList = new List<TimeZoneModel>();
                    }
                    else
                    {
                        string str = File.ReadAllText(PATH);
                        //JArray array = JArray.Parse(str);
                        _zoneList=JsonConvert.DeserializeObject<List<TimeZoneModel>>(str);
                    }
                }

                return _zoneList;
            }
        }

        public static TimeZoneModel GetZone(string ZoneName)
        {
            return ZoneList.SingleOrDefault(a => a.ZoneName == ZoneName);
        }

        public static DateTimeOffset ConvertDate(this DateTimeOffset dateTime, string ZoneName)
        {

            TimeZoneModel zone = GetZone(ZoneName);//获取当前时区的参数
            return dateTime.ConvertDate(zone);
        }

        public static DateTimeOffset ConvertDate(this DateTimeOffset dateTime, TimeZoneModel zone)
        {
            if (zone==null)
            {
                return DateTimeOffset.MinValue;
            }

            DateTimeOffset date = DateTimeOffset.MinValue;

            DateTime dtUTC = dateTime.UtcDateTime;
            
            switch (zone.ZoneType)
            {
                case ZoneType.Summer:
                    
                    DateTime dtToDate = dtUTC.AddHours(zone.GMT+1);//假设当前时间是夏令时
                    DateTime BeginDate = GetDateByNodeTime(dtToDate.Year,zone.BeginDate).AddHours(1);//夏令时开始时间
                    DateTime EndDate = GetDateByNodeTime(dtToDate.Year, zone.EndDate);//夏令时结束时间
                    if (BeginDate<= dtToDate&& dtToDate< EndDate)
                    {
                        date= dateTime.ToOffset(new TimeSpan(TimeSpan.TicksPerHour * (zone.GMT+1)));
                    }
                    else
                    {
                        date = dateTime.ToOffset(new TimeSpan(TimeSpan.TicksPerHour * (zone.GMT)));
                        //date = new DateTimeOffset(dtUTC.AddHours(zone.GMT), new TimeSpan(TimeSpan.TicksPerHour * zone.GMT));
                    }


                    break;
                case ZoneType.Same:
                default:
                    DateTime dtTemp = dtUTC.AddHours(zone.GMT);

                    date = dateTime.ToOffset(new TimeSpan(TimeSpan.TicksPerHour * (zone.GMT)));
                    //date = new DateTimeOffset(dtTemp, new TimeSpan(TimeSpan.TicksPerHour * zone.GMT));
                    break;
            }

            return date;
        }

        /// <summary>
        /// 获取当前年份的节点
        /// </summary>
        /// <param name="Year">年份</param>
        /// <param name="node">节点</param>
        /// <returns></returns>
        private static DateTime GetDateByNodeTime(int Year, TimeNode node)
        {
            DateTime dt = new DateTime(Year, node.Month, 1, node.Hours, 0, 0);//获取当前月的第一天
            int times = 0;
            switch (node.Sort)
            {
                case Sort.desc:
                    dt = dt.AddMonths(1).AddDays(-1);//获取当前月的最后一天
                    times = 0;
                    while (true)//第几个时间
                    {
                        if (dt.DayOfWeek == node.DayOfWeek)
                        {
                            times++;
                            if (times >= node.Num)
                            {
                                break;
                            }
                            if (times > 31)
                            {
                                Console.WriteLine($"超过天数范围:dt={dt.ToString("yyyy-MM-dd")};times={times}");
                                break;
                            }
                        }
                        dt = dt.AddDays(-1);
                    }
                    break;
                case Sort.asc:
                    
                    times = 0;
                    while (true)//第几个时间
                    {
                        if (dt.DayOfWeek == node.DayOfWeek)
                        {
                            times++;
                            if (times >= node.Num)
                            {
                                break;
                            }

                            if (times > 31)
                            {
                                Console.WriteLine($"超过天数范围:dt={dt.ToString("yyyy-MM-dd")};times={times}");
                                break;
                            }
                        }
                        dt = dt.AddDays(1);
                    }
                    break;
                default:
                    break;
            }

            return dt;
        }


        public static void Add(TimeZoneModel model)
        {
            ZoneList.Add(model);
        }
        public static void Save()
        {
            JArray array = JArray.FromObject(ZoneList);
            File.WriteAllText(PATH,array.ToString());
        }
    }
}


具体用法如下面的代码所示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tools.TimeZone;

namespace 时区转换工具
{
    public class Program
    {
        static void Main(string[] args)
        {

            IsZoneEnd();
            Console.ReadLine();
        }


        /// <summary>
        /// 检查是否是夏令时结束
        /// </summary>
        private static void IsZoneEnd()
        {
            for (int i = 0; i < 200; i++)
            {
                DateTimeOffset date = new DateTimeOffset(2019, 11, 3, 8 + i / 60, i % 60, 0, new TimeSpan(0));
                DateTimeOffset offset = date.ConvertDate("US.PST");

                Console.WriteLine($"i={i}当前时间是{offset.ToString("yyyy-MM-dd HH:mm:ss")}===时区是{offset.Offset}");

            }
        }
        /// <summary>
        /// 检查是否是夏令时开始
        /// </summary>
        private static void IsZoneBegin()
        {
            for (int i = 0; i < 100; i++)
            {
                DateTimeOffset date = new DateTimeOffset(2019, 3, 10, 9 + i / 60, i % 60, 0, new TimeSpan(0));
                DateTimeOffset offset = date.ConvertDate("US.PST");

                Console.WriteLine($"i={i}当前时间是{offset.ToString("yyyy-MM-dd HH:mm:ss")}===时区是{offset.Offset}");

            }
        }

        private static void USZoneWrite()
        {
            TimeNode AMBegin = new TimeNode
            {
                Month = 3,
                Num = 2,
                DayOfWeek = DayOfWeek.Sunday,
                Hours = 2,
                Sort = Sort.asc,
            };

            TimeNode AMEnd = new TimeNode
            {
                Month = 11,
                Num = 1,
                DayOfWeek = DayOfWeek.Sunday,
                Hours = 2,
                Sort = Sort.asc,
            };
            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.EST",
                ZoneRemark = "美国东部时间 西五区时间 美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",
                GMT = -5,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });

            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.CST",
                ZoneRemark = "美国中部时间(CST)(西六区时间) 美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",
                GMT = -6,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });
            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.MST",
                ZoneRemark = "美国山地时间(MST)(西七区时间) 美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",//东部时间 西五区时间
                GMT = -7,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });
            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.PST",
                ZoneRemark = "太平洋时间(西部时间)(PST)(西八区时间) 美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",//东部时间 西五区时间
                GMT = -8,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });
            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.AKST",
                ZoneRemark = "阿拉斯加时间(AKST)(西九区时间)美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",//东部时间 西五区时间
                GMT = -9,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });

            DateZoneHelper.ZoneList.Add(new TimeZoneModel()
            {
                ZoneName = "US.HST",
                ZoneRemark = "夏威夷时间(HST)(西十区时间)美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时",//东部时间 西五区时间
                GMT = -10,
                ZoneType = ZoneType.Summer,
                BeginDate = AMBegin,
                EndDate = AMEnd,
            });


            DateZoneHelper.Save();
        }


    }





}

以上是关于实现时区的转换--涉及到冬令时和夏令时的时候的主要内容,如果未能解决你的问题,请参考以下文章

各种时间格式(UTC、GMT等)及夏令时和冬令时

Java编程系列Java判断世界各时区的夏令时冬令时

中国与美国的时差怎么算?

将 Postgres 中没有时区的 DateTime 字段从中欧时间转换为 UTC

美国和中国的时差是多少?

在使用利用夏令时的 Python 时区时,应该传递啥 tzinfo?