using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
namespace Masuit.Tools.DateTimeExt
{
///
/// 日期操作工具类
///
public static class DateTimeHelper
{
///
/// 获取某一年有多少周
///
///
/// 年份
/// 该年周数
public static int GetWeekAmount(this DateTime _, int year)
{
var end = new DateTime(year, 12, 31); //该年最后一天
var gc = new GregorianCalendar();
return gc.GetWeekOfYear(end, CalendarWeekRule.FirstDay, DayOfWeek.Monday); //该年星期数
}
///
/// 返回年度第几个星期 默认星期日是第一天
///
/// 时间
/// 第几周
public static int WeekOfYear(this in DateTime date)
{
var gc = new GregorianCalendar();
return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
}
///
/// 返回年度第几个星期
///
/// 时间
/// 一周的开始日期
/// 第几周
public static int WeekOfYear(this in DateTime date, DayOfWeek week)
{
var gc = new GregorianCalendar();
return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, week);
}
///
/// 得到一年中的某周的起始日和截止日
/// 年 nYear
/// 周数 nNumWeek
/// 周始 out dtWeekStart
/// 周终 out dtWeekeEnd
///
///
/// 年份
/// 第几周
/// 开始日期
/// 结束日期
public static void GetWeekTime(this DateTime _, int nYear, int nNumWeek, out DateTime dtWeekStart, out DateTime dtWeekeEnd)
{
var dt = new DateTime(nYear, 1, 1);
dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1);
}
///
/// 得到一年中的某周的起始日和截止日 周一到周五 工作日
///
///
/// 年份
/// 第几周
/// 开始日期
/// 结束日期
public static void GetWeekWorkTime(this DateTime _, int nYear, int nNumWeek, out DateTime dtWeekStart, out DateTime dtWeekeEnd)
{
var dt = new DateTime(nYear, 1, 1);
dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1).AddDays(-2);
}
#region P/Invoke 设置本地时间
[DllImport("kernel32.dll")]
private static extern bool SetLocalTime(ref SystemTime time);
[StructLayout(LayoutKind.Sequential)]
private struct SystemTime
{
public short year;
public short month;
public short dayOfWeek;
public short day;
public short hour;
public short minute;
public short second;
public short milliseconds;
}
///
/// 设置本地计算机系统时间,仅支持Windows系统
///
/// DateTime对象
public static void SetLocalTime(this in DateTime dt)
{
SystemTime st;
st.year = (short)dt.Year;
st.month = (short)dt.Month;
st.dayOfWeek = (short)dt.DayOfWeek;
st.day = (short)dt.Day;
st.hour = (short)dt.Hour;
st.minute = (short)dt.Minute;
st.second = (short)dt.Second;
st.milliseconds = (short)dt.Millisecond;
SetLocalTime(ref st);
}
#endregion P/Invoke 设置本地时间
///
/// 返回相对于当前时间的相对天数
///
///
/// 相对天数
public static string GetDateTime(this in DateTime dt, int relativeday)
{
return dt.AddDays(relativeday).ToString("yyyy-MM-dd HH:mm:ss");
}
///
/// 返回标准时间格式string
///
public static string GetDateTimeF(this in DateTime dt) => dt.ToString("yyyy-MM-dd HH:mm:ss:fffffff");
///
/// 获取该时间相对于1970-01-01T00:00:00Z的秒数
///
///
///
public static long GetTotalSeconds(this in DateTime dt) => new DateTimeOffset(dt).UtcDateTime.Ticks / 10_000_000L - 62135596800L;
///
/// 获取该时间相对于1970-01-01T00:00:00Z的毫秒数
///
///
///
public static long GetTotalMilliseconds(this in DateTime dt) => new DateTimeOffset(dt).UtcDateTime.Ticks / 10000L - 62135596800000L;
///
/// 获取该时间相对于1970-01-01T00:00:00Z的微秒时间戳
///
///
///
public static long GetTotalMicroseconds(this in DateTime dt) => (new DateTimeOffset(dt).UtcTicks - 621355968000000000) / 10;
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
///
/// 获取该时间相对于1970-01-01T00:00:00Z的纳秒时间戳
///
///
///
public static long GetTotalNanoseconds(this in DateTime dt)
{
var ticks = (new DateTimeOffset(dt).UtcTicks - 621355968000000000) * 100;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
QueryPerformanceCounter(out var timestamp);
return ticks + timestamp % 100;
}
return ticks + Stopwatch.GetTimestamp() % 100;
}
///
/// 获取该时间相对于1970-01-01T00:00:00Z的分钟数
///
///
///
public static double GetTotalMinutes(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalMinutes;
///
/// 获取该时间相对于1970-01-01T00:00:00Z的小时数
///
///
///
public static double GetTotalHours(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalHours;
///
/// 获取该时间相对于1970-01-01T00:00:00Z的天数
///
///
///
public static double GetTotalDays(this in DateTime dt) => new DateTimeOffset(dt).Offset.TotalDays;
///
/// 返回本年有多少天
///
///
/// 年份
/// 本年的天数
public static int GetDaysOfYear(this DateTime _, int iYear)
{
return IsRuYear(iYear) ? 366 : 365;
}
/// 本年有多少天
/// 日期
/// 本天在当年的天数
public static int GetDaysOfYear(this in DateTime dt)
{
//取得传入参数的年份部分,用来判断是否是闰年
int n = dt.Year;
return IsRuYear(n) ? 366 : 365;
}
/// 本月有多少天
///
/// 年
/// 月
/// 天数
public static int GetDaysOfMonth(this DateTime _, int iYear, int month)
{
return month switch
{
1 => 31,
2 => (IsRuYear(iYear) ? 29 : 28),
3 => 31,
4 => 30,
5 => 31,
6 => 30,
7 => 31,
8 => 31,
9 => 30,
10 => 31,
11 => 30,
12 => 31,
_ => 0
};
}
/// 本月有多少天
/// 日期
/// 天数
public static int GetDaysOfMonth(this in DateTime dt)
{
//--利用年月信息,得到当前月的天数信息。
return dt.Month switch
{
1 => 31,
2 => (IsRuYear(dt.Year) ? 29 : 28),
3 => 31,
4 => 30,
5 => 31,
6 => 30,
7 => 31,
8 => 31,
9 => 30,
10 => 31,
11 => 30,
12 => 31,
_ => 0
};
}
/// 返回当前日期的星期名称
/// 日期
/// 星期名称
public static string GetWeekNameOfDay(this in DateTime idt)
{
return idt.DayOfWeek switch
{
DayOfWeek.Monday => "星期一",
DayOfWeek.Tuesday => "星期二",
DayOfWeek.Wednesday => "星期三",
DayOfWeek.Thursday => "星期四",
DayOfWeek.Friday => "星期五",
DayOfWeek.Saturday => "星期六",
DayOfWeek.Sunday => "星期日",
_ => ""
};
}
/// 判断当前年份是否是闰年,私有函数
/// 年份
/// 是闰年:True ,不是闰年:False
private static bool IsRuYear(int iYear)
{
//形式参数为年份
//例如:2003
var n = iYear;
return n % 400 == 0 || n % 4 == 0 && n % 100 != 0;
}
///
/// 判断是否为合法日期,必须大于1800年1月1日
///
/// 输入日期字符串
/// True/False
public static bool IsDateTime(this string strDate)
{
DateTime.TryParse(strDate, out var result);
return result.CompareTo(DateTime.Parse("1800-1-1")) > 0;
}
///
/// 判断时间是否在区间内
///
///
/// 开始
/// 结束
/// 模式
///
public static bool In(this in DateTime @this, DateTime start, DateTime end, RangeMode mode = RangeMode.Close)
{
return mode switch
{
RangeMode.Open => start < @this && end > @this,
RangeMode.Close => start <= @this && end >= @this,
RangeMode.OpenClose => start < @this && end >= @this,
RangeMode.CloseOpen => start <= @this && end > @this,
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null)
};
}
///
/// 返回每月的第一天和最后一天
///
///
/// 月份
/// 第一天
/// 最后一天
public static void ReturnDateFormat(this DateTime _, int month, out string firstDay, out string lastDay)
{
int year = DateTime.Now.Year + month / 12;
if (month != 12)
{
month %= 12;
}
switch (month)
{
case 1:
firstDay = DateTime.Now.ToString($"{year}-0{month}-01");
lastDay = DateTime.Now.ToString($"{year}-0{month}-31");
break;
case 2:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.IsLeapYear(DateTime.Now.Year) ? DateTime.Now.ToString(year + "-0" + month + "-29") : DateTime.Now.ToString(year + "-0" + month + "-28");
break;
case 3:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString("yyyy-0" + month + "-31");
break;
case 4:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 5:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 6:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 7:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 8:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 9:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 10:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
break;
case 11:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-30");
break;
default:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
break;
}
}
///
/// 返回某年某月最后一天
///
///
/// 年份
/// 月份
/// 日
public static int GetMonthLastDate(this DateTime _, int year, int month)
{
DateTime lastDay = new DateTime(year, month, new GregorianCalendar().GetDaysInMonth(year, month));
int day = lastDay.Day;
return day;
}
///
/// 获得一段时间内有多少小时
///
/// 起始时间
/// 终止时间
/// 小时差
public static string GetTimeDelay(this in DateTime dtStar, DateTime dtEnd)
{
long lTicks = (dtEnd.Ticks - dtStar.Ticks) / 10000000;
string sTemp = (lTicks / 3600).ToString().PadLeft(2, '0') + ":";
sTemp += (lTicks % 3600 / 60).ToString().PadLeft(2, '0') + ":";
sTemp += (lTicks % 3600 % 60).ToString().PadLeft(2, '0');
return sTemp;
}
///
/// 获得8位时间整型数字
///
/// 当前的日期时间对象
/// 8位时间整型数字
public static string GetDateString(this in DateTime dt)
{
return dt.Year + dt.Month.ToString().PadLeft(2, '0') + dt.Day.ToString().PadLeft(2, '0');
}
///
/// 返回时间差
///
/// 时间1
/// 时间2
/// 时间差
public static string DateDiff(this in DateTime dateTime1, in DateTime dateTime2)
{
string dateDiff;
var ts = dateTime2 - dateTime1;
if (ts.Days >= 1)
{
dateDiff = dateTime1.Month + "月" + dateTime1.Day + "日";
}
else
{
dateDiff = ts.Hours > 1 ? ts.Hours + "小时前" : ts.Minutes + "分钟前";
}
return dateDiff;
}
///
/// 计算2个时间差
///
/// 开始时间
/// 结束时间
/// 时间差
public static string GetDiffTime(this in DateTime beginTime, in DateTime endTime)
{
string strResout = string.Empty;
//获得2时间的时间间隔秒计算
TimeSpan span = endTime.Subtract(beginTime);
int sec = Convert.ToInt32(span.TotalSeconds);
int minutes = 1 * 60;
int hours = minutes * 60;
int day = hours * 24;
int month = day * 30;
int year = month * 12;
//提醒时间,到了返回1,否则返回0
if (sec > year)
{
strResout += sec / year + "年";
sec %= year; //剩余
}
if (sec > month)
{
strResout += sec / month + "月";
sec %= month;
}
if (sec > day)
{
strResout += sec / day + "天";
sec %= day;
}
if (sec > hours)
{
strResout += sec / hours + "小时";
sec %= hours;
}
if (sec > minutes)
{
strResout += sec / minutes + "分";
sec %= minutes;
}
strResout += sec + "秒";
return strResout;
}
///
/// 根据某个时间段查找在某批时间段中的最大并集
///
///
///
///
///
public static ICollection GetUnionSet(this T destination, List sources) where T : ITimePeriod, new()
{
var result = true;
ICollection frames = new List();
var timeFrames = sources.Where(frame =>
!(destination.Start > frame.End || destination.End < frame.Start)).ToList();
if (timeFrames.Any())
foreach (var frame in timeFrames)
{
frames.Add(frame);
sources.Remove(frame);
}
if (!frames.Any()) return frames;
var timePeriod = new T()
{
End = frames.OrderBy(frame => frame.End).Max(frame => frame.End),
Start = frames.OrderBy(frame => frame.Start).Min(frame => frame.Start)
};
while (result)
{
var maxTimeFrame = GetUnionSet(timePeriod, sources);
if (!maxTimeFrame.Any())
result = false;
else
foreach (var frame in maxTimeFrame)
frames.Add(frame);
}
return frames;
}
///
/// 获取一批时间段内存在相互重叠的最大时间段
///
/// 基础时间段
/// 一批时间段
///
///
/// 源数据sources 会受到影响
public static T GetMaxTimePeriod(this T destination, List sources) where T : ITimePeriod, new()
{
var list = sources.Select(period => new T()
{
End = period.End,
Start = period.Start,
}).ToList();
var timePeriods = GetUnionSet(destination, list);
return new T()
{
End = timePeriods.OrderBy(period => period.End).Max(period => period.End),
Start = timePeriods.OrderBy(period => period.Start).Min(period => period.Start)
};
}
}
public interface ITimePeriod
{
///
/// 起始时间
///
public DateTime Start { get; set; }
///
/// 终止时间
///
public DateTime End { get; set; }
}
///
/// 区间模式
///
public enum RangeMode
{
///
/// 开区间
///
Open,
///
/// 闭区间
///
Close,
///
/// 左开右闭区间
///
OpenClose,
///
/// 左闭右开区间
///
CloseOpen
}
}