using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
namespace XCharts.Runtime
{
public static class DateTimeUtil
{
#if UNITY_2018_3_OR_NEWER
private static readonly DateTime k_LocalDateTime1970 = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
#else
private static readonly DateTime k_LocalDateTime1970 = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
#endif
private static readonly DateTime k_DateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static readonly int ONE_SECOND = 1;
public static readonly int ONE_MINUTE = ONE_SECOND * 60;
public static readonly int ONE_HOUR = ONE_MINUTE * 60;
public static readonly int ONE_DAY = ONE_HOUR * 24;
public static readonly int ONE_MONTH = ONE_DAY * 30;
public static readonly int ONE_YEAR = ONE_DAY * 365;
public static readonly int MIN_TIME_SPLIT_NUMBER = 4;
private static string s_YearDateFormatter = "yyyy";
//private static string s_MonthDateFormatter = "MM";
//private static string s_DayDateFormatter = "dd";
//private static string s_HourDateFormatter = "HH:mm";
//private static string s_MinuteDateFormatter = "mm:ss";
private static string s_SecondDateFormatter = "HH:mm:ss";
//private static string s_FullDateFormatter = "yyyy-MM-dd HH:mm:ss";
private static Regex s_DateOrTimeRegex = new Regex(@"^(date|time)\s*[:\s]+(.*)", RegexOptions.IgnoreCase);
public static bool IsDateOrTimeRegex(string regex)
{
return regex.StartsWith("date") || regex.StartsWith("time");
}
public static bool IsDateOrTimeRegex(string regex, ref bool date, ref string formatter)
{
if(IsDateOrTimeRegex(regex))
{
if(regex == "date" || regex == "time")
{
date = regex == "date";
formatter = "";
return true;
}
var mc = s_DateOrTimeRegex.Matches(regex);
date = mc[0].Groups[1].Value == "date";
formatter = mc[0].Groups[2].Value;
return true;
}
return false;
}
public static int GetTimestamp()
{
return (int)(DateTime.Now - k_LocalDateTime1970).TotalSeconds;
}
public static int GetTimestamp(DateTime time, bool local = false)
{
if (local)
{
return (int)(time - k_LocalDateTime1970).TotalSeconds;
}
else
{
return (int)(time - k_DateTime1970).TotalSeconds;
}
}
public static int GetTimestamp(string dateTime, bool local = false)
{
try
{
return GetTimestamp(DateTime.Parse(dateTime), local);
}
catch (Exception e)
{
throw e;
}
}
public static DateTime GetDateTime(double timestamp, bool local = true)
{
return local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp);
}
public static string GetDefaultDateTimeString(int timestamp, double range = 0)
{
var dateString = String.Empty;
var dateTime = GetDateTime(timestamp);
if (range <= 0 || range >= DateTimeUtil.ONE_DAY)
{
dateString = dateTime.ToString("yyyy-MM-dd");
}
else
{
dateString = dateTime.ToString(s_SecondDateFormatter);
}
return dateString;
}
internal static string GetDateTimeFormatString(DateTime dateTime, double range)
{
var dateString = String.Empty;
if (range >= DateTimeUtil.ONE_YEAR * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
{
dateString = dateTime.ToString(s_YearDateFormatter);
}
else if (range >= DateTimeUtil.ONE_MONTH * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
{
dateString = dateTime.Month == 1 ?
dateTime.ToString(s_YearDateFormatter) :
XCSettings.lang.GetMonthAbbr(dateTime.Month);
}
else if (range >= DateTimeUtil.ONE_DAY * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
{
dateString = dateTime.Day == 1 ?
XCSettings.lang.GetMonthAbbr(dateTime.Month) :
XCSettings.lang.GetDay(dateTime.Day);
}
else if (range >= DateTimeUtil.ONE_HOUR * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
{
dateString = dateTime.ToString(s_SecondDateFormatter);
}
else if (range >= DateTimeUtil.ONE_MINUTE * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
{
dateString = dateTime.ToString(s_SecondDateFormatter);
}
else
{
dateString = dateTime.ToString(s_SecondDateFormatter);
}
return dateString;
}
///
/// 根据给定的最大最小时间戳范围,计算合适的Tick值
///
///
///
///
///
internal static float UpdateTimeAxisDateTimeList(List list, int minTimestamp, int maxTimestamp, int splitNumber)
{
var firstValue = list.Count > 0 ? list[0] : 0;
var secondValue = list.Count > 1 ? list[1] : 0;
list.Clear();
var range = maxTimestamp - minTimestamp;
if (range <= 0) return 0;
var dtMin = DateTimeUtil.GetDateTime(minTimestamp);
var dtMax = DateTimeUtil.GetDateTime(maxTimestamp);
int tick = 0;
if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
{
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : Math.Max(range / (splitNumber * ONE_YEAR), 1);
var dtStart = (firstValue == 0 || secondValue == 0 || (minTimestamp > firstValue && minTimestamp > secondValue))
? (new DateTime(dtMin.Year, dtMin.Month, 1).AddMonths(1))
: (minTimestamp > firstValue ? DateTimeUtil.GetDateTime(secondValue) : DateTimeUtil.GetDateTime(firstValue));
tick = num * 365 * 24 * 3600;
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
while (dtStart.Ticks < dtMax.Ticks)
{
list.Add(DateTimeUtil.GetTimestamp(dtStart));
dtStart = dtStart.AddYears(num);
}
}
else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
{
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : Math.Max(range / (splitNumber * ONE_MONTH), 1);
var dtStart = (firstValue == 0 || secondValue == 0 || (minTimestamp > firstValue && minTimestamp > secondValue))
? (new DateTime(dtMin.Year, dtMin.Month, 1).AddMonths(1))
: (minTimestamp > firstValue ? DateTimeUtil.GetDateTime(secondValue) : DateTimeUtil.GetDateTime(firstValue));
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
tick = num * 30 * 24 * 3600;
while (dtStart.Ticks < dtMax.Ticks)
{
list.Add(DateTimeUtil.GetTimestamp(dtStart));
dtStart = dtStart.AddMonths(num);
}
}
else if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_DAY);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_HOUR);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_MINUTE);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
else
{
tick = GetTickSecond(range, splitNumber, ONE_SECOND);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
return tick;
}
private static int GetSplitNumber(int range, int tickSecond)
{
var num = 1;
while (range / (num * tickSecond) > 8)
{
num++;
}
return num;
}
private static int GetTickSecond(int range, int splitNumber, int tickSecond)
{
var num = 0;
if (splitNumber > 0)
{
num = Math.Max(range / (splitNumber * tickSecond), 1);
}
else
{
num = 1;
var tick = tickSecond;
while (range / tick > 8)
{
num++;
tick = num * tickSecond;
}
}
return num * tickSecond;
}
private static void AddTickTimestamp(List list, int startTimestamp, int maxTimestamp, int tickSecond)
{
while (startTimestamp <= maxTimestamp)
{
list.Add(startTimestamp);
startTimestamp += tickSecond;
}
}
}
}