web-dev-qa-db-ja.com

datetime:マイクロ秒単位の桁数の丸め/トリム

現在、私はものをログに記録しており、カスタムformatTime()で独自のフォーマッタを使用しています:

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

私の問題は、マイクロ秒、%fは、6桁です。とにかく、マイクロ秒の最初の3桁のように、より少ない桁を吐き出す必要はありますか?

31
Parham

最も簡単な方法は、スライスを使用して、マイクロ秒の最後の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:])
42
steveha

このメソッドは、常に次のようなタイムスタンプを返す必要があります(入力dtオブジェクトにタイムゾーンが含まれているかどうかによって、タイムゾーンの有無は異なります)。

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

入力として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')
    )   
_

上記の他のメソッドのいくつかは、末尾のゼロが1つあれば省略されることに気づきました(例えば、_0.870_が_0.87_になり、これがこれらのタイムスタンプを供給しているパーサーに問題を引き起こしていました)。この方法にはその問題はありません。

3
Eric Herot

編集:以下のコメントで指摘されているように、999.5は1000(オーバーフロー)に丸められるため、このソリューション(および上記のソリューション)の丸めでは、マイクロ秒値が999500に達すると問題が発生します。

必要な形式をサポートするためにstrftimeを再実装するのではなく(丸めによって発生する可能性のあるオーバーフローを数秒、数分などに伝播する必要があります)、最初の3桁に切り捨てる方がはるかに簡単です受け入れられた答え、または次のようなものを使用して:

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

-以下に元の回答を保存-

私の場合、ミリ秒を「ddd」としてフォーマットした日付スタンプをフォーマットしようとしました。最終的にミリ秒を取得するために使用した解決策は、microsecondオブジェクトのdatetime属性を使用し、1000.0で除算し、必要に応じてゼロを埋め込み、フォーマットで丸めることでした。次のようになります。

'{:03.0f}'.format(datetime.now().microsecond / 1000.0)
# Produces: '033', '499', etc.
2
Apteryx

すべての場合に機能する簡単なソリューション:

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]

基本的に、最初に日付オブジェクト自体を手動で丸めてから、マイクロ秒を安全にトリミングできます。

1
Abdurrahman

正規表現を使用した私のソリューションは次のとおりです。

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())
1
iurii

この方法により、柔軟な精度が可能になり、あまりにも高い精度を指定すると、マイクロ秒値全体が消費されます。

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)))

完全にシリアル化されたdatetimeオブジェクトを変更したくない再検証せずに、strftimeメソッドを意図的に使用することを避けました。この方法では、さらに変更する場合に備えて、日付の内部も表示されます。

丸めの例では、Decimalモジュールの精度は文字列ベースであることに注意してください。

1
NuclearPeon

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)
0
gandreoti

結果とともに曜日(つまり、「日曜日」)を取得したい場合、「[:-3]」をスライスしても機能しません。そのとき、あなたは一緒に行くかもしれません、

dt = datetime.datetime.now()
print("{}.{:03d} {}".format(dt.strftime('%Y-%m-%d %I:%M:%S'), dt.microsecond//1000, dt.strftime("%A")))

#Output: '2019-05-05 03:11:22.211 Sunday'

%H-24時間形式の場合

%I-12時間形式の場合

おかげで、

0
Jai K