diff --git a/_data/sidebars/flexberry-orm_sidebar.yml b/_data/sidebars/flexberry-orm_sidebar.yml index 7b1bcf204..a976f8811 100644 --- a/_data/sidebars/flexberry-orm_sidebar.yml +++ b/_data/sidebars/flexberry-orm_sidebar.yml @@ -347,6 +347,10 @@ entries: title_ru: Пример использования собственных типов url: /fo_using-custom-types-example.html output: web + - title: DateOnly and TimeOnly support + title_ru: Поддержка DateOnly и TimeOnly + url: /fo_date-only-time-only.html + output: web - title: Язык запросов output: web, pdf diff --git a/pages/products/flexberry-orm/data-types/fo_date-only-time-only.en.md b/pages/products/flexberry-orm/data-types/fo_date-only-time-only.en.md new file mode 100644 index 000000000..bfc3c5897 --- /dev/null +++ b/pages/products/flexberry-orm/data-types/fo_date-only-time-only.en.md @@ -0,0 +1,252 @@ +--- +title: DateOnly and TimeOnly support +keywords: Programming +sidebar: flexberry-orm_sidebar +toc: true +permalink: en/fo_date-only-time-only.html +lang: en +--- + +## Overview + +Types `DateOnly` and `TimeOnly` appeared in .NET 6.0. Flexberry ORM supports these types, while for compilation for earlier .NET versions, `DateTime` is used as a replacement. + +## Type conversion + +### Information.SetPropValueByName + +The `SetPropValueByName` method automatically performs conversion between time types: + +| From | To | Behavior | +|---|---|---| +| `DateTime` | `DateOnly` | Only date is used, time is discarded | +| `TimeSpan` | `TimeOnly` | Conversion via `TimeOnly.FromTimeSpan` | +| `string` | `DateOnly/TimeOnly` | Parsing via `Parse/TryParse` | + +Example: +```csharp +var obj = new MyEntity(); + +// DateTime converts to DateOnly (date only) +Information.SetPropValueByName(obj, "BirthDate", new DateTime(2026, 5, 20, 14, 30, 0)); +// result: BirthDate = new DateOnly(2026, 5, 20) + +// TimeSpan converts to TimeOnly (time only) +Information.SetPropValueByName(obj, "StartTime", new TimeSpan(14, 30, 45)); +// result: StartTime = new TimeOnly(14, 30, 45) +``` + +### Information.ParsePropertyValue + +The `ParsePropertyValue` method converts string representations to `DateOnly` and `TimeOnly` types: + +```csharp +var result = Information.ParsePropertyValue(typeof(MyEntity), "BirthDate", "2026-05-20"); +// result: new DateOnly(2026, 5, 20) + +var result = Information.ParsePropertyValue(typeof(MyEntity), "StartTime", "14:30:45"); +// result: new TimeOnly(14, 30, 45) +``` + +## LCS functions + +The following functions are available for date handling: + +| Function | Description | Return type | +|---------|----------|------------------| +| `funcDayNumber` | Day number from 0001-01-01 | Numeric | +| `funcDayOfYear` | Day of year (1-366) | Numeric | +| `funcSSPart` | Seconds from DateTime | Numeric | + +Usage example: +```csharp +var langDef = ExternalLangDef.LanguageDef; +var varDef = new VariableDef(langDef.DateTimeType, "MyDateField"); + +// Find records where day of year = 150 +var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(MyEntity), view); +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcDayOfYear, varDef), + 150); +``` + +## LINQ Provider + +### Supported properties and methods + +**DateOnly:** +- `Year`, `Month`, `Day` +- `DayOfWeek` +- `DayNumber` — day number from 0001-01-01 +- `DayOfYear` — day of year + +**TimeOnly:** +- `Hour`, `Minute`, `Second` +- `TimeOfDay` + +LINQ query examples: + +```csharp +// Equality +var result = ds.Query() + .Where(x => x.BirthDate == new DateOnly(2026, 5, 20)) + .ToList(); + +// Comparison +var result = ds.Query() + .Where(x => x.BirthDate > new DateOnly(2025, 1, 1)) + .ToList(); + +// Year and month +var result = ds.Query() + .Where(x => x.BirthDate.Year == 2026 && x.BirthDate.Month == 5) + .ToList(); + +// Day of week +var result = ds.Query() + .Where(x => x.BirthDate.DayOfWeek == DayOfWeek.Monday) + .ToList(); + +// Seconds of time +var result = ds.Query() + .Where(x => x.MeetingTime.Second == 30) + .ToList(); +``` + +### LCS queries + +LINQ expressions with `DateOnly` and `TimeOnly` are automatically translated to LCS: + +```csharp +var langDef = ExternalLangDef.LanguageDef; +var varDef = new VariableDef(langDef.DateTimeType, "BirthDate"); + +// Year +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcYearPart, varDef), + 2026); + +// Day of year +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcDayOfYear, varDef), + 150); + +// Day from 0001-01-01 +lcs.LimitFunction = langDef.GetFunction( + langDef.funcG, + langDef.GetFunction(langDef.funcDayNumber, varDef), + 739000); +``` + +## Working with databases + +### PostgreSQL + +**SQL representation:** +```csharp +DateOnly -> cast(value as date) +TimeOnly -> cast(value as time) + +DateOnly -> date '2026-05-20' +TimeOnly -> time '14:30:45.123456' +``` + +**Supported functions:** +- `EXTRACT (HOUR FROM ...)`, `EXTRACT (MINUTE FROM ...)`, `EXTRACT (SECOND FROM ...)` +- `EXTRACT (DOY FROM ...)` — day of year +- Date subtraction for day number + +### MSSQL + +**SQL representation:** +```csharp +DateOnly -> '20260520' (format yyyyMMdd) +TimeOnly -> '14:30:45.fff' (format HH:mm:ss.fff) +``` + +**Supported functions:** +- `datepart(hour, ...)`, `datepart(minute, ...)` +- `DATEDIFF(day, '0001-01-01', ...)` — day number +- `DATEPART(dy, ...)` — day of year + +### Oracle + +**SQL representation:** +```csharp +DateOnly -> TO_DATE('2026-05-20', 'YYYY-MM-DD') +TimeOnly -> TO_TIMESTAMP('14:30:45.123', 'HH24:MI:SS.FF3') +``` + +**Supported functions:** +- `TO_CHAR(..., 'SS')` — seconds +- `TO_NUMBER(TO_CHAR(..., 'DDD'))` — day of year +- Date subtraction for day number + +## Nullable types + +Both `DateOnly?` and `TimeOnly?` are supported: + +```csharp +public virtual System.DateOnly? OptionalDate { get; set; } +public virtual System.TimeOnly? OptionalTime { get; set; } +``` + +Examples: + +```csharp +// Assign null +obj.OptionalDate = null; +obj.OptionalTime = null; + +// Null check in LINQ +var result = ds.Query() + .Where(x => x.OptionalDate != null) + .ToList(); + +// LCS with nullable +var varDef = new VariableDef(langDef.DateTimeType, "OptionalDate"); +var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(MyEntity), view); +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + varDef, + new DateOnly?(new DateOnly(2026, 5, 20))); +``` + +## Data types in functional language + +`DateOnly` and `TimeOnly` are mapped to `DateTimeType` in the functional language, ensuring a unified API for all time types. + +## Object definition example + +```csharp +public class MyEntity : ICSSoft.STORMNET.DataObject +{ +#if NET6_0_OR_GREATER + private System.DateOnly fBirthDate; + private System.TimeOnly fMeetingTime; +#else + private System.DateTime fBirthDate; + private System.DateTime fMeetingTime; +#endif + +#if NET6_0_OR_GREATER + public virtual System.DateOnly BirthDate + { + get => fBirthDate; + set => fBirthDate = value; + } + + public virtual System.TimeOnly MeetingTime + { + get => fMeetingTime; + set => fMeetingTime = value; + } + + public virtual System.DateOnly? OptionalDate { get; set; } + public virtual System.TimeOnly? OptionalTime { get; set; } +#endif +} +``` diff --git a/pages/products/flexberry-orm/data-types/fo_date-only-time-only.ru.md b/pages/products/flexberry-orm/data-types/fo_date-only-time-only.ru.md new file mode 100644 index 000000000..d3334c426 --- /dev/null +++ b/pages/products/flexberry-orm/data-types/fo_date-only-time-only.ru.md @@ -0,0 +1,252 @@ +--- +title: Поддержка DateOnly и TimeOnly в Flexberry ORM +keywords: Programming +sidebar: flexberry-orm_sidebar +toc: true +permalink: ru/fo_date-only-time-only.html +lang: ru +--- + +## Обзор + +Типы `DateOnly` и `TimeOnly` появились в .NET 6.0. Flexberry ORM поддерживает эти типы, при этом при компиляции для более ранних версий.NET используется `DateTime` в качестве замены. + +## Конвертация типов + +### Information.SetPropValueByName + +Метод `SetPropValueByName` автоматически выполняет конвертацию между временными типами: + +| Из | В | Поведение | +|---|---|---| +| `DateTime` | `DateOnly` | Используется только дата, время отбрасывается | +| `TimeSpan` | `TimeOnly` | Преобразование через `TimeOnly.FromTimeSpan` | +| `string` | `DateOnly/TimeOnly` | Парсинг через `Parse/TryParse` | + +Пример: +```csharp +var obj = new MyEntity(); + +// DateTime конвертируется в DateOnly (только дата) +Information.SetPropValueByName(obj, "BirthDate", new DateTime(2026, 5, 20, 14, 30, 0)); +// результат: BirthDate = new DateOnly(2026, 5, 20) + +// TimeSpan конвертируется в TimeOnly (только время) +Information.SetPropValueByName(obj, "StartTime", new TimeSpan(14, 30, 45)); +// результат: StartTime = new TimeOnly(14, 30, 45) +``` + +### Information.ParsePropertyValue + +Метод `ParsePropertyValue` преобразует строковые представления в типы `DateOnly` и `TimeOnly`: + +```csharp +var result = Information.ParsePropertyValue(typeof(MyEntity), "BirthDate", "2026-05-20"); +// результат: new DateOnly(2026, 5, 20) + +var result = Information.ParsePropertyValue(typeof(MyEntity), "StartTime", "14:30:45"); +// результат: new TimeOnly(14, 30, 45) +``` + +## Функции LCS + +Для работы с датами доступны следующие функции: + +| Функция | Описание | Возвращаемый тип | +|---------|----------|------------------| +| `funcDayNumber` | Номер дня от 0001-01-01 | Numeric | +| `funcDayOfYear` | День от начала года (1-366) | Numeric | +| `funcSSPart` | Секунды от DateTime | Numeric | + +Пример использования: +```csharp +var langDef = ExternalLangDef.LanguageDef; +var varDef = new VariableDef(langDef.DateTimeType, "MyDateField"); + +// Найти записи, где день от начала года = 150 +var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(MyEntity), view); +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcDayOfYear, varDef), + 150); +``` + +## LINQ Provider + +### Поддерживаемые свойства и методы + +**DateOnly:** +- `Year`, `Month`, `Day` +- `DayOfWeek` +- `DayNumber` — номер дня от 0001-01-01 +- `DayOfYear` — день от начала года + +**TimeOnly:** +- `Hour`, `Minute`, `Second` +- `TimeOfDay` + +Пример LINQ-запросов: + +```csharp +// Равенство +var result = ds.Query() + .Where(x => x.BirthDate == new DateOnly(2026, 5, 20)) + .ToList(); + +// Сравнение +var result = ds.Query() + .Where(x => x.BirthDate > new DateOnly(2025, 1, 1)) + .ToList(); + +// Год и месяц +var result = ds.Query() + .Where(x => x.BirthDate.Year == 2026 && x.BirthDate.Month == 5) + .ToList(); + +// День недели +var result = ds.Query() + .Where(x => x.BirthDate.DayOfWeek == DayOfWeek.Monday) + .ToList(); + +// Секунды времени +var result = ds.Query() + .Where(x => x.MeetingTime.Second == 30) + .ToList(); +``` + +### LCS-запросы + +LINQ-выражения с `DateOnly` и `TimeOnly` автоматически транслируются в LCS: + +```csharp +var langDef = ExternalLangDef.LanguageDef; +var varDef = new VariableDef(langDef.DateTimeType, "BirthDate"); + +// Год +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcYearPart, varDef), + 2026); + +// День года +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + langDef.GetFunction(langDef.funcDayOfYear, varDef), + 150); + +// День от 0001-01-01 +lcs.LimitFunction = langDef.GetFunction( + langDef.funcG, + langDef.GetFunction(langDef.funcDayNumber, varDef), + 739000); +``` + +## Работа с базами данных + +### PostgreSQL + +**SQL-представление:** +```csharp +DateOnly -> cast(value as date) +TimeOnly -> cast(value as time) + +DateOnly -> date '2026-05-20' +TimeOnly -> time '14:30:45.123456' +``` + +**Поддерживаемые функции:** +- `EXTRACT (HOUR FROM ...)`, `EXTRACT (MINUTE FROM ...)`, `EXTRACT (SECOND FROM ...)` +- `EXTRACT (DOY FROM ...)` — день года +- Вычитание дат для номера дня + +### MSSQL + +**SQL-представление:** +```csharp +DateOnly -> '20260520' (формат yyyyMMdd) +TimeOnly -> '14:30:45.fff' (формат HH:mm:ss.fff) +``` + +**Поддерживаемые функции:** +- `datepart(hour, ...)`, `datepart(minute, ...)` +- `DATEDIFF(day, '0001-01-01', ...)` — номер дня +- `DATEPART(dy, ...)` — день года + +### Oracle + +**SQL-представление:** +```csharp +DateOnly -> TO_DATE('2026-05-20', 'YYYY-MM-DD') +TimeOnly -> TO_TIMESTAMP('14:30:45.123', 'HH24:MI:SS.FF3') +``` + +**Поддерживаемые функции:** +- `TO_CHAR(..., 'SS')` — секунды +- `TO_NUMBER(TO_CHAR(..., 'DDD'))` — день года +- Вычитание дат для номера дня + +## Nullable-типы + +Поддерживаются как `DateOnly?`, так и `TimeOnly?`: + +```csharp +public virtual System.DateOnly? OptionalDate { get; set; } +public virtual System.TimeOnly? OptionalTime { get; set; } +``` + +Примеры: + +```csharp +// Присваивание null +obj.OptionalDate = null; +obj.OptionalTime = null; + +// Проверка на null в LINQ +var result = ds.Query() + .Where(x => x.OptionalDate != null) + .ToList(); + +// LCS с nullable +var varDef = new VariableDef(langDef.DateTimeType, "OptionalDate"); +var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(MyEntity), view); +lcs.LimitFunction = langDef.GetFunction( + langDef.funcEQ, + varDef, + new DateOnly?(new DateOnly(2026, 5, 20))); +``` + +## Типы данных в функциональном языке + +`DateOnly` и `TimeOnly` отображаются на `DateTimeType` в функциональном языке, что обеспечивает единообразный API для всех временных типов. + +## Пример определения объекта + +```csharp +public class MyEntity : ICSSoft.STORMNET.DataObject +{ +#if NET6_0_OR_GREATER + private System.DateOnly fBirthDate; + private System.TimeOnly fMeetingTime; +#else + private System.DateTime fBirthDate; + private System.DateTime fMeetingTime; +#endif + +#if NET6_0_OR_GREATER + public virtual System.DateOnly BirthDate + { + get => fBirthDate; + set => fBirthDate = value; + } + + public virtual System.TimeOnly MeetingTime + { + get => fMeetingTime; + set => fMeetingTime = value; + } + + public virtual System.DateOnly? OptionalDate { get; set; } + public virtual System.TimeOnly? OptionalTime { get; set; } +#endif +} +```