Сохранить PersianCalendar как строку в таблице вместо типа DateTime - PullRequest
1 голос
/ 20 марта 2020

У меня есть приложение, которое использует PersianCalender. Если я сохраню дату в виде строки в персидском формате («1399/01/01»), это будет так просто сделать запрос. Но я не уверен насчет производительности и других последствий.

Какова лучшая практика? Должен ли я избегать сохранения даты в виде строки и просто сохранять их как тип DateTime и конвертировать их каждый раз, когда мне это нужно? Есть ли лучшие решения?

1 Ответ

1 голос
/ 21 марта 2020

Нет такой вещи как лучшая практика для этого. Вам необходимо найти компромисс между Calculation Cost и Storage Cost, и это зависит от того, как вы хотите работать со значениями даты и времени и где вы хотите выполнить вычисления для них. Мне известно, что многие люди используют несколько подходов:

  1. Сохранить персидскую дату как nvarchar(10) только для представления, сохранить григорианское эквивалентное значение в поле даты и времени и выполнить вычисления даты и времени в поле даты и времени.
  2. Сохраните персидскую дату как nvarchar(10) и создайте пользовательский PersianDateTime Type в вашем C# коде, который может преобразовать это строковое значение в PersianDateTime. Введите и выполните операции datetime с этим очень легко. В конце этого ответа я включил код для типа PersianDateTime.
  3. Вы также можете создать Пользовательские типы в SQL Server и сохранить свое значение в качестве этого пользовательского типа.
  4. Сохраните персидскую дату как 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);
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...