//==============================================================
//  版权所有：深圳杰文科技
//  文件名：DateTimeUtil.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Infrastructure.Utilities
{
	/// <summary>
	/// 时间类型计算类
	/// </summary>
	public static class DateTimeUtil
	{
		//public const string yyyyMMdd = "yyyy-MM-dd";
		public const string yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
		//public const string yyyyMMddHHmmssfff = "yyyy-MM-dd HH:mm:ss.fff";

		public static string yyyyMMdd(this DateTime date)
		{
			return date.ToString("yyyy-MM-dd");
		}

		public static string yyyyMMddHHmm(this DateTime datetime)
		{
			return datetime.ToString("yyyy-MM-dd HH:mm");
		}

		/// <summary>
		/// 判断起始和截止日期，是否是一个有效的日期范围。
		/// </summary>
		/// <param name="startDate"></param>
		/// <param name="endDate"></param>
		/// <returns></returns>
		public static bool IsValidDateRange(DateTime startDate, DateTime endDate)
		{
			return startDate > DefaultMinDate && endDate < DefaultMaxDate;
		}

		/// <summary>
		/// 系统所能支持的最大日期。综合考虑了SqlServer和DateTimePicker控件的取值范围。
		/// </summary>
		public static DateTime DefaultMaxDate
		{
			get
			{
				return new DateTime(9998, 12, 30); //本来最大日期是31号，但考虑到实际查询时可能会+1，因此改为30日。
			}
		}

		/// <summary>
		/// 系统所能支持的最小日期。综合考虑了SqlServer和DateTimePicker控件的取值范围。
		/// </summary>
		public static DateTime DefaultMinDate
		{
			get
			{
				return new DateTime(1900, 1, 1);
			}
		}

		/// <summary>
		/// 获得本月的第一天。
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		public static DateTime GetFirstDate(DateTime date)
		{
			return new DateTime(date.Year, date.Month, 1);
		}

		/// <summary>
		/// 获得本月的最后一天。
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		public static DateTime GetLastDate(DateTime date)
		{
			return new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);
		}

		/// <summary>
		/// 根据两个时间获取其年份差
		/// 返回值为正整数
		/// </summary>
		public static int GetDiffYear(DateTime dateTime1, DateTime dateTime2)
		{
			DateTime d0 = dateTime1 <= dateTime2 ? dateTime1 : dateTime2;
			DateTime d1 = dateTime1 > dateTime2 ? dateTime1 : dateTime2;

			d0 = d0.Date;
			d1 = d1.Date;

			int i = 0;
			while (d0 < d1)
			{
				d0 = d0.AddYears(1);
				i++;
			}

			return i;
		}

		/// <summary>
		/// 根据两个时间获取其日期差
		/// 返回值为正整数
		/// </summary>
		public static int GetDiffDay(DateTime dateTime1, DateTime dateTime2)
		{
			DateTime d0 = dateTime1 <= dateTime2 ? dateTime1 : dateTime2;
			DateTime d1 = dateTime1 > dateTime2 ? dateTime1 : dateTime2;

			d0 = d0.Date;
			d1 = d1.Date;

			int i = 0;
			while (d0 < d1)
			{
				d0 = d0.AddDays(1);
				i++;
			}

			return i;
		}

		/// <summary>
		/// 将日期转换为int型，精确到天
		/// </summary>
		public static int Time2Day(DateTime time)
		{
			return time.Year * 1000 + time.Month * 100 + time.Day;
		}

		/// <summary>
		/// 将日期转换为int型，精确到月份
		/// </summary>
		public static int Time2Month(DateTime time)
		{
			return time.Year * 100 + time.Month;
		}

		/// <summary>
		/// 尝试将一个字符串解析为日期类型
		/// </summary>
		public static bool TryParse(string input, out DateTime time)
		{
			time = default(DateTime);
			if (string.IsNullOrEmpty(input))
				return false;

			input = input.Trim();

			//含年份的日期
			string[] patterns = {
				"(?<y>20[0-9]{2,2})(?<m>[0-9]{1,2})(?<d>[0-9]{1,2})",
				"(?<y>20[0-9]{2,2})-(?<m>[0-9]{1,2})-(?<d>[0-9]{1,2})",
				"(?<y>20[0-9]{2,2})年(?<m>[0-9]{1,2})月(?<d>[0-9]{1,2})(日|号)?",
			};

			foreach (string p in patterns)
			{
				MatchCollection mc = Regex.Matches(input, p);
				if (mc.Count > 0)
				{
					Match match = mc[0];
					string y = match.Groups["y"].Value;
					string m = match.Groups["m"].Value;
					string d = match.Groups["d"].Value;

					if (DateTime.TryParse(string.Format("{0}-{1}-{2}", y, m, d), out time))
						return true;
				}
			}

			//不含年份的日期，默认取当年
			patterns = new string[]{
				"(?<m>[0-9]{2,2})(?<d>[0-9]{2,2})",
				"(?<m>[0-9]{1,2})-(?<d>[0-9]{1,2})",
				"(?<m>[0-9]{1,2})月(?<d>[0-9]{1,2})(日|号)?",
			};

			foreach (string p in patterns)
			{
				MatchCollection mc = Regex.Matches(input, p);
				if (mc.Count > 0)
				{
					Match match = mc[0];
					string m = match.Groups["m"].Value;
					string d = match.Groups["d"].Value;

					if (DateTime.TryParse(string.Format("{0}-{1}-{2}", DateTime.Now.Year, m, d), out time))
						return true;
				}
			}

			return false;
		}

		/// <summary>
		/// 尝试将一个整型解析为日期类型
		/// </summary>
		public static bool TryParse(int date, out DateTime time)
		{
			time = default(DateTime);
			string input = date.ToString();
			if (input.Length == 8)
			{
				try
				{
					int year = date / 10000;
					int month = date / 100 - year * 100;
					int day = date - year * 10000 - month * 100;
					time = new DateTime(year, month, day);
					return true;
				}
				catch
				{
					return false;
				}

			}

			return false;
		}

		/// <summary>
		/// 比较两组日期是否重叠
		/// </summary>
		/// <param name="beginDate0">开始日期0</param>
		/// <param name="endDate0">结束日期0</param>
		/// <param name="beginDate1">开始日期1</param>
		/// <param name="endDate1">结束日期1</param>
		/// <returns>是否有重叠</returns>
		public static bool IsDateOverlap(DateTime beginDate0, DateTime endDate0, DateTime beginDate1, DateTime endDate1)
		{
			if ((beginDate0 >= beginDate1 && beginDate0 <= endDate1)
			   || (endDate0 >= beginDate1 && beginDate0 <= endDate1
			   || (beginDate1 >= beginDate0 && beginDate1 <= endDate0)
			   || (endDate1 >= beginDate0 && beginDate1 <= endDate0)))
			{
				return true;
			}
			return false;
		}

		/// <summary>
		/// 判断两段日期是否交叉
		/// </summary>
		/// <param name="d00">第一段的开始日期</param>
		/// <param name="d01">第一段的截止日期</param>
		/// <param name="d10">第二段的开始日期</param>
		/// <param name="d11">第二段的截止日期</param>
		/// <returns>有任意一天重合，返回true，否则返回false</returns>
		public static bool IsCross(DateTime d00, DateTime d01, DateTime d10, DateTime d11)
		{
			DateTime t00 = Min(d00, d01);
			DateTime t01 = Max(d00, d01);

			DateTime t10 = Min(d10, d11);
			DateTime t11 = Max(d10, d11);

			return !((t01 < t10) || (t11 < t00));
		}

		/// <summary>
		/// 返回最小的日期值
		/// </summary>
		/// <param name="dates">需要进行比较的日期列表</param>
		/// <returns>最小的日期值</returns>
		public static DateTime Min(params DateTime[] dates)
		{
			if (dates == null || dates.Length == 0)
			{
				return default(DateTime);
			}

			DateTime t = dates[0];
			for (int i = 1; i < dates.Length; i++)
			{
				if (dates[i] < t)
				{
					t = dates[i];
				}
			}

			return t;
		}

		/// <summary>
		/// 返回最大的日期值
		/// </summary>
		/// <param name="dates">需要进行比较的日期列表</param>
		/// <returns>最大的日期值</returns>
		public static DateTime Max(params DateTime[] dates)
		{
			if (dates == null || dates.Length == 0)
			{
				return default(DateTime);
			}

			DateTime t = dates[0];
			for (int i = 1; i < dates.Length; i++)
			{
				if (dates[i] > t)
				{
					t = dates[i];
				}
			}

			return t;
		}

		/// <summary>
		/// 获得指定月份的最后一天的日期号。
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		public static int GetLastDay(DateTime date)
		{
			DateTime d = new DateTime(date.Year, date.Month, 1);
			d = d.AddMonths(1).AddDays(-1);
			return d.Day;
		}

		/// <summary>
		/// 将Unix时间戳转换为DateTime类型时间。
		/// </summary>
		/// <param name="d">double 型数字</param>
		/// <returns>DateTime</returns>
		public static System.DateTime? ConvertFromUnixDateTime(double d)
		{
			if (d == 0)
			{
				return null;
			}
			System.DateTime time = System.DateTime.MinValue;
			System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
			time = startTime.AddSeconds(d);
			return time;
		}

		public static System.DateTime? ConvertFromUnixDateTime(double? d)
		{
			return null;
		}

		public static System.DateTime? ConvertFromUnixDateTime(long? d)
		{
			return null;
		}

		public static System.DateTime? ConvertFromUnixDateTime(long d)
		{
			return ConvertFromUnixDateTime((double)d);
		}

		/// <summary>
		/// 将c# DateTime时间格式转换为Unix时间戳格式。
		/// </summary>
		/// <param name="time">时间</param>
		/// <returns>double</returns>
		public static long ConvertToUnixDateTime(System.DateTime time)
		{
			System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
			return (int)(time - startTime).TotalSeconds;
		}

		public static long? ConvertToUnixDateTime(System.DateTime? time)
		{
			return null;
		}

		public static long ToUnixDateTime(this System.DateTime time)
		{
			return ConvertToUnixDateTime(time);
		}

		public static DateTime SetTime(this DateTime d, string s)
		{
			string[] str = s.Split(':');
			int hours = int.Parse(str[0]);
			int minutes = int.Parse(str[1]);
			int seconds = 0;
			if (str.Length == 3)
			{
				seconds = int.Parse(str[2]);
			}
			return d.Date.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds);
		}

		public static string DayOfWeekName(this DateTime d)
		{
			return new string[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", }[Convert.ToInt16(d.DayOfWeek.ToString("D"))];
		}

		public static DateTime MergeTime(this DateTime date, DateTime time)
		{
			return date.Date.AddHours(time.Hour).AddMinutes(time.Minute);
		}

		//根据生日计算年龄
		public static int GetAgeByBirthdate(DateTime birthdate)
		{
			DateTime now = DateTime.Now;
			int age = now.Year - birthdate.Year;
			if (now.Month < birthdate.Month || (now.Month == birthdate.Month && now.Day < birthdate.Day))
			{
				age--;
			}
			return age < 0 ? 0 : age;
		}

	}
}
