46

I am storing all my times in UTC and my system is set to UTC (though I am in EST).

I have dates stored as:

Wed, 20 Feb 2013 03:51:39 +0000

However, I would like to select information based off today for EST, so I am attempting to:

  • Get current time as UTC and change to EST

    datetime.utcnow().replace(tzinfo=tz.tzutc()).astimezone(tz.gettz('America/New_York'))
    2013-02-19 23:17:20.560898-05:00
    
  • Next I want to get the start time for the EST day (2013-02-19 00:00:00.000000-05:00) and the end time (2013-02-19 23:59:59.99999-05:00)

  • Once I have those values, I'd like to convert back to UTC, so I have a high and low value I can clamp by that's correct my EST (my timezone).

If this isn't the best way to do this, or I'm missing something (does seem overly complicated to me) please help me see the light!

TIA

Update per answer:

d1 = datetime.utcnow().replace(tzinfo=tz.tzutc()).astimezone(tz.gettz('America/New_York'))
print d1.strftime("%m %d %Y") ; d2 = d1.replace(day=d1.day + 1) ; print d2.strftime("%m %d %Y")

That will give me

02 20 2013
02 21 2013

Which is correct. I now need to generate the full EST time from that and then convert to UTC. This I cannot figure out. Actually, I probably want to convert to UTC epoch timestamp when complete because that will make my database operations pretty easy (<, >, ==, etc).

mr-sk
  • 13,174
  • 11
  • 66
  • 101
  • I don't understand what you are trying to do now. I thought you wanted the EST time for in this case 02/20/2013 00:00 UTC. All your code right now does is in a very complex way get todays (and tomorrows) date... – Lennart Regebro Feb 21 '13 at 07:44
  • (In EST, to boot, not UTC) – Lennart Regebro Feb 21 '13 at 07:57
  • Don't replace the day. That will break at the end of each month. Use timedelta, as per my answer. Also, stop trying to do everything in one line. You shouldn't use "most" of my answer, you should use *all* of it, as it is. Your code above is very hard to read. And finally, are you not using the *time*? You are only printing out the dates. If you don't want the time, most of this is completely pointless. Dates have no timezones, for starters. – Lennart Regebro Mar 08 '13 at 09:16
  • related: [Python: Given the current time in UTC, how do you determine the start and end time of the day in a particular timezone?](http://stackoverflow.com/a/25605133/4279) – jfs Jul 18 '15 at 20:07
  • Please be careful with editing 9 years old questions with highly upvoted 9 years old answers. "I now need to ..." is dangerously close to a so called moving target question. Maybe this is not the case here, but be careful and pleasea reconsider your phrasing... – Yunnosch Apr 24 '22 at 15:48

11 Answers11

62

The first step of getting current time as UTC and converting it to EST seems a bit pointless. Do you use that time for anything?

Other than that it seems rather straighforward. You want to get the start and end of a day EST in UTC, so you create them and convert them to UTC. That's not so complicated. :-)

You might want to look at your matching routines though, so that you can use the start of today as the lower value, and the start of tomorrow as the higher, so you don't have to deal with that 23:59:59.9999 time.

Update:

From my original understanding of your question, this is what you want to do:

First you want to get the current date as it is in UTC (so at 11pm EST the 12st, you want the 22nd, as it is the 22nd in UTC then.

>>> from datetime import datetime
>>> today = datetime.utcnow().date()
>>> today
datetime.date(2013, 2, 21)

Secondly you want 00:00:00 of that day in UTC, as start for a search.

>>> from dateutil import tz
>>> start = datetime(today.year, today.month, today.day, tzinfo=tz.tzutc())
datetime.datetime(2013, 2, 21, 0, 0, tzinfo=tzutc())

Except that you want to know what that time is in New York:

>>> from dateutil import tz
>>> est = tz.gettz('America/New_York')
>>> start = start.astimezone(est)
>>> start
datetime.datetime(2013, 2, 20, 19, 0, tzinfo=tzfile('/usr/share/zoneinfo/America/New_York'))

And you also want tomorrow as the end:

>>> from datetime import timedelta
>>> end = start + timedelta(1)
>>> end
datetime.datetime(2013, 2, 21, 19, 0, tzinfo=tzfile('/usr/share/zoneinfo/America/New_York'))

Summary:

today = datetime.utcnow().date()
start = datetime(today.year, today.month, today.day, tzinfo=tz.tzutc()).astimezone(est)
end = start + timedelta(1)
Maxim Galushka
  • 397
  • 1
  • 5
  • 22
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • Struggling with getting this to work. Updated my OP with what I have. – mr-sk Feb 21 '13 at 04:56
  • Thanks - I ended up using most of this. I'll update my OP w/the answer. – mr-sk Mar 08 '13 at 03:08
  • is there a reason why `start` is yesterday instead of today? & end today instead of tomorrow? P.S: I replaced `.astimezone(est)` with `.astimezone()` to get local timezone –  Jan 06 '21 at 18:53
26

use datetime pytz will solve your problem.

def get_start_and_end():
    tz = pytz.timezone('Asia/Shanghai')
    today = datetime.now(tz=tz)
    start = today.replace(hour=0, minute=0, second=0, microsecond=0)
    end = start + timedelta(1)

    return start, end
Lifei Chen
  • 575
  • 4
  • 17
  • is there a way to replace 'Asia/Shanghai' with local time? I tried get_localzone() & got `AttributeError: 'America/Toronto' object has no attribute 'upper'` –  Jan 06 '21 at 18:37
  • 1
    It also works: `end = today.replace(hour=23, minute=59, second=59, microsecond=999999)` – Hill Aug 31 '21 at 03:03
8

The question is old but maybe this helps:

import datetime
end_of_today = datetime.datetime.combine(datetime.datetime.today(), datetime.time(23, 59, 59, 999999))
juankysmith
  • 11,839
  • 5
  • 37
  • 62
7

I would definitely give Delorean a look, to solve your problem would follow a few steps.

You first need to parse your string. Excellent use the Delorean parse method.

>>> from delorean import parse
>>> d = parse("Wed, 20 Feb 2013 03:51:39 +0000")
>>> d
Delorean(datetime=2013-02-20 03:51:39+00:00, timezone=UTC)

Once you have the datetime that you parsed in a Delorean object you simply convert to EST

>>> d = d.shift('US/Eastern')
>>> d
Delorean(datetime=2013-02-19 22:51:39-05:00, timezone=US/Eastern)

Albeit pointless. You never use it for anything in your question, but super easy with Delorean.

Then you get the time now in EST

from delorean import Delorean

>>> d1 = Delorean(timezone="US/Eastern")
>>> d1
Delorean(datetime=2013-02-21 00:35:56.405256-05:00, timezone=US/Eastern)

Now for the truncation step.

>>> d.truncate('day')
Delorean(datetime=2013-02-21 00:00:00-05:00, timezone=US/Eastern)

do the simple shift as above to UTC.

Now get the end of day.

d = d.next_day(1) # move to the next day

Then to shift back one second. Something that the library needs I will be updating this. Simply get the datetime from the Delorean example by asking for it with datetime attribute.

d.datetime - timedelta(seconds=1)
datetime.datetime(2013, 2, 21, 23, 59, 59, tzinfo=<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>)

Goodluck, but this library should simply your dealing with datetime operations :)

Mahdi Yusuf
  • 19,931
  • 26
  • 72
  • 101
  • 1
    Shift back one second? That's not the end of the day, there's an entire second missing in that day. Either you substract one microsecond, or you do a comparison with `if some_datetime < start_of_next_day`, which would be the correct way of doing this. – Daniel F Apr 26 '14 at 04:58
7

This is only a partial answer, because the rest has been covered well. I struggled with this for a while, as some technologies have inclusive searches, and I don't want to include any data from the first microsecond of the next day.

My solution for finding the end of day time quickly and correctly is this:

reference_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1,microseconds=-1)
3

How about this

import datetime
datetime.datetime.combine(datetime.date.today(), datetime.time(00, 00, 00))
datetime.datetime.combine(datetime.date.today(), datetime.time(23, 59, 59))
mirhossein
  • 682
  • 7
  • 16
  • This solution does not cover a situation with microseconds. If you add `999999` microseconds - it would be more correct, since you cover actually the **whole** day: `datetime.datetime.combine(datetime.date.today(), datetime.time(23, 59, 59, 999999))` – finomayato Oct 29 '21 at 00:46
2

Just ran into this, here's the simplest option I found:

from delorean import Delorean
today_d = Delorean()
sod_dt = today_d.start_of_day
eod_dt = today_d.end_of_day
sod_d = Delorean(sod_dt)
eod_d = Delorean(eod_dt)
sod_e = sod_d.epoch
eod_e = eod_d.epoch

to confirm:

In [69]: eod_e - sod_e
Out[69]: 86399.99999904633

close enough for most people

Bruce Edge
  • 1,975
  • 1
  • 23
  • 31
2

Here's a nice solution if you already use Arrow.

import arrow

now = arrow.now('US/Eastern')
start = now.floor('day')
end = now.ceil('day')

# Use the "datetime" property to access the actual datetime
print(start.datetime)
Chad
  • 1,708
  • 1
  • 25
  • 44
1

With python3.8, we can use as follow:

from datetime import datetime, timedelta, time
from pytz import timezone

today = datetime.utcnow()
start_of_day = datetime.combine(today, time.min).astimezone(tz=timezone('America/New_York'))
end_of_day = datetime.combine(today, time.max).astimezone(tz=timezone('America/New_York'))
Vengleab SO
  • 716
  • 4
  • 11
1

To get the min and max time of the day, you could use datetime.time that gives you the earliest and latest representalbe time:

time.min --> datetime.time(0, 0) time.max --> datetime.time(23, 59, 59, 999999)

and then you can combine this with datetime.now() or the specific date you want as below to get the desired result

from datetime import datetime, time
tmp = datetime.combine(datetime.now(), time.max)
print(tmp) --> 2022-09-27 23:59:59.999999

from datetime import datetime, time
tmp = datetime.combine(datetime.now(), time.max)
print(tmp) --> 2022-09-27 00:00:00
Luigi Bungaro
  • 61
  • 1
  • 4
0

Simplest solution for getting the start of a day, though it might produce a phantom microsecond in unlucky floating point imprecision cases:

import datetime as dt
d = dt.datetime.now()
d = d - dt.timedelta(seconds=d.timestamp() % dt.timedelta(days=1).total_seconds())
Sheppy
  • 330
  • 1
  • 10