Menu

Даты в R: as.Date, format() и арифметика дат

Класс Date в R — это счётчик дней в костюме. Как разбирать строки через as.Date, форматировать даты для вывода, вычитать их, строить последовательности и когда вместо этого нужен POSIXct.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Дата в R — это счётчик дней в костюме

Чтобы превратить строку в настоящую дату, используйте as.Date(); чтобы получить сегодняшний день — Sys.Date(). За обеими стоит простой трюк: класс Date в R — это просто число, счёт дней с 1 января 1970 года, надевшее костюм, из-за которого оно печатается как календарная дата. Костюм можно снять через unclass():

Это 20672 — сырой счёт дней, и именно он заставляет работать всё остальное на этой странице: сравнения, вычитание и последовательности внизу являются обычной целочисленной арифметикой. А костюм делает всё это пригодным к использованию: то же число печатается как дата, форматируется как дата и рисуется на оси дат.

as.Date() спокойно разбирает раскладку ISO "YYYY-MM-DD" без всякой помощи, и это одна из нескольких хороших причин хранить даты в файлах именно так. Одна привычка, которую стоит выработать пораньше: неудачный разбор молча возвращает NA, а не ошибку, — так что всегда бросайте взгляд на результат после разбора чего-то нового.

Строки, которые лишь выглядят как даты, остаются обычными строками: "2026-08-07" < "2026-11-01" случайно сравнивается верно, потому что порядок ISO совпадает с алфавитным, а вот "07/08/2026" сортируется бессмысленно. Сначала преобразуйте, потом сравнивайте.

Разбор других раскладок через format =

Мир не пишет даты в формате ISO. Для всего остального as.Date() принимает аргумент format = — рецепт, описывающий входную строку и собранный из кодов с %.

Все три разбираются в один и тот же день. Рецепт должен точно соответствовать строке, включая разделители: "%d/%m/%Y" не разберёт "07-08-2026". Коды, которыми вы действительно будете пользоваться:

КодЗначениеПример
%YГод из 4 цифр2026
%yГод из 2 цифр26
%mНомер месяца08
%dДень месяца07
%bСокращённое название месяцаAug
%BПолное название месяцаAugust
%aСокращённый день неделиFri
%AПолный день неделиFriday
%HЧас (00-23)14
%MМинута30
%SСекунда05

Классическая засада — сама строка "07/08/2026": день/месяц/год в большей части мира, месяц/день/год в США, и R не может угадать, что имеет в виду ваш файл. Хуже того, неверная догадка часто «работает» — оба прочтения дают корректные даты, — пока не наступит 13-й день какого-нибудь месяца и не разберётся в NA (тринадцатого месяца не существует). Узнайте соглашение своих данных до того, как писать рецепт.

Форматирование дат для вывода

format() — зеркальное отражение as.Date(): те же коды с %, работающие в обратную сторону — на входе Date, на выходе строка.

Используйте это для заголовков отчётов, подписей и имён файлов — format(Sys.Date(), "%Y-%m-%d") даёт имена, сортирующиеся хронологически. Две детали стоит знать: %d дополняет нулём («August 07»), а %B/%A выдают названия на языке системных настроек — сессия, настроенная на немецкий, напечатает «Freitag» вместо «Friday». Держите форматирование на краях скрипта, для людей; внутри пусть даты остаются датами.

Арифметика дат и последовательности

Поскольку Date — это счётчик дней, арифметика работает так, как хотелось бы. Вычитание двух дат даёт объект difftime:

Три привычки из этого блока. Во-первых, оборачивайте difftime в as.numeric(), прежде чем считать с ним, — difftime несёт атрибут единиц, который может удивить в дальнейших вычислениях. Во-вторых, когда единицы важны, задавайте их через difftime(units = ), а не принимайте то, что выберет R. В-третьих, прибавление обычного числа означает прибавление дней — в базовом R нет + 1 месяц, потому что «один месяц» не является фиксированным числом дней.

Для календарно осведомлённого шага используйте seq(), которая понимает "day", "week", "month", "quarter" и "year":

Месячные последовательности — стандартный инструмент для отчётных периодов и делений оси. Одна причуда: начните месячную последовательность 31-го числа, и R продолжит отсчитывать реальные дни сквозь месяцы, где такого числа нет, поэтому «февральская» запись окажется в начале марта. Привязывайте месячные последовательности к 1-му числу и выводите всё остальное отсюда.

Извлечение частей даты

В базовом R есть два удобных экстрактора и одна общая идиома. weekdays() и months() возвращают названия; для чисел делайте круг через format():

Приём «format(), а затем as.integer()» выглядит окольным, но это стандартная идиома базового R, и она векторизована: передайте ей целый столбец дат — и получите обратно целый столбец годов. Это ровно то, что нужно после импорта датированного набора из CSV-файла: один раз разобрать столбец дат через as.Date(), а затем вывести столбцы года и месяца для группировки.

Когда дней мало: POSIXct и lubridate

У Date нет понятия часов. В момент, когда в ваших данных появляются отметки времени — записи журнала, показания датчиков, «заказ размещён в 14:32», — вам нужен POSIXct, класс даты-времени в R: секунды с 1970 года вместо дней и учёт часового пояса.

Переносится всё: те же коды с % (теперь включая %H, %M, %S) работают при разборе и в format(), вычитание даёт difftime, Sys.time() — это «сейчас». Новое бремя — часовой пояс: при разборе передавайте tz = явно, иначе две сессии в разных поясах прочитают одну и ту же строку как два разных момента. И не поддавайтесь искушению хранить календарные данные как POSIXct «на всякий случай»: день рождения, сохранённый как полночь в каком-то поясе, может напечататься предыдущим днём в другом поясе — по-настоящему мучительный для отслеживания баг. Целые дни — Date. Моменты — POSIXct.

Наконец, пакет lubridate — более дружелюбное лицо, которое большая часть кода tidyverse надевает на всё вышеописанное; его стоит взять на вооружение, когда базовая механика стала понятной:

library(lubridate)

ymd("2026-08-07")            # order-based parsing: no format string
mdy("08/07/2026")            # ...you just say which order the parts come in
dmy("7 August 2026")
floor_date(Sys.Date(), "month")   # snap to the start of the period

ymd(), mdy() и dmy() заменяют форматные рецепты простым указанием порядка частей, а floor_date() решает задачу «сгруппировать эти отметки времени по месяцам» одним вызовом. lubridate едет на тех же классах Date/POSIXct под капотом — это лучший руль, а не другой двигатель.

Что вы уносите с собой

  • Date — это счёт дней с 1970-01-01, наряженный печататься как дата; unclass() показывает число.
  • as.Date("2026-08-07") разбирает ISO напрямую; всему остальному нужен рецепт format = из кодов с % — а неудачный разбор молча возвращает NA.
  • format(date, "...") работает в обратную сторону: те же коды, на выходе строки для отображения.
  • Вычитание даёт difftime — задавайте units = явно и применяйте as.numeric() перед вычислениями. + n прибавляет дни; для месяцев используйте seq(by = "month").
  • weekdays(), months() и идиома as.integer(format(...)) вытаскивают части, векторизованно.
  • Date — для целых дней, POSIXct (с явным tz) — для отметок времени; lubridate делает оба дружелюбнее.

Дальше: что делать, когда R на вас кричит, — как читать сообщения об ошибках и методично их отлаживать.

Часто задаваемые вопросы

Как преобразовать строку в дату в R?

С помощью as.Date(). Если строка в формате ISO, это просто работает: as.Date("2026-08-07"). Любая другая раскладка требует рецепта format =, собранного из кодов с %: as.Date("07/08/2026", format = "%d/%m/%Y"). Неудачный разбор возвращает NA, а не ошибку, поэтому проверяйте результат.

Как получить сегодняшнюю дату в R?

Sys.Date() возвращает сегодняшний день объектом Date; Sys.time() возвращает текущие дату и время как POSIXct. Обе берут данные из часов и настроек часового пояса вашего компьютера.

Как вычислить разницу между двумя датами в R?

Вычтите их: as.Date("2026-08-07") - as.Date("2026-01-01") даёт difftime в 218 дней. Оберните в as.numeric(), чтобы использовать число в вычислениях, или вызовите difftime(d1, d2, units = "weeks"), чтобы выбрать единицы самому, а не оставлять это на усмотрение R.

В чём разница между Date и POSIXct в R?

Date хранит целые дни (внутри — дни с 1970-01-01) и ничего не знает о часах и часовых поясах. POSIXct хранит момент времени (секунды с 1970 года) и учитывает часовой пояс. Используйте Date для календарных данных вроде дней рождения и дедлайнов; используйте POSIXct только когда важно время суток, например для отметок времени и журналов.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ