JavaRush /Курси /C# SELF /Основні типи роботи з часом

Основні типи роботи з часом

C# SELF
Рівень 15 , Лекція 0
Відкрита

1. Знайомство з типом DateTime

Дата й час — це така базова цеглинка будь-якої бізнес-логіки, що її не можна ігнорувати навіть у найпростіших проєктах. Дуже часто потрібно знати, коли користувач зареєструвався, коли надіслати лист, як правильно опрацювати розклад рейсів; і часові пояси — всюди потрібні дати! Але, як показує практика, робота з датою й часом — одна з найпідступніших тем у програмуванні. 😅

C# пропонує два особливо важливих типи для роботи з часом: DateTime і DateTimeOffset. Якщо коротко — один для простих сценаріїв, інший для завдань, пов’язаних із часовими поясами та точним зберіганням часу.

Що таке DateTime?

Тип DateTime — це структура, визначена у просторі імен System. Вона призначена для зберігання дати й часу з точністю до 100 наносекунд (однієї десятимільярдної секунди).

  • Тип значення (struct), тобто копіюється за значенням.
  • Містить і дату, і час.
  • Дозволяє зберігати як просто дату (2025-05-24), так і дату з часом (2025-05-24 15:17:42).
  • «Не знає» про часові пояси, доки це явно не вказано.

2. Створюємо DateTime

Варіантів кілька, розгляньмо основні.

1. Поточна дата і час

DateTime now = DateTime.Now;           // Локальний час компʼютера
DateTime utcNow = DateTime.UtcNow;     // Час за Гринвічем (UTC)
  • Now — це «як на вашому компʼютері», з урахуванням локального часового поясу Windows.
  • UtcNow — «універсальний», тобто всесвітній координований час. Дуже зручно для зберігання часу, наприклад, у базах даних або системах, що працюють у всьому світі.

2. Конструктори

// Рік, місяць, день
var date1 = new DateTime(2025, 5, 24);

// Рік, місяць, день, години, хвилини, секунди
var date2 = new DateTime(2025, 5, 24, 12, 0, 0);

// Рік, місяць, день, години, хвилини, секунди, мілісекунди
var date3 = new DateTime(2025, 5, 24, 12, 0, 0, 500);

Місяці не нумеруються від нуля! Тобто січень — це 1, грудень — 12.

3. Парсинг із рядка

Дуже часто дата надходить у вигляді рядка! Наприклад, користувач вводить її вручну.

string userInput = "2025-05-24 18:30";
DateTime parsed = DateTime.Parse(userInput); // Може згенерувати виняток!

Для безпечного парсингу скористайтеся TryParse:

string input = "2025-05-24 18:30";
if (DateTime.TryParse(input, out DateTime result))
{
    Console.WriteLine($"Перетворено успішно: {result}");
}
else
{
    Console.WriteLine("Не вдалося перетворити рядок на дату.");
}

4. Отримання дати «без часу»

DateTime today = DateTime.Today; // Поточний день, але час = 00:00:00

Отримання компонентів дати й часу

Усі властивості доступні напряму:

var dt = new DateTime(2025, 5, 24, 15, 17, 42);

int year = dt.Year;         // 2025
int month = dt.Month;       // 5 (травень)
int day = dt.Day;           // 24
int hour = dt.Hour;         // 15
int minute = dt.Minute;     // 17
int second = dt.Second;     // 42
DayOfWeek dow = dt.DayOfWeek; // пʼятниця

3. Робота з типом DateTime

Додавання і віднімання дат

Час у програмуванні плине швидко, тож, щоб не вираховувати «скільки годин до дедлайну», користуйтеся методами класу:

DateTime now = DateTime.Now;
DateTime tomorrow = now.AddDays(1); // Завтра
DateTime afterFiveHours = now.AddHours(5); // Через 5 годин
DateTime inTenMinutes = now.AddMinutes(10); // Через 10 хвилин

Різниця двох дат: TimeSpan

Різниця між двома датами — це окрема величина, тип TimeSpan:

DateTime deadline = new DateTime(2026, 6, 1);
DateTime now = DateTime.Now;

TimeSpan untilDeadline = deadline - now;

Console.WriteLine($"До дедлайну залишилося днів: {untilDeadline.Days}");
Console.WriteLine($"До дедлайну залишилося годин: {untilDeadline.TotalHours:N2}");

TimeSpan — це «різниця», а не «конкретна дата/час»!

Перевірка дати у майбутньому/минулому

if (deadline > now)
    Console.WriteLine("Дедлайн ще попереду!");
else
    Console.WriteLine("Дедлайн вже минув! Терміново здаємо роботу!");

4. Як зберігаються дати під капотом

Щоб зручно додавати та віднімати дати, у .NET їх зберігають як кількість «тіків», що минули з початку літочислення. Діапазон значень:

Властивість Значення
Мінімальна дата
DateTime.MinValue
= 0001-01-01 00:00:00
Максимальна дата
DateTime.MaxValue
= 9999-12-31 23:59:59.9999999
Одиниця вимірювання 1 тік = 100 наносекунд

DateTime зберігає не кількість секунд, а кількість «тіків» (ticks) від особливої дати — 1 січня 0001 року (так-так, програмісти не знають про динозаврів, їхнє літочислення суворіше). Один тік дорівнює 100 наносекундам.

5. Тип DateTimeOffset

Іноді типу DateTime замало. Розгляньмо класичний випадок: компанія працює у двох країнах, часові пояси різні, а всі зустрічі заплановані «за моїм часом». Як бути?

Час, записаний як DateTime, зазвичай «абстрактний»: це просто набір цифр і тік, доки ви не вкажете явно, у якому поясі це було. Наприклад, якщо ви отримали "2025-05-24 15:00", ви не можете бути певні: це за часом Найробі? Багдада? Берліна? (а якщо ще й літній час — тримайтеся міцніше!).

Тому для завдань, пов’язаних із точним моментом у часі, а не просто з «датою календаря», з’явився другий тип — DateTimeOffset. Створення DateTimeOffset із вказанням зміщення (наприклад, Найробі +3 до UTC):


var localTime = new DateTimeOffset(2025, 5, 24, 15, 0, 0, TimeSpan.FromHours(3));

Використовуйте DateTimeOffset, якщо:

  • Треба знати точний момент часу (наприклад, для подій у журналі подій, прив’язаних до серверного часу).
  • Програма працює з користувачами у різних часових поясах.
  • Потрібно зберігати/передавати час із зазначенням поясу (наприклад, для транзакцій, подій, розкладів).

6. Як створити DateTimeOffset?

  1. Поточний момент часу
    DateTimeOffset now = DateTimeOffset.Now; // Локальний час + зміщення
    DateTimeOffset utc = DateTimeOffset.UtcNow; // UTC (нульове зміщення)
    
  2. Явне створення
    // Рік, місяць, день, година, хвилина, секунда, зміщення (наприклад, +2 години)
    DateTimeOffset custom = new DateTimeOffset(2025, 5, 24, 20, 0, 0, TimeSpan.FromHours(2));
    
  3. Перетворення з DateTime
    DateTime dt = DateTime.Now;
    DateTimeOffset dto = new DateTimeOffset(dt); // Локальне зміщення підхопиться автоматично
    

Отримання компонентів

DateTimeOffset dto = DateTimeOffset.Now;
var datePart = dto.Date;      // Тільки дата
var timePart = dto.TimeOfDay; // Тільки час
var offset = dto.Offset;      // Зміщення відносно UTC, наприклад, 03:00:00

Перетворення між часовими поясами

Магія зміщень:

// Отримуємо дату в UTC
var now = DateTimeOffset.Now;
var utc = now.ToUniversalTime();
Console.WriteLine(utc); // Час за Гринвічем

// Переводимо в інший часовий пояс
var berlinTime = utc.ToOffset(TimeSpan.FromHours(2));
Console.WriteLine(berlinTime); // Для Берліна (UTC+2)

7. Коли використовувати DateTime, а коли — DateTimeOffset?

Філософія вибору

Коли йдеться про щось просте й локальне — наприклад, день народження, дату публікації статті або дедлайн для опитування до 15:00, найчастіше достатньо DateTime. У таких випадках абсолютний час не критичний, важливо лише, що подія відбулася у певний день і годину, без прив’язки до часового поясу.

А от якщо треба зафіксувати конкретний момент часу з урахуванням часового поясу, наприклад, у логах, транзакціях або розподілених системах — краще використовувати DateTimeOffset. Він не дасть заплутатися під час передавання часу між системами, особливо якщо вони перебувають у різних часових поясах.

Сценарій Тип Чому
День народження
DateTime
Важлива лише дата, пояс неважливий (зазвичай)
Час логіну
DateTimeOffset
Важливо знати точний момент і зміщення
Термін дії товару
DateTime
Дата закінчення, пояс неважливий
Час події у журналі подій
DateTimeOffset
Бажано завжди зберігати зі зміщенням
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ