Come troncare l'ora su un oggetto DateTime in Python?


251

Qual è un modo di classe per troncare un oggetto datetime python?

In questo caso particolare, fino al giorno. Quindi sostanzialmente impostando ora, minuti, secondi e microsecondi su 0.

Vorrei che l'output fosse anche un oggetto datetime, non una stringa.

Risposte:


376

Penso che sia quello che stai cercando ...

>>> import datetime
>>> dt = datetime.datetime.now()
>>> dt = dt.replace(hour=0, minute=0, second=0, microsecond=0) # Returns a copy
>>> dt
datetime.datetime(2011, 3, 29, 0, 0)

Ma se davvero non ti interessa l'aspetto temporale delle cose, allora dovresti davvero solo passare intorno agli dateoggetti ...

>>> d_truncated = datetime.date(dt.year, dt.month, dt.day)
>>> d_truncated
datetime.date(2011, 3, 29)

14
Con un dt consapevole del fuso orario, datetime.datetime (dt.year, dt.month, dt.day) elimina le informazioni di tzinfo.
ʇsәɹoɈ

1
se stai cercando proprio oggi, puoi anche fare datetime.date.today ()
galarant

4
Si noti che entrambi i documenti python 2 e python 3 affermano che il replace()metodo restituisce un oggetto datetime, quindi l'incantesimo corretto sarebbe:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
Brad M

3
OP vuole datetime, non dateoggetto (che potresti ottenere usando dt.date()call (non c'è bisogno di usare il costruttore esplicito)). Il .replace()metodo potrebbe non riuscire se si datetimeaggiunge il supporto di nanosecondi . Invece potresti usaredatetime.combine() .
jfs,

@chrisw Perché non scriverlo in una riga datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)?
3kstc,

66

Usa un datenon a datetimese non ti interessa l'ora.

>>> now = datetime.now()
>>> now.date()
datetime.date(2011, 3, 29)

Puoi aggiornare un datetime come questo:

>>> now.replace(minute=0, hour=0, second=0, microsecond=0)
datetime.datetime(2011, 3, 29, 0, 0)

9
Con i periodi di tempo sensibili al fuso orario, now.date () elimina le informazioni di tzinfo.
ʇsәɹoɈ

1
@ ʇsәɹoɈ: ecco come è possibile ottenere la mezzanotte sensibile al fuso orario
jfs

34

Quattro anni dopo: un altro modo, evitando replace

So che la risposta accettata da quattro anni fa funziona, ma questo sembra un po 'più leggero dell'uso replace:

dt = datetime.date.today()
dt = datetime.datetime(dt.year, dt.month, dt.day)

Appunti

  • Quando si crea un datetimeoggetto senza passare le proprietà del tempo al costruttore, si ottiene la mezzanotte.
  • Come altri hanno già notato, ciò presuppone che si desideri un oggetto datetime per un uso successivo con timedeltas.
  • Puoi ovviamente sostituirlo con la prima riga: dt = datetime.datetime.now()

20

Non è possibile troncare un oggetto datetime perché è immutabile .

Tuttavia, ecco un modo per costruire un nuovo datetime con i campi 0 ora, minuti, secondi e microsecondi, senza eliminare la data originale o tzinfo:

newdatetime = now.replace(hour=0, minute=0, second=0, microsecond=0)

1
+1: se metti replaceprima l' opzione, poiché è probabilmente quello che vogliono.
S.Lott

Non è corretto da usare tzinfo=now.tzinfo. La tzinfomezzanotte può essere diversa, ad esempio, l'offset utc alle 2012-04-01 00:09:00(9) nel fuso orario Australia / Melbourne è, AEST+10:00ma è AEDT+11:00alle 2012-04-01 00:00:00(mezzanotte) - in quel giorno c'è una transizione di fine ora legale. Potresti usare il pytzmodulo per risolverlo, vedi la mia risposta.
jfs,

13

Per ottenere una mezzanotte corrispondente a un determinato oggetto datetime, è possibile utilizzare il datetime.combine()metodo :

>>> from datetime import datetime, time
>>> dt = datetime.utcnow()
>>> dt.date()
datetime.date(2015, 2, 3)
>>> datetime.combine(dt, time.min)
datetime.datetime(2015, 2, 3, 0, 0)

Il vantaggio rispetto al il .replace()metodo è che datetime.combine()la soluzione basata su continuerà a funzionare anche se datetimeintroduce modulo i nanosecondi supportano .

tzinfopuò essere conservato se necessario ma l'offset utc può essere diverso a mezzanotte, ad es. a causa di una transizione DST e quindi una soluzione ingenua (impostazione tzinfodell'attributo del tempo) potrebbe non riuscire. Vedi Come posso ottenere l'ora UTC di "mezzanotte" per un determinato fuso orario?


7

Potresti usare i panda per questo (anche se potrebbe essere un sovraccarico per quell'attività). Puoi usare round , floor e ceil come per i soliti numeri e qualsiasi frequenza di panda dagli alias offset :

import pandas as pd
import datetime as dt

now = dt.datetime.now()
pd_now = pd.Timestamp(now)

freq = '1d'
pd_round = pd_now.round(freq)
dt_round = pd_round.to_pydatetime()

print(now)
print(dt_round)

"""
2018-06-15 09:33:44.102292
2018-06-15 00:00:00
"""

4

Puoi usare datetime.strftime per estrarre il giorno, il mese, l'anno ...

Esempio :

from datetime import datetime
d = datetime.today()

# Retrieves the day and the year
print d.strftime("%d-%Y")

Uscita (per oggi):

29-2011

Se vuoi solo recuperare il giorno, puoi usare l'attributo day come:

from datetime import datetime
d = datetime.today()

# Retrieves the day
print d.day

Ouput (per oggi):

29

Bene, il fatto è che lo faccio già una volta, quindi ciò potrebbe avere un overhead maggiore rispetto all'impostazione dei campi ora min ecc nell'oggetto datetime.
Kyle Brandt,

Heh, questo è un modo strano di farlo, in realtà puoi semplicemente farlo d.dayecc.
Jochen Ritzel,

3

C'è una grande biblioteca usata per manipolare le date: Delorean

import datetime
from delorean import Delorean
now = datetime.datetime.now()
d = Delorean(now, timezone='US/Pacific')

>>> now    
datetime.datetime(2015, 3, 26, 19, 46, 40, 525703)

>>> d.truncate('second')
Delorean(datetime=2015-03-26 19:46:40-07:00, timezone='US/Pacific')

>>> d.truncate('minute')
Delorean(datetime=2015-03-26 19:46:00-07:00, timezone='US/Pacific')

>>> d.truncate('hour')
Delorean(datetime=2015-03-26 19:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('day')
Delorean(datetime=2015-03-26 00:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('month')
Delorean(datetime=2015-03-01 00:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('year')
Delorean(datetime=2015-01-01 00:00:00-07:00, timezone='US/Pacific')

e se si desidera ripristinare il valore datetime:

>>> d.truncate('year').datetime
datetime.datetime(2015, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)

restituisce il tempo sbagliato (offset utc errato) se il tempo del risultato ha un offset utc diverso, ad es. a causa di una transizione DST. Vedi Come posso ottenere l'ora UTC di "mezzanotte" per un determinato fuso orario?
jfs,


1

C'è un modulo datetime_truncate che lo gestisce per te. Chiama semplicemente datetime.replace.


1

6 anni dopo ... Ho trovato questo post e mi è piaciuto di più l'approccio insensibile:

import numpy as np
dates_array = np.array(['2013-01-01', '2013-01-15', '2013-01-30']).astype('datetime64[ns]')
truncated_dates = dates_array.astype('datetime64[D]')

Saluti


1
>>> import datetime
>>> dt = datetime.datetime.now()
>>> datetime.datetime.date(dt)
datetime.date(2019, 4, 2)

1

Puoi solo usare

datetime.date.today()

È leggero e restituisce esattamente quello che vuoi.


La stessa risposta è stata data prima, non c'è nulla di nuovo.
slfan

Spiacente @slfan ma non ho visto nessun post con il tuo nome, anche usando "cerca" dal browser.
Bordotti,

1
Non da me, da zx81 3 anni fa. cerca datetime.date.today (). Se una risposta è corretta, dovresti votare, non rispondere di nuovo.
slfan,


0

Se hai a che fare con una serie di tipo DateTime c'è un modo più efficiente per troncarli, specialmente quando l'oggetto Serie ha molte righe.

È possibile utilizzare la funzione piano

Ad esempio, se si desidera troncarlo a ore:

Genera un intervallo di date

times = pd.Series(pd.date_range(start='1/1/2018 04:00:00', end='1/1/2018 22:00:00', freq='s'))

Possiamo verificarlo confrontando il tempo di funzionamento tra le funzioni di sostituzione e piano.

%timeit times.apply(lambda x : x.replace(minute=0, second=0, microsecond=0))
>>> 341 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit times.dt.floor('h')
>>>>2.26 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

0

Ecco un altro modo che si adatta in una riga ma non è particolarmente elegante:

dt = datetime.datetime.fromordinal(datetime.date.today().toordinal())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.