Related
I'm new to Python and I cannot for the life of me find my specific answer online. I need to format a timestamp to this exact format to include 'T', 'Z' and no sub or miliseconds like this yyyy-mm-ddThh:mm:ssZ i.e. 2019-03-06T11:22:00Z. There's lots of stuff on parsing this format but nothing about formatting this way. The only way I have nearly got it to work involves sub-seconds which I do not need. I've tried using arrow and reading their documentation but unable to get anything to work. Any help would be appreciated.
Try datetime library
import datetime
output_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
print(output_date)
For more information, refer to the Python Documentation.
Be careful. Just be cause a date can be formatted to look like UTC, doesn't mean it's accurate.
In ISO 8601, 'Z' is meant to designate "zulu time" or UTC ('+00:00'). While local times are typically designated by their offset from UTC. Even worse, these offsets can change throughout a year due to Daylight Saving Time (DST).
So unless you live in England in the winter or Iceland in the summer, chances are, you aren't lucky enough to be working with UTC locally, and your timestamps will be completely wrong.
Python3.8
from datetime import datetime, timezone
# a naive datetime representing local time
naive_dt = datetime.now()
# incorrect, local (MST) time made to look like UTC (very, very bad)
>>> naive_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
'2020-08-27T20:57:54Z' # actual UTC == '2020-08-28T02:57:54Z'
# so we'll need an aware datetime (taking your timezone into consideration)
# NOTE: I imagine this works with DST, but I haven't verified
aware_dt = naive_dt.astimezone()
# correct, ISO-8601 (but not UTC)
>>> aware_dt.isoformat(timespec='seconds')
'2020-08-27T20:57:54-06:00'
# lets get the time in UTC
utc_dt = aware_dt.astimezone(timezone.utc)
# correct, ISO-8601 and UTC (but not in UTC format)
>>> utc_dt.isoformat(timespec='seconds')
'2020-08-28T02:57:54+00:00'
# correct, UTC format (this is what you asked for)
>>> date_str = utc_dt.isoformat(timespec='seconds')
>>> date_str.replace('+00:00', 'Z')
'2020-08-28T02:57:54Z'
# Perfect UTC format
>>> date_str = utc_dt.isoformat(timespec='milliseconds')
>>> date_str.replace('+00:00', 'Z')
'2020-08-28T02:57:54.640Z'
I just wanted to illustrate some things above, there are much simpler ways:
from datetime import datetime, timezone
def utcformat(dt, timespec='milliseconds'):
"""convert datetime to string in UTC format (YYYY-mm-ddTHH:MM:SS.mmmZ)"""
iso_str = dt.astimezone(timezone.utc).isoformat('T', timespec)
return iso_str.replace('+00:00', 'Z')
def fromutcformat(utc_str, tz=None):
iso_str = utc_str.replace('Z', '+00:00')
return datetime.fromisoformat(iso_str).astimezone(tz)
now = datetime.now(tz=timezone.utc)
# default with milliseconds ('2020-08-28T02:57:54.640Z')
print(utcformat(now))
# without milliseconds ('2020-08-28T02:57:54Z')
print(utcformat(now, timespec='seconds'))
>>> utc_str1 = '2020-08-28T04:35:35.455Z'
>>> dt = fromutcformat(utc_string)
>>> utc_str2 = utcformat(dt)
>>> utc_str1 == utc_str2
True
# it even converts naive local datetimes correctly (as of Python 3.8)
>>> now = datetime.now()
>>> utc_string = utcformat(now)
>>> converted = fromutcformat(utc_string)
>>> now.astimezone() - converted
timedelta(microseconds=997)
Thanks to skaul05 I managed to get the code I needed, it's
date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
print(date)
With f strings, you can shorten it down to:
from datetime import datetime
f'{datetime.now():%Y-%m-%dT%H:%M:%SZ}'
Credits go to How do I turn a python datetime into a string, with readable format date?.
Given a datetime.time value in Python, is there a standard way to add an integer number of seconds to it, so that 11:34:59 + 3 = 11:35:02, for example?
These obvious ideas don't work:
>>> datetime.time(11, 34, 59) + 3
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'int'
>>> datetime.time(11, 34, 59) + datetime.timedelta(0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
>>> datetime.time(11, 34, 59) + datetime.time(0, 0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.time'
In the end I have written functions like this:
def add_secs_to_time(timeval, secs_to_add):
secs = timeval.hour * 3600 + timeval.minute * 60 + timeval.second
secs += secs_to_add
return datetime.time(secs // 3600, (secs % 3600) // 60, secs % 60)
I can't help thinking that I'm missing an easier way to do this though.
Related
python time + timedelta equivalent
You can use full datetime variables with timedelta, and by providing a dummy date then using time to just get the time value.
For example:
import datetime
a = datetime.datetime(100,1,1,11,34,59)
b = a + datetime.timedelta(0,3) # days, seconds, then other fields.
print(a.time())
print(b.time())
results in the two values, three seconds apart:
11:34:59
11:35:02
You could also opt for the more readable
b = a + datetime.timedelta(seconds=3)
if you're so inclined.
If you're after a function that can do this, you can look into using addSecs below:
import datetime
def addSecs(tm, secs):
fulldate = datetime.datetime(100, 1, 1, tm.hour, tm.minute, tm.second)
fulldate = fulldate + datetime.timedelta(seconds=secs)
return fulldate.time()
a = datetime.datetime.now().time()
b = addSecs(a, 300)
print(a)
print(b)
This outputs:
09:11:55.775695
09:16:55
As others here have stated, you can just use full datetime objects throughout:
from datetime import datetime, date, time, timedelta
sometime = time(8,00) # 8am
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()
However, I think it's worth explaining why full datetime objects are required. Consider what would happen if I added 2 hours to 11pm. What's the correct behavior? An exception, because you can't have a time larger than 11:59pm? Should it wrap back around?
Different programmers will expect different things, so whichever result they picked would surprise a lot of people. Worse yet, programmers would write code that worked just fine when they tested it initially, and then have it break later by doing something unexpected. This is very bad, which is why you're not allowed to add timedelta objects to time objects.
One little thing, might add clarity to override the default value for seconds
>>> b = a + datetime.timedelta(seconds=3000)
>>> b
datetime.datetime(1, 1, 1, 12, 24, 59)
You cannot simply add number to datetime because it's unclear what unit is used: seconds, hours, weeks...
There is timedelta class for manipulations with date and time. datetime minus datetime gives timedelta, datetime plus timedelta gives datetime, two datetime objects cannot be added although two timedelta can.
Create timedelta object with how many seconds you want to add and add it to datetime object:
>>> from datetime import datetime, timedelta
>>> t = datetime.now() + timedelta(seconds=3000)
>>> print(t)
datetime.datetime(2018, 1, 17, 21, 47, 13, 90244)
There is same concept in C++: std::chrono::duration.
Thanks to #Pax Diablo, #bvmou and #Arachnid for the suggestion of using full datetimes throughout. If I have to accept datetime.time objects from an external source, then this seems to be an alternative add_secs_to_time() function:
def add_secs_to_time(timeval, secs_to_add):
dummy_date = datetime.date(1, 1, 1)
full_datetime = datetime.datetime.combine(dummy_date, timeval)
added_datetime = full_datetime + datetime.timedelta(seconds=secs_to_add)
return added_datetime.time()
This verbose code can be compressed to this one-liner:
(datetime.datetime.combine(datetime.date(1, 1, 1), timeval) + datetime.timedelta(seconds=secs_to_add)).time()
but I think I'd want to wrap that up in a function for code clarity anyway.
If it's worth adding another file / dependency to your project, I've just written a tiny little class that extends datetime.time with the ability to do arithmetic. When you go past midnight, it wraps around zero. Now, "What time will it be, 24 hours from now" has a lot of corner cases, including daylight savings time, leap seconds, historical timezone changes, and so on. But sometimes you really do need the simple case, and that's what this will do.
Your example would be written:
>>> import datetime
>>> import nptime
>>> nptime.nptime(11, 34, 59) + datetime.timedelta(0, 3)
nptime(11, 35, 2)
nptime inherits from datetime.time, so any of those methods should be usable, too.
It's available from PyPi as nptime ("non-pedantic time"), or on GitHub: https://github.com/tgs/nptime
For completeness' sake, here's the way to do it with arrow (better dates and times for Python):
sometime = arrow.now()
abitlater = sometime.shift(seconds=3)
In a real world environment it's never a good idea to work solely with time, always use datetime, even better utc, to avoid conflicts like overnight, daylight saving, different timezones between user and server etc.
So I'd recommend this approach:
import datetime as dt
_now = dt.datetime.now() # or dt.datetime.now(dt.timezone.utc)
_in_5_sec = _now + dt.timedelta(seconds=5)
# get '14:39:57':
_in_5_sec.strftime('%H:%M:%S')
If you don't already have a timedelta object, another possibility would be to just initialize a new time object instead with the attributes of the old one and add values where needed:
new_time:time = time(
hour=curr_time.hour + n_hours,
minute=curr_time.minute + n_minutes,
seconds=curr_time.second + n_seconds
)
Admittedly this only works if you make a few assumptions about your values, since overflow is not handled here. But I just thought it was worth to keep this in mind
as it can save a line or two
Try adding a datetime.datetime to a datetime.timedelta. If you only want the time portion, you can call the time() method on the resultant datetime.datetime object to get it.
Old question, but I figured I'd throw in a function that handles timezones. The key parts are passing the datetime.time object's tzinfo attribute into combine, and then using timetz() instead of time() on the resulting dummy datetime. This answer partly inspired by the other answers here.
def add_timedelta_to_time(t, td):
"""Add a timedelta object to a time object using a dummy datetime.
:param t: datetime.time object.
:param td: datetime.timedelta object.
:returns: datetime.time object, representing the result of t + td.
NOTE: Using a gigantic td may result in an overflow. You've been
warned.
"""
# Create a dummy date object.
dummy_date = date(year=100, month=1, day=1)
# Combine the dummy date with the given time.
dummy_datetime = datetime.combine(date=dummy_date, time=t, tzinfo=t.tzinfo)
# Add the timedelta to the dummy datetime.
new_datetime = dummy_datetime + td
# Return the resulting time, including timezone information.
return new_datetime.timetz()
And here's a really simple test case class (using built-in unittest):
import unittest
from datetime import datetime, timezone, timedelta, time
class AddTimedeltaToTimeTestCase(unittest.TestCase):
"""Test add_timedelta_to_time."""
def test_wraps(self):
t = time(hour=23, minute=59)
td = timedelta(minutes=2)
t_expected = time(hour=0, minute=1)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
def test_tz(self):
t = time(hour=4, minute=16, tzinfo=timezone.utc)
td = timedelta(hours=10, minutes=4)
t_expected = time(hour=14, minute=20, tzinfo=timezone.utc)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
if __name__ == '__main__':
unittest.main()
This question already has answers here:
Is a specific timezone using DST right now?
(2 answers)
Closed 8 years ago.
We have a server that runs on GMT time. I need to write a Python script that determines if it's currently (at this very second) Daylight Savings Time (DST) in Los Angeles, CA. How can I accomplish this? I took a look at pytz and time, but I can't figure it out. I realize that I could create some logic such as comparing the current time in LA to GMT time, but it would be a lot cleaner if I could use a standard library instead.
Thanks
Edit: Here's some sample code of me setting up the timezone:
from pytz import timezone
import pytz
from datetime import datetime, timedelta
tz = timezone('America/Los_Angeles')
// Instantiate a datetime object using tz?
Edit: Here's a snippet of code that will work. It's not elegant, which is why I'm asking if there's a library or something that is made for this. Maybe like a is_dst() function.
utc = timezone("UTC")
now = utc.localize(datetime.utcnow())
los_angeles_tz = timezone('America/Los_Angeles')
los_angeles_time = now.astimezone(los_angeles_tz)
delta = los_angeles_time.utcoffset()
dstDelta = timedelta(hours=-8)
is_dst = (delta == dstDelta)
import pytz
from datetime import datetime, timedelta
def is_dst(zonename):
tz = pytz.timezone(zonename)
now = pytz.utc.localize(datetime.utcnow())
return now.astimezone(tz).dst() != timedelta(0)
Usage:
>>> is_dst("America/Los_Angeles")
False
>>> is_dst("America/Sao_Paulo")
True
from datetime import datetime
import pytz
isdst_now_in = lambda zonename: bool(datetime.now(pytz.timezone(zonename)).dst())
Example:
>>> isdst_now_in("America/Los_Angeles") # 2014-10-27 12:32:07 PDT-0700
True
>>> isdst_now_in("Australia/Melbourne") # 2014-10-28 06:32:07 AEDT+1100
True
Here's stdlib-only version on Unix using time.tzset() function:
import os
import time
from contextlib import contextmanager
#contextmanager
def local_timezone(zonename):
#NOTE: it manipulates global state
oldname = os.environ.get('TZ')
try:
os.environ['TZ'] = zonename
time.tzset()
yield
finally:
if oldname is None:
del os.environ['TZ']
else:
os.environ['TZ'] = oldname
time.tzset()
def time_isdst_now_in(zonename):
with local_timezone(zonename):
return time.localtime().tm_isdst > 0
The usage is the same:
>>> time_isdst_now_in('Europe/London') # 2014-04-17 18:42:11 BST+0100
True
Note: time.daylight is not used due to issues in some edge cases.
I'm trying to learn python after spending the last 15 or so years working only in Perl and only occasionally.
I can't understand how to handle the two different kinds of results from the parse method of Calendar.parse() from parsedatetime
Given this script:
#!/usr/bin/python
import parsedatetime.parsedatetime as pdt
import parsedatetime.parsedatetime_consts as pdc
import sys
import os
# create an instance of Constants class so we can override some of the defaults
c = pdc.Constants()
# create an instance of the Calendar class and pass in our Constants # object instead of letting it create a default
p = pdt.Calendar(c)
while True:
reply = raw_input('Enter text:')
if reply == 'stop':
break
else:
result = p.parse(reply)
print result
print
And this sample run:
Enter text:tomorrow
(time.struct_time(tm_year=2009, tm_mon=11, tm_mday=28, tm_hour=9, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=332, tm_isdst=-1), 1)
Enter text:11/28
((2009, 11, 28, 14, 42, 55, 4, 331, 0), 1)
I can't figure out how to get the output such that I can consisently use result like so:
print result[0].tm_mon, result[0].tm_mday
That won't work in the case where the input is "11/28" because the output is just a tuple and not a struct_time.
Probably a simple thing.. but not for this newbie. From my perspective the output of Calendar.parse() is unpredictable and hard to use. Any help appreciated. Tia.
I know this is an old question but I ran into this yesterday and the answer here is incomplete (it will fail in the case that parse() returns a datetime).
From the parsedatetime docs:
parse() returns a tuple ( result, type ) where type specifies one of:
0 = not parsed at all
1 = parsed as a date (of type struct_time)
2 = parsed as a time (of type struct_time)
3 = parsed as a datetime (of type datetime.datetime)
Which is a little weird and maybe not the clearest way to do it, but it works and is pretty useful.
Here's a little chunk of code that will convert whatever it returns to a proper python datetime:
import parsedatetime.parsedatetime as pdt
def datetimeFromString( s ):
c = pdt.Calendar()
result, what = c.parse( s )
dt = None
# what was returned (see http://code-bear.com/code/parsedatetime/docs/)
# 0 = failed to parse
# 1 = date (with current time, as a struct_time)
# 2 = time (with current date, as a struct_time)
# 3 = datetime
if what in (1,2):
# result is struct_time
dt = datetime.datetime( *result[:6] )
elif what == 3:
# result is a datetime
dt = result
if dt is None:
# Failed to parse
raise ValueError, ("Don't understand date '"+s+"'")
return dt
Use x = time.struct_time(result[0]) and you'll get a struct_time (so that you can check x.tm_mon and x.tm_mday) no matter whether that result[0] is a struct_time itself, or just a 9-tuple (I've never heard of parsedatetime so I don't know why it's inconsistent in its return type, but with this simple approach you can neutralize that inconsistency).
Given a datetime.time value in Python, is there a standard way to add an integer number of seconds to it, so that 11:34:59 + 3 = 11:35:02, for example?
These obvious ideas don't work:
>>> datetime.time(11, 34, 59) + 3
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'int'
>>> datetime.time(11, 34, 59) + datetime.timedelta(0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
>>> datetime.time(11, 34, 59) + datetime.time(0, 0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.time'
In the end I have written functions like this:
def add_secs_to_time(timeval, secs_to_add):
secs = timeval.hour * 3600 + timeval.minute * 60 + timeval.second
secs += secs_to_add
return datetime.time(secs // 3600, (secs % 3600) // 60, secs % 60)
I can't help thinking that I'm missing an easier way to do this though.
Related
python time + timedelta equivalent
You can use full datetime variables with timedelta, and by providing a dummy date then using time to just get the time value.
For example:
import datetime
a = datetime.datetime(100,1,1,11,34,59)
b = a + datetime.timedelta(0,3) # days, seconds, then other fields.
print(a.time())
print(b.time())
results in the two values, three seconds apart:
11:34:59
11:35:02
You could also opt for the more readable
b = a + datetime.timedelta(seconds=3)
if you're so inclined.
If you're after a function that can do this, you can look into using addSecs below:
import datetime
def addSecs(tm, secs):
fulldate = datetime.datetime(100, 1, 1, tm.hour, tm.minute, tm.second)
fulldate = fulldate + datetime.timedelta(seconds=secs)
return fulldate.time()
a = datetime.datetime.now().time()
b = addSecs(a, 300)
print(a)
print(b)
This outputs:
09:11:55.775695
09:16:55
As others here have stated, you can just use full datetime objects throughout:
from datetime import datetime, date, time, timedelta
sometime = time(8,00) # 8am
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()
However, I think it's worth explaining why full datetime objects are required. Consider what would happen if I added 2 hours to 11pm. What's the correct behavior? An exception, because you can't have a time larger than 11:59pm? Should it wrap back around?
Different programmers will expect different things, so whichever result they picked would surprise a lot of people. Worse yet, programmers would write code that worked just fine when they tested it initially, and then have it break later by doing something unexpected. This is very bad, which is why you're not allowed to add timedelta objects to time objects.
One little thing, might add clarity to override the default value for seconds
>>> b = a + datetime.timedelta(seconds=3000)
>>> b
datetime.datetime(1, 1, 1, 12, 24, 59)
You cannot simply add number to datetime because it's unclear what unit is used: seconds, hours, weeks...
There is timedelta class for manipulations with date and time. datetime minus datetime gives timedelta, datetime plus timedelta gives datetime, two datetime objects cannot be added although two timedelta can.
Create timedelta object with how many seconds you want to add and add it to datetime object:
>>> from datetime import datetime, timedelta
>>> t = datetime.now() + timedelta(seconds=3000)
>>> print(t)
datetime.datetime(2018, 1, 17, 21, 47, 13, 90244)
There is same concept in C++: std::chrono::duration.
Thanks to #Pax Diablo, #bvmou and #Arachnid for the suggestion of using full datetimes throughout. If I have to accept datetime.time objects from an external source, then this seems to be an alternative add_secs_to_time() function:
def add_secs_to_time(timeval, secs_to_add):
dummy_date = datetime.date(1, 1, 1)
full_datetime = datetime.datetime.combine(dummy_date, timeval)
added_datetime = full_datetime + datetime.timedelta(seconds=secs_to_add)
return added_datetime.time()
This verbose code can be compressed to this one-liner:
(datetime.datetime.combine(datetime.date(1, 1, 1), timeval) + datetime.timedelta(seconds=secs_to_add)).time()
but I think I'd want to wrap that up in a function for code clarity anyway.
If it's worth adding another file / dependency to your project, I've just written a tiny little class that extends datetime.time with the ability to do arithmetic. When you go past midnight, it wraps around zero. Now, "What time will it be, 24 hours from now" has a lot of corner cases, including daylight savings time, leap seconds, historical timezone changes, and so on. But sometimes you really do need the simple case, and that's what this will do.
Your example would be written:
>>> import datetime
>>> import nptime
>>> nptime.nptime(11, 34, 59) + datetime.timedelta(0, 3)
nptime(11, 35, 2)
nptime inherits from datetime.time, so any of those methods should be usable, too.
It's available from PyPi as nptime ("non-pedantic time"), or on GitHub: https://github.com/tgs/nptime
For completeness' sake, here's the way to do it with arrow (better dates and times for Python):
sometime = arrow.now()
abitlater = sometime.shift(seconds=3)
In a real world environment it's never a good idea to work solely with time, always use datetime, even better utc, to avoid conflicts like overnight, daylight saving, different timezones between user and server etc.
So I'd recommend this approach:
import datetime as dt
_now = dt.datetime.now() # or dt.datetime.now(dt.timezone.utc)
_in_5_sec = _now + dt.timedelta(seconds=5)
# get '14:39:57':
_in_5_sec.strftime('%H:%M:%S')
If you don't already have a timedelta object, another possibility would be to just initialize a new time object instead with the attributes of the old one and add values where needed:
new_time:time = time(
hour=curr_time.hour + n_hours,
minute=curr_time.minute + n_minutes,
seconds=curr_time.second + n_seconds
)
Admittedly this only works if you make a few assumptions about your values, since overflow is not handled here. But I just thought it was worth to keep this in mind
as it can save a line or two
Try adding a datetime.datetime to a datetime.timedelta. If you only want the time portion, you can call the time() method on the resultant datetime.datetime object to get it.
Old question, but I figured I'd throw in a function that handles timezones. The key parts are passing the datetime.time object's tzinfo attribute into combine, and then using timetz() instead of time() on the resulting dummy datetime. This answer partly inspired by the other answers here.
def add_timedelta_to_time(t, td):
"""Add a timedelta object to a time object using a dummy datetime.
:param t: datetime.time object.
:param td: datetime.timedelta object.
:returns: datetime.time object, representing the result of t + td.
NOTE: Using a gigantic td may result in an overflow. You've been
warned.
"""
# Create a dummy date object.
dummy_date = date(year=100, month=1, day=1)
# Combine the dummy date with the given time.
dummy_datetime = datetime.combine(date=dummy_date, time=t, tzinfo=t.tzinfo)
# Add the timedelta to the dummy datetime.
new_datetime = dummy_datetime + td
# Return the resulting time, including timezone information.
return new_datetime.timetz()
And here's a really simple test case class (using built-in unittest):
import unittest
from datetime import datetime, timezone, timedelta, time
class AddTimedeltaToTimeTestCase(unittest.TestCase):
"""Test add_timedelta_to_time."""
def test_wraps(self):
t = time(hour=23, minute=59)
td = timedelta(minutes=2)
t_expected = time(hour=0, minute=1)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
def test_tz(self):
t = time(hour=4, minute=16, tzinfo=timezone.utc)
td = timedelta(hours=10, minutes=4)
t_expected = time(hour=14, minute=20, tzinfo=timezone.utc)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
if __name__ == '__main__':
unittest.main()