552

I'm adding UTC time strings to Bitbucket API responses that currently only contain Amsterdam (!) time strings. For consistency with the UTC time strings returned elsewhere, the desired format is 2011-11-03 11:07:04 (followed by +00:00, but that's not germane).

What's the best way to create such a string (without a microsecond component) from a datetime instance with a microsecond component?

>>> import datetime
>>> print unicode(datetime.datetime.now())
2011-11-03 11:13:39.278026

I'll add the best option that's occurred to me as a possible answer, but there may well be a more elegant solution.

Edit: I should mention that I'm not actually printing the current time – I used datetime.now to provide a quick example. So the solution should not assume that any datetime instances it receives will include microsecond components.

davidchambers
  • 23,918
  • 16
  • 76
  • 105

16 Answers16

1080

If you want to format a datetime object in a specific format that is different from the standard format, it's best to explicitly specify that format:

>>> import datetime
>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 18:21:26'

See the documentation of datetime.strftime() for an explanation of the % directives.

Starting from Python 3.6, the isoformat() method is flexible enough to also produce this format:

datetime.datetime.now().isoformat(sep=" ", timespec="seconds")
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 3
    What was that convincing case - putting this solution above your solution using datetime.replace? – matlehmann Jan 14 '14 at 11:36
  • 15
    @matlehmann: Of course I don't know the arguments of davidchambers' colleague. However, I think if your intention is to print a date in a very specific format, you should be explicit about this intention. The code in this answer says "take the current time and format it exactly like this". The code in the other answer says "take the current time, set the microseconds to 0, and then convert it to a string somehow". – Sven Marnach Jan 14 '14 at 14:41
  • 3
    +1, being explicit about the string format avoids problems if standard datetime-str conversion changes in a future Python version – Alan Evangelista Nov 11 '14 at 15:04
  • 1
    Is inventing your own format really the solution? Or even duplicating by hand an existing standardized format? Maybe if interoperability isn't a concern, but why not use ISO format? In which case, the other solution is more clear and more explicit (noting Bengt's comment). Manual format strings generally violate DRY, either on a project level (if you hardcode them as above) or on a community level (unless you're really inventing a new datetime format). – DylanYoung Nov 07 '16 at 21:22
  • 2
    @DylanYoung The requirement of the OP is to print a datetime object in a format that is _different_ from the standard format returned by `.isoformat()`, which includes the microseconds by default. If that's what you need, be explicit about it. Everyone will immediately understand what this code does. Hardly anyone will understand the other code without looking at the documentation. – Sven Marnach Nov 10 '16 at 10:48
  • 1
    @SvenMarnach My bad; I didn't see the specified format in the question (just thought they wanted microseconds left out). `.isoformat()` will leave out microseconds if they are zero. – DylanYoung Nov 10 '16 at 15:11
  • 1
    @DylanYoung which ISO format? There are several. Why risk making your code dependent on changes that are decided by a 3rd party? First and foremost, standards must be consistent across the project, which might include several platforms. You can't do that by relying on conventions agreed upon in the merely _current version_ of the platform. And what if needs require one to migrate the code to another platform? In JS it's `2017-05-11T12:54:23.123Z`, in PHP it's `2017-05-11T12:54:23+00:00`. So which one is "ISO"? Don't be a menace. Use explicit formats. – Alex May 11 '17 at 13:53
  • 1
    @AlexanderMP Are you kidding? ISO Formats exist *to* ensure compatibility between platforms. Unfortunately their adoption is slow, exactly *because* every person decides to 'roll their own' format. To ensure internal consistency? Maybe, but break external compatibility. – DylanYoung May 11 '17 at 16:45
  • 1
    @DylanYoung In my line of work I integrate with multiple systems. I've integrated with dozens, and each of them had a different date/time format. Similar, but different. And according to the ISO 8601 specification https://en.wikipedia.org/wiki/ISO_8601 it's all ISO. Relying on one specific format that is currently being output when converting to string, as a given, is just foolish, as it is subject to change, and break everything. Especially with all the hacks seen in other answers (string operations, or the microsecond hack). – Alex May 12 '17 at 06:37
  • 1
    @DylanYoung moreover, these multiple systems, that all use ISO datetime format, can't integrate out of the box. One still has to use slow fuzzy parsers when dealing with them. Which is why, to ensure compatibility, within a project, a very strict format has to be chosen - a literal format. Of course it should be an ISO format. But if you rely on implicit conversions to string, well, you're really not gonna get far, as I've clearly shown with the differences between JS, PHP, Python, and don't get me started with all the SQL flavors. – Alex May 12 '17 at 06:39
  • 1
    @AlexanderMP I suppose if you're concerned with the efficiency of parsing your dates, it makes sense to use a stricter subset of ISO, but the ISO datetime format is unambiguous, so if python can't natively parse a Java ISO datetime format, that is a weakness in the python's datetime tools. Actually, last I looked python didn't even have a native ISO parser (though that was python 2: ridiculous. In this case, a third party library that does fully support ISO is on order. – DylanYoung May 12 '17 at 18:13
  • 1
    @DylanYoung or in this case accept inevitability and ensure unquestionable compatibility by enforcing a specific strict format on all dates on all subsystems. – Alex May 12 '17 at 20:23
  • 1
    @AlexanderMP Internal compatibility is not compatibility; that's why we have standards. But yes, as long as you're using ISO format, sure speed up your parsing by using a stricter subset. But for the sake of everyone, encapsulate your format in a method or function. – DylanYoung May 15 '17 at 15:21
  • A question that specifies an ISO-8601 date, should never have an answer that manually builds that ISO-8601 date by hand. – CaptainCrunch Aug 05 '20 at 12:32
  • @CaptainCrunch The question doesn't specify an [ISO-8601 date](https://en.wikipedia.org/wiki/ISO_8601). So while it's possible you have a point with your statement, it simply doesn't apply here. – Sven Marnach Aug 05 '20 at 12:47
  • 6
    As of Python 3.6, you can simply do: `datetime.now().isoformat(timespec='seconds', sep=' ')` – craymichael Oct 16 '20 at 22:42
215
>>> import datetime
>>> now = datetime.datetime.now()
>>> print unicode(now.replace(microsecond=0))
2011-11-03 11:19:07
davidchambers
  • 23,918
  • 16
  • 76
  • 105
  • 22
    I think, this is the right solution, because it is readable and documented and consistent behavior: ["`.isoformat([sep])` - Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS"](http://docs.python.org/2/library/datetime.html#datetime.datetime.isoformat) – Bengt Dec 01 '13 at 01:30
  • 1
    in my situation, the date has already been constructed and I needed to "floor" it to the second. this is perfect, thanks. – Vigrond Jul 13 '14 at 02:29
  • 1
    This is the best answer! – Havok Sep 30 '14 at 23:49
  • Far better than formatting or parsing strings for the comparison, thank you. – Zach Young Mar 28 '16 at 01:33
  • 1
    This is the right answer as it upholds the format datetime, not turning it into string. But it can be shortened further by removing third line and changing second line of code to `now = datetime.datetime.now().replace(microsecond=0)`. Also worth mentioning that datetime.datetime.utcnow() prints GMT—never store timestamps in local time – user3661992 Sep 23 '20 at 12:49
  • Also works when saving this in a datetime field in the DB. – Phipsen Apr 26 '22 at 08:11
149

In Python 3.6:

from datetime import datetime
datetime.now().isoformat(' ', 'seconds')
'2017-01-11 14:41:33'

https://docs.python.org/3.6/library/datetime.html#datetime.datetime.isoformat

fireant
  • 14,080
  • 4
  • 39
  • 48
codeif
  • 1,591
  • 1
  • 8
  • 4
  • 7
    I think that now, 8 years later with the advent of Python 3.6 this should be the accepted, universal answer. This offers the better of both worlds argued about by @DylanYoung and AlexanderMP on this same thread [here](https://stackoverflow.com/a/7999977/6118556) – pfabri Mar 23 '19 at 23:16
  • 1
    [How to install Python 3.7 on Linux](https://tecadmin.net/install-python-3-7-on-ubuntu-linuxmint/) – jaggedsoft Apr 18 '19 at 00:07
  • 1
    I have always hated that 'T' in my times. I did not know of the separator option until now. Thank you and 1+. – Malik A. Rumi Feb 27 '21 at 20:53
55

This is the way I do it. ISO format:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
# Returns: '2017-01-23T14:58:07'

You can replace the 'T' if you don't want ISO format:

datetime.datetime.now().replace(microsecond=0).isoformat(' ')
# Returns: '2017-01-23 15:05:27'
radtek
  • 34,210
  • 11
  • 144
  • 111
  • This is similar to my answer. Is there a reason to favour `.isoformat()` over `unicode()`? – davidchambers Jan 24 '17 at 00:25
  • 1
    Depends on what you want, if you want the python string representation use `unicode()`, and if you want ISO-8601, use `isoformat()` – radtek Jan 24 '17 at 14:57
  • I see. `unicode()` is more convenient than `.isoformat().replace('T', ' ')`, certainly. ;) – davidchambers Jan 24 '17 at 16:49
  • I would just use Sven's solution for non-iso format, its more explicit: datetime.now().strftime("%Y-%m-%d %H:%M") , but replacing the 'T' is just another way. May be best solution if you need both ISO and unicode date. – radtek Jan 24 '17 at 19:51
  • `isoformat` accepts the separator specifier, so no replace should be done. just do: `datetime.datetime.now().replace(microsecond=0).isoformat(' ')` – coya Jul 25 '17 at 18:18
19

Yet another option:

>>> import time
>>> time.strftime("%Y-%m-%d %H:%M:%S")
'2011-11-03 11:31:28'

By default this uses local time, if you need UTC you can use the following:

>>> time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
'2011-11-03 18:32:20'
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
17

Keep the first 19 characters that you wanted via slicing:

>>> str(datetime.datetime.now())[:19]
'2011-11-03 14:37:50'
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
16

I usually do:

import datetime
now = datetime.datetime.now()
now = now.replace(microsecond=0)  # To print now without microsecond.

# To print now:
print(now)

output:

2019-01-13 14:40:28
An0n
  • 705
  • 6
  • 19
8

As of Python 3.6+, the best way of doing this is by the new timespec argument for isoformat.

isoformat(timespec='seconds', sep=' ')

Usage:

>>> datetime.now().isoformat(timespec='seconds')
'2020-10-16T18:38:21'
>>> datetime.now().isoformat(timespec='seconds', sep=' ')
'2020-10-16 18:38:35'
craymichael
  • 4,578
  • 1
  • 15
  • 24
8

Since not all datetime.datetime instances have a microsecond component (i.e. when it is zero), you can partition the string on a "." and take only the first item, which will always work:

unicode(datetime.datetime.now()).partition('.')[0]
Austin Marshall
  • 2,991
  • 16
  • 14
4

f-string formatting

>>> import datetime
>>> print(f'{datetime.datetime.now():%Y-%m-%d %H:%M:%S}')
2021-12-01 22:10:07
codeye
  • 564
  • 5
  • 6
3

We can try something like below

import datetime

date_generated = datetime.datetime.now()
date_generated.replace(microsecond=0).isoformat(' ').partition('+')[0]
  • This is inferior to `.isoformat(' ', 'seconds')`, proposed in an earlier answer. – davidchambers Feb 01 '18 at 12:50
  • 1
    When I am trying above proposed earlier answer, I am getting below error >>> datetime.datetime.now().isoformat(' ', 'seconds') Traceback (most recent call last): File "", line 1, in TypeError: isoformat() takes at most 1 argument (2 given) – Abhishek Bajaj Feb 08 '18 at 06:32
  • Ah, I see. It works for me in Python 3 but not in Python 2. – davidchambers Feb 08 '18 at 10:41
  • I am using python 3.4.3 version, in that i see that error. >>> datetime.datetime.now().isoformat(' ', 'seconds') Traceback (most recent call last): File "", line 1, in TypeError: isoformat() takes at most 1 argument (2 given) – Abhishek Bajaj Feb 09 '18 at 06:09
3
>>> from datetime import datetime
>>> dt = datetime.now().strftime("%Y-%m-%d %X")
>>> print(dt)
'2021-02-05 04:10:24'
Sommelier
  • 31
  • 2
2

This I use because I can understand and hence remember it better (and date time format also can be customized based on your choice) :-

import datetime
moment = datetime.datetime.now()
print("{}/{}/{} {}:{}:{}".format(moment.day, moment.month, moment.year,
                                 moment.hour, moment.minute, moment.second))
1

I found this to be the simplest way.

>>> t = datetime.datetime.now()
>>> t
datetime.datetime(2018, 11, 30, 17, 21, 26, 606191)
>>> t = str(t).split('.')
>>> t
['2018-11-30 17:21:26', '606191']
>>> t = t[0]
>>> t
'2018-11-30 17:21:26'
>>> 
  • datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") '2011-11-03 18:21:26' much easier imo. But easy is not alwast the best – An0n Jan 29 '19 at 03:59
1

You can also use the following method

import datetime as _dt

ts = _dt.datetime.now().timestamp()
print("TimeStamp without microseconds: ", int(ts)) #TimeStamp without microseconds:  1629275829

dt = _dt.datetime.now()
print("Date & Time without microseconds: ", str(dt)[0:-7]) #Date & Time without microseconds:  2021-08-18 13:07:09
-2

Current TimeStamp without microsecond component:

timestamp = list(str(datetime.timestamp(datetime.now())).split('.'))[0]