Spec-Zone.ru › NumPy 2.0

Типы данных datetime и timedelta

Введено в версии 1.7.0.

Начиная с NumPy 1.7, существуют основные массивно-ориентированные типы данных, которые изначально поддерживают функциональность datetime. Тип данных называется datetime64, так как datetime уже используется стандартной библиотекой Python.

Конвенции и предположения для datetime64

Подобно классу Python date, даты выражаются в современном григорианском календаре, бесконечно продолжающемся как в будущее, так и в прошлое. [1] В отличие от Python date, который поддерживает только годы в диапазоне с 1 по 9999 год нашей эры, datetime64 также допускает даты до нашей эры; года до нашей эры следуют конвенции астрономической нумерации, т.е. год 2 до нашей эры обозначается как −1, год 1 до нашей эры — как 0, год 1 нашей эры — как 1.

Мгновения времени, скажем, 16:23:32.234, представляются как количество часов, минут, секунд и долей секунды от полуночи: т.е. 00:00:00.000 — полуночь, 12:00:00.000 — полдень и т.д. Каждый календарный день длится ровно 86400 секунд. Это «простое» время без явного представления о часовых поясах или конкретных временных шкалах (UT1, UTC, TAI и т.д.). [2]

[1]

Календарь, полученный путем продолжения григорианского календаря до его официального принятия 15 октября 1582 года, называется Пролептическим григорианским календарем

[2]

Предположение о 86400 секундах в календарный день неверно для UTC, современной гражданской временной шкалы. Фактически, из-за наличия дополнительных секунд, в редких случаях день может длиться 86401 или 86399 секунд. Напротив, предположение о 86400 секундах в день справедливо для шкалы TAI. Предлагается явная поддержка TAI и преобразования TAI в UTC, учитывающая дополнительные секунды, но пока не реализована. См. также раздел «Недостатки» ниже.

Основные типы данных datetime

Самый простой способ создания datetime — из строк в формате даты или времени ISO 8601. Также возможно создание datetime из целого числа, сдвинутого относительно эпохи Unix (00:00:00 UTC 1 января 1970 г.). Единица для внутреннего хранения автоматически выбирается из формы строки и может быть либо единицей даты, либо единицей времени. Единицы дат — годы (‘Y’), месяцы (‘M’), недели (‘W’) и дни (‘D’), а единицы времени — часы (‘h’), минуты (‘m’), секунды (‘s’), миллисекунды (‘ms’) и некоторые дополнительные единицы времени, основанные на секундах с использованием префиксов СИ. Тип данных datetime64 также принимает строку “NAT” (в любой комбинации прописных и строчных букв) для значения «Нет времени».

Пример

Простая дата в формате ISO:

>>> np.datetime64('2005-02-25')
np.datetime64('2005-02-25')

Из целого числа и единицы даты, 1 год от эпохи Unix:

>>> np.datetime64(1, 'Y')
np.datetime64('1971')

Использование месяцев в качестве единицы:

>>> np.datetime64('2005-02')
np.datetime64('2005-02')

Указание только месяца, но принудительно используя единицу «дни»:

>>> np.datetime64('2005-02', 'D')
np.datetime64('2005-02-01')

Из даты и времени:

>>> np.datetime64('2005-02-25T03:30')
np.datetime64('2005-02-25T03:30')

NAT (нет времени):

>>> np.datetime64('nat')
np.datetime64('NaT')

При создании массива datetime из строки можно по-прежнему автоматически выбирать единицу из входных данных, используя тип datetime с общими единицами.

Пример

>>> np.array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64')
array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64[D]')
>>> np.array(['2001-01-01T12:00', '2002-02-03T13:56:03.172'], dtype='datetime64')
array(['2001-01-01T12:00:00.000', '2002-02-03T13:56:03.172'],
      dtype='datetime64[ms]')

Массив datetime можно создать из целых чисел, представляющих метки времени POSIX с заданной единицей.

Пример

>>> np.array([0, 1577836800], dtype='datetime64[s]')
array(['1970-01-01T00:00:00', '2020-01-01T00:00:00'],
      dtype='datetime64[s]')
>>> np.array([0, 1577836800000]).astype('datetime64[ms]')
array(['1970-01-01T00:00:00.000', '2020-01-01T00:00:00.000'],
      dtype='datetime64[ms]')

Тип datetime работает со многими стандартными функциями NumPy, например, arange можно использовать для генерации диапазонов дат.

Пример

Все даты за один месяц:

>>> np.arange('2005-02', '2005-03', dtype='datetime64[D]')
array(['2005-02-01', '2005-02-02', '2005-02-03', '2005-02-04',
       '2005-02-05', '2005-02-06', '2005-02-07', '2005-02-08',
       '2005-02-09', '2005-02-10', '2005-02-11', '2005-02-12',
       '2005-02-13', '2005-02-14', '2005-02-15', '2005-02-16',
       '2005-02-17', '2005-02-18', '2005-02-19', '2005-02-20',
       '2005-02-21', '2005-02-22', '2005-02-23', '2005-02-24',
       '2005-02-25', '2005-02-26', '2005-02-27', '2005-02-28'],
      dtype='datetime64[D]')

Объект datetime представляет собой единственный момент во времени. Если два datetime имеют разные единицы, они могут представлять один и тот же момент времени, и преобразование из большей единицы, такой как месяцы, в меньшую, такую как дни, считается «безопасным» преобразованием, поскольку момент времени по-прежнему представлен точно.

Пример

>>> np.datetime64('2005') == np.datetime64('2005-01-01')
True
>>> np.datetime64('2010-03-14T15') == np.datetime64('2010-03-14T15:00:00.00')
True

Устарело начиная с версии 1.11.0: NumPy не хранит информацию о часовом поясе. Для обеспечения обратной совместимости datetime64 по-прежнему анализирует смещения часовых поясов, которые обрабатываются путем преобразования в UTC±00:00 (время по Гринвичу). Это поведение устарело и в будущем будет вызывать ошибку.

Арифметика datetime и timedelta

NumPy позволяет вычитать два значения datetime, операция, которая производит число с единицей времени. Поскольку в NumPy нет системы физических величин в ядре, был создан тип данных timedelta64 для дополнения datetime64. Аргументы для timedelta64 — это число, представляющее количество единиц, и единица даты/времени, например (D)ень, (M)есяц, (Y)год, (h)асы, (m)инуты или (s)екунды. Тип данных timedelta64 также принимает строку “NAT” вместо числа для значения «Нет времени».

Пример

>>> np.timedelta64(1, 'D')
np.timedelta64(1,'D')
>>> np.timedelta64(4, 'h')
np.timedelta64(4,'h')
>>> np.timedelta64('nAt')
np.timedelta64('NaT')

Datetime и Timedelta работают вместе, чтобы обеспечить способы выполнения простых расчетов с датой и временем.

Пример

>>> np.datetime64('2009-01-01') - np.datetime64('2008-01-01')
np.timedelta64(366,'D')
>>> np.datetime64('2009') + np.timedelta64(20, 'D')
np.datetime64('2009-01-21')
>>> np.datetime64('2011-06-15T00:00') + np.timedelta64(12, 'h')
np.datetime64('2011-06-15T12:00')
>>> np.timedelta64(1,'W') / np.timedelta64(1,'D')
7.0
>>> np.timedelta64(1,'W') % np.timedelta64(10,'D')
np.timedelta64(7,'D')
>>> np.datetime64('nat') - np.datetime64('2009-01-01')
np.timedelta64('NaT','D')
>>> np.datetime64('2009-01-01') + np.timedelta64('nat')
np.datetime64('NaT')

Существуют две единицы Timedelta (‘Y’, годы и ‘M’, месяцы), которые обрабатываются особым образом, так как количество времени, которое они представляют, изменяется в зависимости от того, где они используются. В то время как единица timedelta «день» эквивалентна 24 часам, нет способа преобразовать единицу «месяц» в дни, потому что разные месяцы имеют разное количество дней.

Пример

>>> a = np.timedelta64(1, 'Y')
>>> np.timedelta64(a, 'M')
numpy.timedelta64(12,'M')
>>> np.timedelta64(a, 'D')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cannot cast NumPy timedelta64 scalar from metadata [Y] to [D] according to the rule 'same_kind'

Единицы datetime

Типы данных Datetime и Timedelta поддерживают большое количество единиц времени, а также общие единицы, которые могут быть преобразованы в любые другие единицы на основе входных данных.

Datetime всегда хранятся с эпохой 1970-01-01T00:00. Это означает, что поддерживаемые даты всегда представляют собой симметричный интервал вокруг эпохи, который в таблице ниже называется «временной интервал».

Длина интервала — это диапазон 64-битного целого числа умноженный на длину даты или единицы. Например, временной интервал для ‘W’ (недели) ровно в 7 раз больше, чем временной интервал для ‘D’ (дней), а временной интервал для ‘D’ (дней) ровно в 24 раза больше, чем временной интервал для ‘h’ (часов).

Вот единицы дат:

Код

Значение

Временной интервал (относительно)

Временной интервал (абсолютно)

Y

год

+/- 9,2e18 лет

[9,2e18 до н.э., 9,2e18 н.э.]

M

месяц

+/- 7,6e17 лет

[7,6e17 до н.э., 7,6e17 н.э.]

W

неделя

+/- 1,7e17 лет

[1,7e17 до н.э., 1,7e17 н.э.]

D

день

+/- 2,5e16 лет

[2,5e16 до н.э., 2,5e16 н.э.]

А вот единицы времени:

Код

Значение

Временной интервал (относительно)

Временной интервал (абсолютно)

h

час

+/- 1,0e15 лет

[1,0e15 до н.э., 1,0e15 н.э.]

m

минута

+/- 1,7e13 лет

[1,7e13 до н.э., 1,7e13 н.э.]

s

секунда

+/- 2,9e11 лет

[2,9e11 до н.э., 2,9e11 н.э.]

ms

миллисекунда

+/- 2,9e8 лет

[2,9e8 до н.э., 2,9e8 н.э.]

us / мкс

микросекунда

+/- 2,9e5 лет

[290301 до н.э., 294241 н.э.]

ns

наносекунда

+/- 292 года

[1678 н.э., 2262 н.э.]

ps

пикосекунда

+/- 106 дней

[1969 н.э., 1970 н.э.]

fs

фемтосекунда

+/- 2,6 часа

[1969 н.э., 1970 н.э.]

as

аттосекунда

+/- 9,2 секунды

[1969 н.э., 1970 н.э.]

Функциональность рабочих дней

Для использования datetime в контекстах, где допустимы только определённые дни недели, NumPy включает набор функций «рабочих дней» (busday).

По умолчанию функции busday учитывают только понедельник по пятницу (обычные рабочие дни). Реализация основана на «weekmask», содержащем 7 логических флагов, указывающих допустимые дни; возможны настраиваемые weekmask, которые задают другие наборы допустимых дней.

Функции «busday» дополнительно могут проверять список дат «выходных», конкретных дат, которые не являются рабочими днями.

Функция busday_offset позволяет применять сдвиги, заданные в рабочих днях, к datetime с единицей ‘D’ (день).

Пример

>>> np.busday_offset('2011-06-23', 1)
np.datetime64('2011-06-24')
>>> np.busday_offset('2011-06-23', 2)
np.datetime64('2011-06-27')

Когда входная дата попадает на выходные или праздничный день, busday_offset сначала применяет правило для переноса даты на ближайший рабочий день, а затем применяет сдвиг. Правило по умолчанию — ‘raise’, которое просто генерирует исключение. Наиболее часто используемые правила — ‘forward’ и ‘backward’.

Пример

>>> np.busday_offset('2011-06-25', 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Non-business day date in busday_offset
>>> np.busday_offset('2011-06-25', 0, roll='forward')
np.datetime64('2011-06-27')
>>> np.busday_offset('2011-06-25', 2, roll='forward')
np.datetime64('2011-06-29')
>>> np.busday_offset('2011-06-25', 0, roll='backward')
np.datetime64('2011-06-24')
>>> np.busday_offset('2011-06-25', 2, roll='backward')
np.datetime64('2011-06-28')

В некоторых случаях для получения желаемого результата необходимо соответствующее использование правила переноса и сдвига.

Пример

Первый рабочий день на или после даты:

>>> np.busday_offset('2011-03-20', 0, roll='forward')
np.datetime64('2011-03-21')
>>> np.busday_offset('2011-03-22', 0, roll='forward')
np.datetime64('2011-03-22')

Первый рабочий день строго после даты:

>>> np.busday_offset('2011-03-20', 1, roll='backward')
np.datetime64('2011-03-21')
>>> np.busday_offset('2011-03-22', 1, roll='backward')
np.datetime64('2011-03-23')

Функция также полезна для вычисления некоторых типов дней, таких как праздники. В Канаде и США День матери приходится на второе воскресенье мая, что можно вычислить с помощью настраиваемого weekmask.

Пример

>>> np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun')
np.datetime64('2012-05-13')

Когда производительность важна для обработки многих дат рабочих дней с конкретным выбором weekmask и праздников, существует объект busdaycalendar, который хранит необходимые данные в оптимизированной форме.

np.is_busday():

Для проверки значения datetime64 на то, является ли это допустимым днём, используйте is_busday.

Пример

>>> np.is_busday(np.datetime64('2011-07-15'))  # a Friday
True
>>> np.is_busday(np.datetime64('2011-07-16')) # a Saturday
False
>>> np.is_busday(np.datetime64('2011-07-16'), weekmask="Sat Sun")
True
>>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
>>> np.is_busday(a)
array([ True,  True,  True,  True,  True, False, False])

np.busday_count():

Чтобы определить количество рабочих дней в заданном диапазоне дат datetime64, используйте busday_count:

Пример

>>> np.busday_count(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
5
>>> np.busday_count(np.datetime64('2011-07-18'), np.datetime64('2011-07-11'))
-5

Если у вас есть массив значений datetime64, и вы хотите подсчитать количество допустимых дат, вы можете сделать это:

Пример

>>> a = np.arange(np.datetime64('2011-07-11'), np.datetime64('2011-07-18'))
>>> np.count_nonzero(np.is_busday(a))
5

Настраиваемые weekmask

Ниже приведены несколько примеров значений custom weekmask. Эти примеры указывают на «busday» по умолчанию — понедельник по пятницу как допустимые дни.

Некоторые примеры:

# Positional sequences; positions are Monday through Sunday.
# Length of the sequence must be exactly 7.
weekmask = [1, 1, 1, 1, 1, 0, 0]
# list or other sequence; 0 == invalid day, 1 == valid day
weekmask = "1111100"
# string '0' == invalid day, '1' == valid day

# string abbreviations from this list: Mon Tue Wed Thu Fri Sat Sun
weekmask = "Mon Tue Wed Thu Fri"
# any amount of whitespace is allowed; abbreviations are case-sensitive.
weekmask = "MonTue Wed  Thu\tFri"

Недостатки типа datetime64

Предположение о том, что все дни имеют длительность ровно 86400 секунд, делает datetime64 в значительной степени совместимым с Python datetime и семантикой «POSIX time»; поэтому все они обладают одними и теми же хорошо известными недостатками по отношению к шкале времени UTC и определению исторического времени. Краткое, неполное резюме приведено ниже.

  • Невозможно разобрать допустимые метки времени UTC, возникающие во время положительной секунды високосного года.

    Пример

    «2016-12-31 23:59:60 UTC» был високосной секундой, поэтому «2016-12-31 23:59:60.450 UTC» — это допустимое значение временной метки, которое не может быть разобрано datetime64:

    >>> np.datetime64("2016-12-31 23:59:60.450")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: Seconds out of range in datetime string "2016-12-31 23:59:60.450"
    
  • Вычисления Timedelta64 между двумя датами UTC могут быть неверными на целое число SI секунд.

    Пример

    Вычислите количество SI секунд между «2021-01-01 12:56:23.423 UTC» и «2001-01-01 00:00:00.000 UTC»:

    >>> (
    ...   np.datetime64("2021-01-01 12:56:23.423")
    ...   - np.datetime64("2001-01-01")
    ... ) / np.timedelta64(1, "s")
    631198583.423
    

    однако правильный ответ — 631198588.423 SI секунд, потому что между 2001 и 2021 годами было 5 високосных секунд.

  • Вычисления Timedelta64 для дат в прошлом не возвращают SI секунд, как можно ожидать.

    Пример

    Вычислите количество секунд между «000-01-01 UT» и «1600-01-01 UT», где UT — универсальное время:

    >>> a = np.datetime64("0000-01-01", "us")
    >>> b = np.datetime64("1600-01-01", "us")
    >>> b - a
    numpy.timedelta64(50491123200000000,'us')
    

    Полученные результаты, 50491123200 секунд, получаются как количество прошедших дней (584388) умноженное на 86400 секунд; это количество секунд часов, синхронизированных с вращением Земли. Точное значение в SI секундах можно только оценить, например, используя данные, опубликованные в Measurement of the Earth’s rotation: 720 BC to AD 2015, 2016, Royal Society’s Proceedings A 472, by Stephenson et.al.. Разумная оценка составляет 50491112870 ± 90 секунд, с разницей в 10330 секунд.

© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/reference/arrays.datetime.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API