Нет такой вещи как лучшая практика для этого. Вам необходимо найти компромисс между Calculation Cost
и Storage Cost
, и это зависит от того, как вы хотите работать со значениями даты и времени и где вы хотите выполнить вычисления для них. Мне известно, что многие люди используют несколько подходов:
- Сохранить персидскую дату как
nvarchar(10)
только для представления, сохранить григорианское эквивалентное значение в поле даты и времени и выполнить вычисления даты и времени в поле даты и времени. - Сохраните персидскую дату как
nvarchar(10)
и создайте пользовательский PersianDateTime
Type
в вашем C# коде, который может преобразовать это строковое значение в PersianDateTime
. Введите и выполните операции datetime с этим очень легко. В конце этого ответа я включил код для типа PersianDateTime. - Вы также можете создать Пользовательские типы в
SQL Server
и сохранить свое значение в качестве этого пользовательского типа. - Сохраните персидскую дату как
nvarchar(10)
и создайте пользовательские функции на SQL сервере для преобразования nvarchar в дату-время.
Вот код PersianDateTime
Type
, вы можете используйте его точно так же, как вы используете C#
встроенный Datetime
Type
:
public enum PersianDateTimeFormat
{
Date = 0,
DateTime = 1,
LongDate = 2,
LongDateLongTime = 3,
FullDate = 4,
FullDateLongTime = 5,
FullDateFullTime = 6,
DateShortTime = 7,
ShortDateShortTime = 8,
LongDateFullTime = 9
}
public enum PersianDateTimeMode
{
System,
PersianTimeZoneInfo,
UtcOffset
}
public class PersianDateTime
{
private readonly static PersianCalendar _persianCalendar = new PersianCalendar();
private readonly static string[] _dayNames = new string[] { "شنبه", "یکشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنج شنبه", "جمعه" };
private readonly static string[] _monthNames = new string[] { "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند" };
public static string AM = "ق.ظ";
public static string PM = "ب.ظ";
public static PersianDateTimeMode Mode = PersianDateTimeMode.UtcOffset;
public static TimeSpan DaylightSavingTimeStart = TimeSpan.FromDays(1);
public static TimeSpan DaylightSavingTimeEnd = TimeSpan.FromDays(185);
public static TimeSpan DaylightSavingTime = TimeSpan.FromHours(1);
public static TimeSpan OffsetFromUtc = new TimeSpan(3, 30, 0);
public static TimeZoneInfo PersianTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time");
public static TimeSpan operator -(PersianDateTime d1, PersianDateTime d2)
{
return d1.ToDateTime() - d2.ToDateTime();
}
public static bool operator >(PersianDateTime d1, PersianDateTime d2)
{
return d1.ToDateTime() > d2.ToDateTime();
}
public static bool operator >=(PersianDateTime d1, PersianDateTime d2)
{
return d1.ToDateTime() >= d2.ToDateTime();
}
public static bool operator <=(PersianDateTime d1, PersianDateTime d2)
{
return d1.ToDateTime() <= d2.ToDateTime();
}
public static PersianDateTime operator -(PersianDateTime d, TimeSpan t)
{
return new PersianDateTime(d.ToDateTime() - t);
}
public static PersianDateTime operator +(PersianDateTime d, TimeSpan t)
{
return new PersianDateTime(d.ToDateTime() + t);
}
public static bool operator <(PersianDateTime d1, PersianDateTime d2)
{
return d1.ToDateTime() < d2.ToDateTime();
}
public static bool operator ==(PersianDateTime d1, PersianDateTime d2)
{
if (object.ReferenceEquals(d1, null))
{
return object.ReferenceEquals(d2, null);
}
if (object.ReferenceEquals(d2, null))
{
return false;
}
return d1.ToDateTime() == d2.ToDateTime();
}
public static bool operator !=(PersianDateTime d1, PersianDateTime d2)
{
return !(d1 == d2);
}
public static string GetMonthName(int month)
{
return _monthNames[month + 1];
}
public static string GetDayName(int day)
{
return _dayNames[day];
}
public static bool IsLeapYear(int year)
{
return _persianCalendar.IsLeapYear(year);
}
public static int GetDaysInYear(int year)
{
return _persianCalendar.GetDaysInYear(year);
}
public static int GetDaysInMonth(int year, int month)
{
return _persianCalendar.GetDaysInMonth(year, month);
}
public static PersianDateTime Now
{
get
{
switch (Mode)
{
case PersianDateTimeMode.System:
return new PersianDateTime(DateTime.Now);
case PersianDateTimeMode.PersianTimeZoneInfo:
return new PersianDateTime(TimeZoneInfo.ConvertTime(DateTime.Now, PersianTimeZoneInfo));
case PersianDateTimeMode.UtcOffset:
PersianDateTime now = new PersianDateTime(DateTime.UtcNow.Add(OffsetFromUtc));
return now.IsInDaylightSavingTime ? now.Add(DaylightSavingTime) : now;
default:
throw new NotSupportedException(Mode.ToString());
}
}
}
public static PersianDateTime Parse(string persianDate)
{
return Parse(persianDate, "0");
}
public static PersianDateTime Parse(string persianDate, string time)
{
return new PersianDateTime(int.Parse(persianDate.Replace("/", "")), int.Parse(time.Replace(":", "")));
}
private readonly DateTime _dateTime;
public int Year
{
get { return _persianCalendar.GetYear(_dateTime); }
}
public int Month
{
get { return _persianCalendar.GetMonth(_dateTime); }
}
public int Day
{
get { return _persianCalendar.GetDayOfMonth(_dateTime); }
}
public int Hour
{
get { return _dateTime.Hour; }
}
public int Minute
{
get { return _dateTime.Minute; }
}
public int Second
{
get { return _dateTime.Second; }
}
public int Millisecond
{
get { return _dateTime.Millisecond; }
}
public long Ticks
{
get { return _dateTime.Ticks; }
}
private bool IsInDaylightSavingTime
{
get
{
TimeSpan timeOfYear = TimeOfYear;
return timeOfYear > DaylightSavingTimeStart && timeOfYear < DaylightSavingTimeEnd;
}
}
public TimeSpan TimeOfDay
{
get { return _dateTime.TimeOfDay; }
}
public TimeSpan TimeOfYear
{
get { return this - FirstDayOfYear; }
}
public TimeSpan TimeOfMonth
{
get { return this - FirstDayOfMonth; }
}
public TimeSpan TimeOfWeek
{
get { return this - FirstDayOfWeek; }
}
public PersianDateTime(DateTime dateTime)
{
_dateTime = dateTime;
}
public PersianDateTime(int persianDate)
: this(persianDate, 0)
{
}
public PersianDateTime(int persianDate, short time)
: this(persianDate, time * 100)
{
}
public PersianDateTime(int persianDate, int time)
{
int year = persianDate / 10000;
int month = (persianDate / 100) % 100;
int day = persianDate % 100;
int hour = time / 10000;
int minute = (time / 100) % 100;
int second = time % 100;
_dateTime = _persianCalendar.ToDateTime(year, month, day, hour, minute, second, 0);
}
public PersianDateTime(int year, int month, int day)
: this(year, month, day, 0, 0, 0)
{
}
public PersianDateTime(int year, int month, int day, int hour, int minute, int second)
{
_dateTime = _persianCalendar.ToDateTime(year, month, day, hour, minute, second, 0);
}
public bool IsLeapYear()
{
return _persianCalendar.IsLeapYear(Year);
}
public int DaysInYear
{
get { return _persianCalendar.GetDaysInYear(Year); }
}
public int DaysInMonth
{
get { return _persianCalendar.GetDaysInMonth(Year, Month); }
}
public int GetWeekOfYear(CalendarWeekRule rule)
{
return _persianCalendar.GetWeekOfYear(_dateTime, rule, System.DayOfWeek.Saturday);
}
public int DayOfYear
{
get { return _persianCalendar.GetDayOfYear(_dateTime); }
}
public int DayOfWeek
{
get { return ((int)_dateTime.DayOfWeek + 1) % 7; }
}
public string DayName
{
get { return _dayNames[DayOfWeek]; }
}
public string MonthName
{
get { return _monthNames[Month - 1]; }
}
public PersianDateTime Date
{
get { return new PersianDateTime(_dateTime.Date); }
}
public PersianDateTime FirstDayOfYear
{
get { return AddDays(-DayOfYear + 1).Date; }
}
public PersianDateTime LastDayOfYear
{
get { return AddDays(DaysInYear - DayOfYear).Date; }
}
public PersianDateTime FirstDayOfMonth
{
get { return AddDays(-Day + 1).Date; }
}
public PersianDateTime LastDayOfMonth
{
get { return AddDays(DaysInMonth - Day).Date; }
}
public PersianDateTime FirstDayOfWeek
{
get { return AddDays(-DayOfWeek).Date; }
}
public PersianDateTime LastDayOfWeek
{
get { return AddDays(6 - DayOfWeek).Date; }
}
public PersianDateTime AddSeconds(double value)
{
return new PersianDateTime(_dateTime.AddSeconds(value));
}
public PersianDateTime AddMinutes(double value)
{
return new PersianDateTime(_dateTime.AddMinutes(value));
}
public PersianDateTime AddHours(double value)
{
return new PersianDateTime(_dateTime.AddHours(value));
}
public PersianDateTime AddYears(int value)
{
var newYear = Year + value;
var daysInNewMonth = PersianDateTime.GetDaysInMonth(newYear, Month);
var newDay = daysInNewMonth < Day ? daysInNewMonth : Day;
return new PersianDateTime(Year + value, Month, Day).Add(TimeOfDay);
}
public PersianDateTime AddMonths(int value)
{
var months = Month + value;
var newYear = Year + (months > 0 ? (months - 1) / 12 : months / 12 - 1);
var newMonth = months > 0 ? (months - 1) % 12 + 1 : months % 12 + 12;
var daysInNewMonth = PersianDateTime.GetDaysInMonth(newYear, newMonth);
var newDay = daysInNewMonth < Day ? daysInNewMonth : Day;
return new PersianDateTime(newYear, newMonth, newDay).Add(TimeOfDay);
}
public PersianDateTime AddDays(double value)
{
return new PersianDateTime(_dateTime.AddDays(value));
}
public PersianDateTime Add(TimeSpan value)
{
return new PersianDateTime(_dateTime.Add(value));
}
public DateTime ToDateTime()
{
return _dateTime;
}
public int ToInt()
{
return int.Parse(Year.ToString() + Month.ToString().PadLeft(2, '0') + Day.ToString().PadLeft(2, '0'));
}
public override string ToString()
{
return ToString(PersianDateTimeFormat.DateTime);
}
public string ToString(string format)
{
string towDigitYear = (Year % 100).ToString();
string month = Month.ToString();
string day = Day.ToString();
string fullHour = Hour.ToString();
string hour = (Hour % 12 == 0 ? 12 : Hour % 12).ToString();
string minute = Minute.ToString();
string second = Second.ToString();
string dayPart = Hour >= 12 ? PM : AM;
return format.Replace("yyyy", Year.ToString())
.Replace("yy", towDigitYear.PadLeft(2, '0'))
.Replace("y", towDigitYear)
.Replace("MMMM", MonthName)
.Replace("MM", month.PadLeft(2, '0'))
.Replace("M", month)
.Replace("dddd", DayName)
.Replace("ddd", DayName[0].ToString())
.Replace("dd", day.PadLeft(2, '0'))
.Replace("d", day)
.Replace("HH", fullHour.PadLeft(2, '0'))
.Replace("H", fullHour.ToString())
.Replace("hh", hour.PadLeft(2, '0'))
.Replace("h", hour.ToString())
.Replace("mm", minute.PadLeft(2, '0'))
.Replace("m", minute.ToString())
.Replace("ss", second.PadLeft(2, '0'))
.Replace("s", second)
.Replace("tt", dayPart)
.Replace('t', dayPart[0]);
}
public string ToString(PersianDateTimeFormat format)
{
switch (format)
{
case PersianDateTimeFormat.Date:
return Year.ToString() + "/" + Month.ToString().PadLeft(2, '0') + "/" + Day.ToString().PadLeft(2, '0');
case PersianDateTimeFormat.DateTime:
return ToString(PersianDateTimeFormat.Date) + " " + TimeOfDay.ToHHMMSS();
case PersianDateTimeFormat.DateShortTime:
return ToString(PersianDateTimeFormat.Date) + " " + TimeOfDay.ToHHMM();
case PersianDateTimeFormat.LongDate:
return DayName + " " + Day + " " + MonthName;
case PersianDateTimeFormat.LongDateFullTime:
return DayName + " " + Day + " " + MonthName + " ساعت " + TimeOfDay.ToHHMMSS();
case PersianDateTimeFormat.LongDateLongTime:
return DayName + " " + Day + " " + MonthName + " ساعت " + TimeOfDay.ToHHMM();
case PersianDateTimeFormat.ShortDateShortTime:
return Day.ToString() + " " + MonthName + " " + TimeOfDay.ToHHMM();
case PersianDateTimeFormat.FullDate:
return DayName + " " + Day + " " + MonthName + " " + Year;
case PersianDateTimeFormat.FullDateLongTime:
return DayName + " " + Day + " " + MonthName + " " + Year + " ساعت " + TimeOfDay.ToHHMM();
case PersianDateTimeFormat.FullDateFullTime:
return DayName + " " + Day + " " + MonthName + " " + Year + " ساعت " + TimeOfDay.ToHHMMSS();
default:
throw new NotImplementedException(format.ToString());
}
}
public override int GetHashCode()
{
return _dateTime.GetHashCode();
}
public override bool Equals(object value)
{
return Equals(value as PersianDateTime);
}
public bool Equals(PersianDateTime value)
{
if (object.ReferenceEquals(value, null))
{
return false;
}
return _dateTime.Equals(value._dateTime);
}
}