2021-11-23 13:20:07 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2024-09-11 08:12:14 +08:00
|
|
|
|
using System.Text.RegularExpressions;
|
2021-11-23 13:20:07 +08:00
|
|
|
|
|
2022-02-19 22:37:57 +08:00
|
|
|
|
namespace XCharts.Runtime
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
public static class DateTimeUtil
|
|
|
|
|
|
{
|
2024-06-16 19:21:25 +08:00
|
|
|
|
#if UNITY_2018_3_OR_NEWER
|
2024-09-11 08:12:14 +08:00
|
|
|
|
private static readonly DateTime k_LocalDateTime1970 = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
|
2024-06-16 19:21:25 +08:00
|
|
|
|
#else
|
2024-09-11 08:12:14 +08:00
|
|
|
|
private static readonly DateTime k_LocalDateTime1970 = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
|
2024-06-16 19:21:25 +08:00
|
|
|
|
#endif
|
2024-09-11 08:12:14 +08:00
|
|
|
|
private static readonly DateTime k_DateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
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";
|
2023-11-16 08:20:26 +08:00
|
|
|
|
//private static string s_HourDateFormatter = "HH:mm";
|
|
|
|
|
|
//private static string s_MinuteDateFormatter = "mm:ss";
|
2021-11-23 13:20:07 +08:00
|
|
|
|
private static string s_SecondDateFormatter = "HH:mm:ss";
|
2023-11-16 08:20:26 +08:00
|
|
|
|
//private static string s_FullDateFormatter = "yyyy-MM-dd HH:mm:ss";
|
2024-09-11 08:12:14 +08:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2025-04-06 22:24:05 +08:00
|
|
|
|
if (IsDateOrTimeRegex(regex))
|
2024-09-11 08:12:14 +08:00
|
|
|
|
{
|
2025-04-06 22:24:05 +08:00
|
|
|
|
if (regex == "date" || regex == "time")
|
2024-09-11 08:12:14 +08:00
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2021-11-23 13:20:07 +08:00
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
public static double GetTimestamp()
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2025-04-07 10:03:19 +08:00
|
|
|
|
return (DateTime.Now - k_LocalDateTime1970).TotalSeconds;
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
public static double GetTimestamp(DateTime time, bool local = false)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2024-09-11 08:12:14 +08:00
|
|
|
|
if (local)
|
|
|
|
|
|
{
|
2025-04-07 10:03:19 +08:00
|
|
|
|
return (time - k_LocalDateTime1970).TotalSeconds;
|
2024-09-11 08:12:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-04-07 10:03:19 +08:00
|
|
|
|
return (time - k_DateTime1970).TotalSeconds;
|
2024-09-11 08:12:14 +08:00
|
|
|
|
}
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
public static double GetTimestamp(string dateTime, bool local = false)
|
2024-04-16 22:30:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2024-09-11 08:12:14 +08:00
|
|
|
|
|
|
|
|
|
|
return GetTimestamp(DateTime.Parse(dateTime), local);
|
2024-04-16 22:30:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-30 22:48:36 +08:00
|
|
|
|
public static DateTime GetDateTime(double timestamp, bool local = false)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
var dateTime = local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp);
|
|
|
|
|
|
return dateTime;
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-30 22:48:36 +08:00
|
|
|
|
public static string GetDefaultDateTimeString(double timestamp, double range = 0, bool local = false)
|
2024-07-16 23:03:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
var dateString = String.Empty;
|
2025-10-30 22:48:36 +08:00
|
|
|
|
var dateTime = GetDateTime(timestamp, local);
|
2024-07-16 23:03:31 +08:00
|
|
|
|
if (range <= 0 || range >= DateTimeUtil.ONE_DAY)
|
|
|
|
|
|
{
|
|
|
|
|
|
dateString = dateTime.ToString("yyyy-MM-dd");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
dateString = dateTime.ToString(s_SecondDateFormatter);
|
|
|
|
|
|
}
|
|
|
|
|
|
return dateString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-23 13:20:07 +08:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2022-05-22 22:17:38 +08:00
|
|
|
|
dateString = dateTime.Month == 1 ?
|
|
|
|
|
|
dateTime.ToString(s_YearDateFormatter) :
|
|
|
|
|
|
XCSettings.lang.GetMonthAbbr(dateTime.Month);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (range >= DateTimeUtil.ONE_DAY * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
2022-05-22 22:17:38 +08:00
|
|
|
|
dateString = dateTime.Day == 1 ?
|
|
|
|
|
|
XCSettings.lang.GetMonthAbbr(dateTime.Month) :
|
|
|
|
|
|
XCSettings.lang.GetDay(dateTime.Day);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (range >= DateTimeUtil.ONE_HOUR * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
2023-11-16 08:20:26 +08:00
|
|
|
|
dateString = dateTime.ToString(s_SecondDateFormatter);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (range >= DateTimeUtil.ONE_MINUTE * DateTimeUtil.MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
2023-11-16 08:20:26 +08:00
|
|
|
|
dateString = dateTime.ToString(s_SecondDateFormatter);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
dateString = dateTime.ToString(s_SecondDateFormatter);
|
|
|
|
|
|
}
|
|
|
|
|
|
return dateString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 根据给定的最大最小时间戳范围,计算合适的Tick值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="list"></param>
|
|
|
|
|
|
/// <param name="minTimestamp"></param>
|
|
|
|
|
|
/// <param name="maxTimestamp"></param>
|
|
|
|
|
|
/// <param name="splitNumber"></param>
|
2025-10-31 08:39:29 +08:00
|
|
|
|
internal static float UpdateTimeAxisDateTimeList(List<double> list, double minTimestamp, double maxTimestamp, int splitNumber, double ceilRate, bool local)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var range = maxTimestamp - minTimestamp;
|
2025-04-06 22:24:05 +08:00
|
|
|
|
if (range <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
list.Clear();
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2025-10-31 08:39:29 +08:00
|
|
|
|
var dtMin = GetDateTime(minTimestamp, local);
|
|
|
|
|
|
var dtMax = GetDateTime(maxTimestamp, local);
|
2025-10-30 22:48:36 +08:00
|
|
|
|
int tick;
|
|
|
|
|
|
if (ceilRate != 0)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
var tickSecond = (int)ceilRate;
|
|
|
|
|
|
tick = GetTickSecond(range, 0, tickSecond);
|
|
|
|
|
|
var let = minTimestamp % tickSecond;
|
|
|
|
|
|
var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
|
|
|
|
|
|
var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
|
|
|
|
|
|
while (startTimestamp > minTimestamp)
|
2025-04-06 22:24:05 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
startTimestamp -= tick;
|
2025-04-06 22:24:05 +08:00
|
|
|
|
}
|
2025-10-30 22:48:36 +08:00
|
|
|
|
if (startTimestamp < minTimestamp)
|
2025-04-06 22:24:05 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
startTimestamp += tick;
|
2025-04-06 22:24:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
list.Clear();
|
2025-10-30 22:48:36 +08:00
|
|
|
|
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
2025-10-30 22:48:36 +08:00
|
|
|
|
else
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : (int)Math.Max(range / (splitNumber * ONE_YEAR), 1);
|
2025-10-31 08:39:29 +08:00
|
|
|
|
var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp), local);
|
2025-10-30 22:48:36 +08:00
|
|
|
|
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
|
|
|
|
|
|
while (dtStart > dtMin)
|
|
|
|
|
|
{
|
|
|
|
|
|
dtStart = dtStart.AddYears(-num);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (dtStart < dtMin)
|
|
|
|
|
|
{
|
|
|
|
|
|
dtStart = dtStart.AddYears(num);
|
|
|
|
|
|
}
|
|
|
|
|
|
tick = num * 365 * 24 * 3600;
|
|
|
|
|
|
list.Clear();
|
|
|
|
|
|
while (dtStart.Ticks < dtMax.Ticks)
|
|
|
|
|
|
{
|
2025-10-31 08:39:29 +08:00
|
|
|
|
list.Add(DateTimeUtil.GetTimestamp(dtStart, local));
|
2025-10-30 22:48:36 +08:00
|
|
|
|
dtStart = dtStart.AddYears(num);
|
|
|
|
|
|
}
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
2025-10-30 22:48:36 +08:00
|
|
|
|
else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
|
2025-04-07 10:03:19 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : (int)Math.Max(range / (splitNumber * ONE_MONTH), 1);
|
2025-10-31 08:39:29 +08:00
|
|
|
|
var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp), local);
|
2025-10-30 22:48:36 +08:00
|
|
|
|
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
|
|
|
|
|
|
while (dtStart > dtMin)
|
|
|
|
|
|
{
|
|
|
|
|
|
dtStart = dtStart.AddMonths(-num);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (dtStart < dtMin)
|
|
|
|
|
|
{
|
|
|
|
|
|
dtStart = dtStart.AddMonths(num);
|
|
|
|
|
|
}
|
|
|
|
|
|
tick = num * 30 * 24 * 3600;
|
|
|
|
|
|
list.Clear();
|
|
|
|
|
|
while (dtStart.Ticks < dtMax.Ticks)
|
|
|
|
|
|
{
|
2025-10-31 08:39:29 +08:00
|
|
|
|
list.Add(DateTimeUtil.GetTimestamp(dtStart, local));
|
2025-10-30 22:48:36 +08:00
|
|
|
|
dtStart = dtStart.AddMonths(num);
|
|
|
|
|
|
}
|
2025-04-07 10:03:19 +08:00
|
|
|
|
}
|
2025-10-30 22:48:36 +08:00
|
|
|
|
else
|
2025-04-07 10:03:19 +08:00
|
|
|
|
{
|
2025-10-30 22:48:36 +08:00
|
|
|
|
int tickSecond;
|
|
|
|
|
|
if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
|
|
|
|
|
tickSecond = ONE_DAY;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
|
|
|
|
|
tickSecond = ONE_HOUR;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER)
|
|
|
|
|
|
{
|
|
|
|
|
|
tickSecond = ONE_MINUTE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
tickSecond = ONE_SECOND;
|
|
|
|
|
|
}
|
|
|
|
|
|
tick = GetTickSecond(range, splitNumber, tickSecond);
|
|
|
|
|
|
var let = minTimestamp % tickSecond;
|
|
|
|
|
|
var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
|
|
|
|
|
|
var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
|
|
|
|
|
|
while (startTimestamp > minTimestamp)
|
|
|
|
|
|
{
|
|
|
|
|
|
startTimestamp -= tick;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (startTimestamp < minTimestamp)
|
|
|
|
|
|
{
|
|
|
|
|
|
startTimestamp += tick;
|
|
|
|
|
|
}
|
|
|
|
|
|
list.Clear();
|
|
|
|
|
|
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
|
2025-04-07 10:03:19 +08:00
|
|
|
|
}
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
2022-07-29 07:49:15 +08:00
|
|
|
|
return tick;
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
private static double GetFirstMaxValue(List<double> list, double minTimestamp, double defaultTimestamp = 0)
|
2025-04-06 22:24:05 +08:00
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < list.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (list[i] >= minTimestamp)
|
|
|
|
|
|
{
|
|
|
|
|
|
return list[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-07 10:03:19 +08:00
|
|
|
|
return defaultTimestamp == 0 ? minTimestamp : defaultTimestamp;
|
2025-04-06 22:24:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
private static int GetSplitNumber(double range, int tickSecond)
|
2024-07-20 21:02:24 +08:00
|
|
|
|
{
|
|
|
|
|
|
var num = 1;
|
|
|
|
|
|
while (range / (num * tickSecond) > 8)
|
|
|
|
|
|
{
|
|
|
|
|
|
num++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return num;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
private static int GetTickSecond(double range, int splitNumber, int tickSecond)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
var num = 0;
|
|
|
|
|
|
if (splitNumber > 0)
|
|
|
|
|
|
{
|
2025-04-07 10:03:19 +08:00
|
|
|
|
num = (int)Math.Max(range / (splitNumber * tickSecond), 1);
|
2021-11-23 13:20:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
num = 1;
|
|
|
|
|
|
var tick = tickSecond;
|
|
|
|
|
|
while (range / tick > 8)
|
|
|
|
|
|
{
|
|
|
|
|
|
num++;
|
|
|
|
|
|
tick = num * tickSecond;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return num * tickSecond;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 10:03:19 +08:00
|
|
|
|
private static void AddTickTimestamp(List<double> list, double startTimestamp, double maxTimestamp, int tickSecond)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
2022-08-09 13:38:23 +08:00
|
|
|
|
while (startTimestamp <= maxTimestamp)
|
2021-11-23 13:20:07 +08:00
|
|
|
|
{
|
|
|
|
|
|
list.Add(startTimestamp);
|
|
|
|
|
|
startTimestamp += tickSecond;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|