datetime: округление / усечение числа цифр в микросекундах

В настоящее время я регистрирую материал, и я использую свой собственный форматер с пользовательскимformatTime():

def formatTime(self, _record, _datefmt):
    t = datetime.datetime.now()
    return t.strftime('%Y-%m-%d %H:%M:%S.%f')

Моя проблема в том, что микросекунды,%f, шесть цифр. Есть ли способ выпустить меньше цифр, как первые три цифры микросекунд?

Ответы на вопрос(7)

import re

# Capture 6 digits after dot in a group.
regexp = re.compile(r'\.(\d{6})')
def to_splunk_iso(dt):
    """Converts the datetime object to Splunk isoformat string."""
    # 6-digits string.
    microseconds = regexp.search(dt.isoformat()).group(1)
    return regexp.sub('.%d' % round(float(microseconds) / 1000), dt.isoformat())

Как отмечалось в комментариях ниже, округление этого решения (и приведенного выше) создает проблемы, когда значение микросекунды достигает 999500, а 999,5 округляется до 1000 (переполнение).

За исключением переопределения strftime для поддержки нужного нам формата (потенциальное переполнение, вызванное округлением, должно быть распространено до секунд, затем минут и т. Д.), Гораздо проще просто усечь первые 3 цифры, как указано в принятый ответ, или используя что-то вроде:

'{:03}'.format(int(999999/1000))

- Оригинальный ответ сохранен ниже -

В моем случае я пытался отформатировать метку даты с миллисекундами, отформатированными как «ddd». Решение, которое я использовал для получения миллисекунд, заключалось в использованииmicrosecond атрибутdatetime объект, разделите его на 1000.0, дополните его нулями, если необходимо, и округлите его с форматом. Это выглядит так:

'{:03.0f}'.format(datetime.now().microsecond / 1000.0)
# Produces: '033', '499', etc.
 08 мар. 2017 г., 13:13
микросекунда равна 0 & lt; = микросекунды & lt; 1000000. Так что ровно за миллион он будет производить "1000". Это именно то, что случилось со мнойdevrant.io/rants/466105
 13 апр. 2017 г., 19:29
@alkuzad: Как вы упоминаете, это не может быть ровно миллион, ноformat округляет его до 1000, когда микросекунда составляет не менее 999500. Вместо округления вы можете добавить 500 микросекунд к дате и усечению, чтобы получить тот же эффект, при этом автоматически обрабатывая округление до минут, часов, дней, месяцы или годы. Или просто обрежьте, если время в полсекунде не имеет большого значения для вас:'{:03}'.format(datetime.now().microsecond // 1000)

Pablojim Комментарии:

from datetime import datetime

dt = datetime.now()

dt_round_microsec = round(dt.microsecond/1000) #number of zeroes to round   
dt = dt.replace(microsecond=dt_round_microsec)
 06 апр. 2018 г., 11:33
это не удается для 59,5-> 59,999 '. секунд, поскольку он пытается установить поле секунд на 60.
 14 апр. 2018 г., 04:59
@Pablojim исправил и удалил log10 как функцию, это вообще не нужно. это действительно округляло все до секунд. Спасибо

def format_time():
    t = datetime.datetime.now()
    if t.microsecond % 1000 >= 500:  # check if there will be rounding up
        t = t + datetime.timedelta(milliseconds=1)  # manually round up
    return t.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]

Обычно сначала выполняется ручное округление самого объекта даты, а затем вы можете безопасно обрезать микросекунды.

Решение Вопроса

чтобы просто отрубить последние три цифры микросекунд:

def format_time():
    t = datetime.datetime.now()
    s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
    return s[:-3]

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

def format_time():
    t = datetime.datetime.now()
    s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
    tail = s[-7:]
    f = round(float(tail), 3)
    temp = "%.3f" % f
    return "%s%s" % (s[:-7], temp[1:])
 20 мая 2016 г., 22:23
Это не работает. Когда значение микросекунды оказывается равным нулю, значение секунд усекается, например: «2007-12-24T11: 32».
 13 апр. 2017 г., 19:23
Когда микросекунды не меньше 999500, это усекается вместо округления в большую сторону. Вы можете исправить это после определенияf: if f >= 1.0: return (t + datetime.timedelta(milliseconds=1)).strftime('%Y-%m-%d %H:%M:%S.000') (и в противном случае продолжайте как прежде).
 15 апр. 2015 г., 05:41
Я проверил ваш код в Python 2.7.6 и Python 3.4.0. Скопировал и вставил ваш код, каждый раз один и тот же результат. У вас есть 3 цифры в вашей секундной области. Я смотрю на код, и кажется, что вы плаваете (f переменная) привязывается к ведущему 0 перед десятичной дробью (например:0.367), который добавляется в виде строки. Это ведущий 0 в области секунд, где он начинает терпеть неудачу.
 13 апр. 2015 г., 02:12
Ваш метод округления не работает для меня, он дает такой результат:'2015-04-12 17:09:020.588'секунды недействительны.
 15 апр. 2015 г., 17:57
@ NuclearPeon Я прошу прощения. Вы обнаружили реальную ошибку, которая доказывает, что я на самом деле не проверял это перед публикацией. Я отредактировал код, чтобы исправить ошибку, и теперь он должен работать для вас. Спасибо, что обратили на это мое внимание.

которая выглядит точно так же (с или без часового пояса в зависимости от того, является ли входdt объект содержит один):

2016-08-05T18:18:54.776+0000

Требуетсяdatetime объект в качестве ввода (который вы можете производить сdatetime.datetime.now()). Чтобы получить часовой пояс, как в примере с моим примером, вам нужноimport pytz и передатьdatetime.datetime.now(pytz.utc).

import pytz, datetime


time_format(datetime.datetime.now(pytz.utc))

def time_format(dt):
    return "%s:%.3f%s" % (
        dt.strftime('%Y-%m-%dT%H:%M'),
        float("%.3f" % (dt.second + dt.microsecond / 1e6)),
        dt.strftime('%z')
    )   

Я заметил, что некоторые другие методы выше опускали бы конечный ноль, если он был (например,0.870 стал0.87) и это вызывало проблемы у анализатора, которому я кормил эти метки времени. Этот метод не имеет этой проблемы.

секундное значение, если вы укажете слишком большую точность.

def formatTime(self, _record, _datefmt, precision=3):
    dt = datetime.datetime.now()
    us = str(dt.microsecond)
    f = us[:precision] if len(us) > precision else us
    return "%d-%d-%d %d:%d:%d.%d" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, int(f))

Этот метод реализует округление до 3 десятичных знаков:

import datetime
from decimal import *

def formatTime(self, _record, _datefmt, precision='0.001'):
    dt = datetime.datetime.now()
    seconds = float("%d.%d" % (dt.second, dt.microsecond))
    return "%d-%d-%d %d:%d:%s" % (dt.year, dt.month, dt.day, dt.hour, dt.minute,
                             float(Decimal(seconds).quantize(Decimal(precision), rounding=ROUND_HALF_UP)))

Я избегал использованияstrftime метод нарочно, потому чтоI would prefer not to modify a fully serialized datetime object без повторной проверки. Этот способ также показывает внутреннюю дату, если вы хотите изменить ее дальше.

В примере округления обратите внимание, что точность основана на строках дляDecimal модуль.

Ваш ответ на вопрос