ProjectDDD/Assets/_Datas/SLShared/SLSystem/SLDateTimeUtil.cs
2025-06-17 20:47:57 +09:00

209 lines
6.8 KiB (Stored with Git LFS)
C#

using System;
using Superlazy;
public static class SLDateTimeUtil
{
private const double oADateMaxAsDouble = 2958466.0;
private const double oADateMinAsDouble = -657435.0;
private const int millisPerSecond = 1000;
private const int millisPerMinute = millisPerSecond * 60;
private const int millisPerHour = millisPerMinute * 60;
private const int millisPerDay = millisPerHour * 24;
// Number of 100ns ticks per time unit
private const long ticksPerMillisecond = 10000;
private const long ticksPerSecond = ticksPerMillisecond * 1000;
private const long ticksPerMinute = ticksPerSecond * 60;
private const long ticksPerHour = ticksPerMinute * 60;
private const long ticksPerDay = ticksPerHour * 24;
// Number of days in a non-leap year
private const int daysPerYear = 365;
// Number of days in 4 years
private const int daysPer4Years = daysPerYear * 4 + 1; // 1461
// Number of days in 100 years
private const int daysPer100Years = daysPer4Years * 25 - 1; // 36524
// Number of days in 400 years
private const int daysPer400Years = daysPer100Years * 4 + 1; // 146097
// Number of days from 1/1/0001 to 12/31/1600
// Number of days from 1/1/0001 to 12/30/1899
private const int daysTo1899 = daysPer400Years * 4 + daysPer100Years * 3 - 367;
// Number of days from 1/1/0001 to 12/31/1969
// Number of days from 1/1/0001 to 12/31/9999
private const int daysTo10000 = daysPer400Years * 25 - 366; // 3652059
private const long doubleDateOffset = daysTo1899 * ticksPerDay;
private const long maxMillis = (long)daysTo10000 * millisPerDay;
private const long oADateMinAsTicks = (daysPer100Years - daysPerYear) * ticksPerDay;
private static long DoubleDateToTicks(double value)
{
// The check done this way will take care of NaN
if (!(value < oADateMaxAsDouble) || !(value > oADateMinAsDouble))
{
return 0;
}
// Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble
var millis = (long)(value * millisPerDay + (value >= 0 ? 0.5 : -0.5));
// The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899
// However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative
// This line below fixes up the millis in the negative case
if (millis < 0)
{
millis -= (millis % millisPerDay) * 2;
}
millis += doubleDateOffset / ticksPerMillisecond;
if (millis < 0 || millis >= maxMillis)
{
return 0;
}
return millis * ticksPerMillisecond;
}
private static double TicksToOADate(long value)
{
if (value == 0)
return 0.0; // Returns OleAut's zero'ed date value.
if (value < ticksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899.
value += doubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check.
if (value < oADateMinAsTicks)
throw new OverflowException();
// Currently, our max date == OA's max date (12/31/9999), so we don't
// need an overflow check in that direction.
var millis = (value - doubleDateOffset) / ticksPerMillisecond;
if (millis < 0)
{
var frac = millis % millisPerDay;
if (frac != 0) millis -= (millisPerDay + frac) * 2;
}
return Math.Round((double)millis / millisPerDay, 10);
}
public static DateTime FromSLDate(double d)
{
return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
}
public static DateTime FromSLDateToKRDate(double d)
{
return (new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified)).AddHours(9);
}
public static DateTime ToDateTime(this SLEntity value)
{
return new DateTime(DoubleDateToTicks(value), DateTimeKind.Unspecified);
}
public static DateTime ToLocalDateTime(this SLEntity value)
{
return new DateTime(DoubleDateToTicks(value), DateTimeKind.Unspecified).ToLocalTime();
}
public static DateTime ToDayStart(this DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day);
}
public static DateTime ToKRInitTime(this DateTime dt)
{
return dt.AddDays(1).AddHours(3).ToDayStart().AddHours(-3);
}
public static DateTime ToRankingEndTime(this DateTime dt)
{
return dt.AddDays(1).AddHours(3).AddMinutes(15).ToDayStart().AddHours(-3).AddMinutes(-15);
}
public static DateTime ToWeekliyInitTime(this DateTime dt)
{
if (dt < dt.ToKRInitTime().AddDays(-1))
{
return dt.ToKRInitTime().AddDays(-1);
}
else
{
var delta = 7 + DayOfWeek.Monday - dt.DayOfWeek;
return dt.AddDays(delta).AddHours(3).ToDayStart().AddHours(-3);
}
}
public static double ToSLDate(this DateTime dt)
{
return TicksToOADate(dt.Ticks);
}
public static double FromKRDateToSLDate(this DateTime dt)
{
return TicksToOADate(dt.AddHours(-9).Ticks);
}
public static string ToSLDateString(this DateTime dt)
{
return dt.ToString("yyyy-MM-dd");
}
public static string ToSLDateTimeString(this DateTime dt)
{
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
public static string ToSLDateTimeString(this DateTimeOffset dt)
{
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
public static bool IsDateIn(DateTime date, SLEntity checkDate)
{
var start = new DateTime(checkDate["YStart"], checkDate["MStart"], checkDate["DStart"], checkDate["HStart"], 0, 0);
if (checkDate["YEnd"] == false) checkDate["YEnd"] = checkDate["YStart"];
if (checkDate["MEnd"] == false) checkDate["MEnd"] = checkDate["MStart"];
if (checkDate["DEnd"] == false) checkDate["DEnd"] = checkDate["DStart"];
if (checkDate["HEnd"] == false) checkDate["HEnd"] = checkDate["HStart"];
var end = new DateTime(checkDate["YEnd"], checkDate["MEnd"], checkDate["DEnd"], checkDate["HEnd"], 0, 0);
return date >= start && date < end;
}
}
public abstract class SLDateTime
{
private static SLDateTime instance;
public static void Init(SLDateTime inst)
{
instance = inst;
}
public static DateTime Now
{
get
{
if (instance == null) return DateTime.UtcNow;
return instance.GetNow();
}
set
{
if (instance == null) return;
instance.SetNow(value);
}
}
protected abstract DateTime GetNow();
protected abstract void SetNow(DateTime now);
}