#unity/日常积累
不同的时区,会有不同的时间偏移
/// <summary>
/// UTC:世界时,格林尼治标准时
/// 时间戳定义:此刻的格林威治时间距离UTC_START_DATE的秒数
/// 注意:一般来说,用来显示给玩家看的DateTime,使用本地时区;用来判断跨天、跨周的DateTime,必须使用服务器时区
/// </summary>
#region 常量定义
public const int DEFAULT_TIMEZONE_OFFSET = 28800;//8 * 3600 东八区
public const int DAY_SECOND = 86400;
public const int WEEK_SECOND = 86400 * 7; //一周时间秒数
public const int HOUR_SECOND = 3600;
public const int MINUTE_SECOND = 60;
static readonly DateTime UTC_START_DATE = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
#endregion
/// <summary>
/// 把UTC时间戳转换成指定时区的DateTime
/// </summary>
/// <param name="timeStamp">UTC时间戳</param>
/// <param name="timeZoneOffset">指定时区离UTC时间的偏差值(秒)</param>
/// <returns></returns>
private static DateTime GetDateWithTimeZone(int timeStamp, int timeZoneOffset)
{
return UTC_START_DATE.AddSeconds(timeStamp + timeZoneOffset);
}
/// <summary>
/// 把UTC时间戳转换成当前时区的DateTime
/// MainLand地区默认为东八区
/// 其他地区读取本机的时区设置
/// </summary>
/// <param name="timeStamp">UTC时间戳</param>
/// <returns></returns>
public static DateTime GetDateWithLocalTimeZone(int timeStamp)
{
return GetDateWithTimeZone(timeStamp, LocalTimeZoneOffset);
}
private static int FixTotalSeconds(this TimeSpan span)
{
return span.Days * DAY_SECOND + span.Hours * HOUR_SECOND + span.Minutes * MINUTE_SECOND + span.Seconds;
}
/// <summary>
/// 把UTC时间戳转换成指定时区的DateTime
/// </summary>
/// <param name="timeStamp">UTC时间戳</param>
/// <param name="timeZoneOffset">指定时区离UTC时间的偏差值(秒)</param>
/// <returns></returns>
private static DateTime GetDateWithTimeZone(int timeStamp, int timeZoneOffset)
{
return UTC_START_DATE.AddSeconds(timeStamp + timeZoneOffset);
}
/// <summary>
/// 返回星期一
/// </summary>
/// <param name="timeStamp"></param>
/// <returns></returns>
public static int GetThisMonday(int timeStamp)
{
DateTime date = GetDateWithLocalTimeZone(timeStamp);
int days = 0;
switch (date.DayOfWeek)
{
case DayOfWeek.Monday:
days = 0;
break;
case DayOfWeek.Tuesday:
days = 1;
break;
case DayOfWeek.Wednesday:
days = 2;
break;
case DayOfWeek.Thursday:
days = 3;
break;
case DayOfWeek.Friday:
days = 4;
break;
case DayOfWeek.Saturday:
days = 5;
break;
case DayOfWeek.Sunday:
days = 6;
break;
}
return timeStamp - FixTotalSeconds(date.TimeOfDay) - days*DAY_SECOND;
}
/// <summary>
/// 计算跨自然天的小时数
/// </summary>
/// <param name="oldTimeStamp">之前时间戳</param>
/// <param name="newTimeStamp">现在时间戳</param>
/// <param name="timeZoneOffset">时区</param>
/// <returns></returns>
private static int ComputeCrossHours(int oldTimeStamp, int newTimeStamp, int timeZoneOffset)
{
if (oldTimeStamp >= newTimeStamp)
{
return 0;
}
DateTime oldDate = GetDateWithTimeZone(oldTimeStamp, timeZoneOffset);
DateTime newDate = GetDateWithTimeZone(newTimeStamp, timeZoneOffset);
TimeSpan offsetSpan = newDate.Subtract(oldDate);
int crossHours = Mathf.FloorToInt((float) offsetSpan.TotalHours);
if (crossHours >= 24)
{
crossHours = crossHours % 24;
}
return crossHours;
}
/// <summary>
/// 计算跨自然天的天数,小于1天都返回0
/// </summary>
/// <param name="oldTimeStamp">之前时间戳</param>
/// <param name="newTimeStamp">现在时间戳</param>
/// <param name="timeZoneOffset">时区</param>
/// <returns></returns>
private static int ComputeCrossDays(int oldTimeStamp, int newTimeStamp, int timeZoneOffset)
{
if (oldTimeStamp >= newTimeStamp)
{
return 0;
}
DateTime oldDate = GetDateWithTimeZone(oldTimeStamp, timeZoneOffset);
DateTime newDate = GetDateWithTimeZone(newTimeStamp, timeZoneOffset);
TimeSpan offsetSpan = newDate.Subtract(oldDate);
//满24小时的跨天天数
int crossDays = Mathf.FloorToInt((float) offsetSpan.TotalDays);
//减掉满24小时的天后剩下的newDate
DateTime newDateLeft = newDate.AddDays(-crossDays);
if (newDateLeft.Day != oldDate.Day)
{
//如果不是同一天,说明虽然不满24小时,也跨天了
crossDays += 1;
}
return crossDays;
}
/// <summary>
/// 基于服务器时区,计算跨自然天天数
/// </summary>
/// <param name="oldTimeStamp"></param>
/// <param name="newTimeStamp"></param>
/// <returns></returns>
public static int ComputeCrossServerDays(int oldTimeStamp, int newTimeStamp)
{
return ComputeCrossDays(oldTimeStamp, newTimeStamp, ServerTimeZoneOffset);
}
/// <summary>
/// 基于服务器时区,计算跨自然周数
/// </summary>
/// <param name="oldTimeStamp">之前时间</param>
/// <param name="newTimeStamp">现在时间</param>
/// <returns></returns>
public static int ComputeCrossServerWeeks(int oldTimeStamp, int newTimeStamp)
{
if (oldTimeStamp > newTimeStamp)
{
#if UNITY_EDITOR
if (GLog.IsLogInfoEnabled)
{
GLog.LogError("oldTimeStamp bigger than newTimeStamp");
}
#endif
}
int crossDays = ComputeCrossServerDays(oldTimeStamp,newTimeStamp);
//如果跨天小于 7天,且所在的周一不同
if (crossDays > 0 && crossDays < 7)
{
int oldMonday = GetThisMonday(oldTimeStamp);
int newMonday = GetThisMonday(newTimeStamp);
if (newMonday > oldMonday)
{
return 1;
}
else if (newMonday == oldMonday)
{
return 0;
}
}
return crossDays / 7;
}